Forum: Mikrocontroller und Digitale Elektronik AVR GCC ADC Werte ergeben keinen Sinn


von A. B. (developer_x)


Lesenswert?

Sehr geehrtes Forum,
ich habe eine Frage bezüglich des ADCs.

Ich habe eine Vorrichtung mit einem ATMEGA 88 PA, mit RS232 Verbindung 
zum PC und folgendem Code in C:
1
// 19.12.2013 - 17:19 Uhr, Tests zur Kommunikation per RS232 in C
2
3
#include <avr/io.h>          
4
#include <util/delay.h>
5
6
#define BAUD  4800UL
7
#define F_CPU 1000000UL
8
#define UBRR_VAL ((F_CPU+BAUD*8)/(BAUD*16)-1)
9
10
//  Initialisierung des UART
11
void uart_init(void)
12
{
13
  // Baudrate einstellen
14
  UBRR0H = UBRR_VAL >> 8;
15
  UBRR0L = UBRR_VAL & 0xFF;
16
 
17
  // Verwendungsart einstellen
18
  UCSR0B  = (1<<TXEN0);  // UART TX einschalten
19
  UCSR0C  = (1<<UCSZ01)|(1<<UCSZ00);  // Asynchron 8N1 
20
  UCSR0B |= (1<<RXEN0);  // UART RX einschalten
21
}
22
//  Initialisierung des ADWC
23
void adc_init(void) 
24
{
25
  // die Versorgungsspannung AVcc als Refernz wählen:
26
  //ADMUX = (1<<REFS0);    
27
  // oder interne Referenzspannung als Referenz für den ADC wählen:
28
   ADMUX = (1<<REFS1) | (1<<REFS0);
29
 
30
  // Bit ADFR ("free running") in ADCSRA steht beim Einschalten
31
  // schon auf 0, also single conversion
32
  ADCSRA = (1<<ADPS1) | (1<<ADPS0);     // Frequenzvorteiler
33
  ADCSRA |= (1<<ADEN);                  // ADC aktivieren
34
 
35
  /* nach Aktivieren des ADC wird ein "Dummy-Readout" empfohlen, man liest
36
     also einen Wert und verwirft diesen, um den ADC "warmlaufen zu lassen" */
37
 
38
  ADCSRA |= (1<<ADSC);                  // eine ADC-Wandlung 
39
  while (ADCSRA & (1<<ADSC) ) {         // auf Abschluss der Konvertierung warten
40
  }
41
  /* ADCW muss einmal gelesen werden, sonst wird Ergebnis der nächsten
42
     Wandlung nicht übernommen. */
43
  (void) ADCW;
44
}
45
46
/* USART - Senden eines einzelnen Zeichens */
47
int uart_putc(unsigned char c)
48
{
49
    while (!(UCSR0A & (1<<UDRE0)))  /* warten bis Senden moeglich */
50
    {
51
    }  
52
53
    UDR0 = c;                      /* sende Zeichen */
54
    return 0;
55
}
56
/* Zeichen empfangen */
57
uint8_t uart_getc(void)
58
{
59
    while (!(UCSR0A & (1<<RXC0)))   // warten bis Zeichen verfuegbar
60
        ;
61
    return UDR0;                   // Zeichen aus UDR an Aufrufer zurueckgeben
62
}
63
64
/* ADC Einzelmessung */
65
uint16_t adc_read( uint8_t channel )
66
{
67
  // Kanal waehlen, ohne andere Bits zu beeinflußen
68
  ADMUX = (ADMUX & ~(0x1F)) | (channel & 0x1F);
69
  ADCSRA |= (1<<ADSC);            // eine Wandlung "single conversion"
70
  
71
  while (ADCSRA & (1<<ADSC) )     // auf Abschluss der Konvertierung warten
72
  { 
73
  }
74
75
  return ADCW;                    // ADC auslesen und zurückgeben
76
}
77
78
void welcome(void)
79
{
80
  uart_putc('T');
81
  uart_putc('E');
82
  uart_putc('S');
83
  uart_putc('T');
84
  uart_putc(' ');
85
  uart_putc('D');
86
  uart_putc('E');
87
  uart_putc('V');
88
  uart_putc('I');
89
  uart_putc('C');
90
  uart_putc('E');
91
  uart_putc(' ');
92
  uart_putc('R');
93
  uart_putc('E');
94
  uart_putc('A');
95
  uart_putc('D');
96
  uart_putc('Y');
97
}
98
99
int main (void) 
100
{    
101
  uart_init();
102
  adc_init();
103
104
  welcome();
105
106
  while(1)
107
  {
108
    uart_getc();
109
110
    uint16_t adw = adc_read(0);
111
    uint8_t lo_value = adw;
112
    uint8_t hi_value = (adw >> 8);
113
114
    uart_putc('>');
115
      uart_putc(lo_value);
116
      uart_putc(hi_value); 
117
  }              
118
  return 0;                 
119
}

Problem ist, die Ausgabe ist immer konstant, egal was ich an ADC Channel 
0 auch anschließe, z.B. GND oder VCC oder gar nichts.

Woran könnte es liegen, am Code, oder an der Hardware?

von H.Joachim S. (crazyhorse)


Lesenswert?

K. R. schrieb:
> uart_putc('>');
>       uart_putc(lo_value);
>       uart_putc(hi_value);

unabhängig vom Wandlerproblem - das funktioniert sicher nicht so, wie du 
dir das gedacht hast. Musst du in Ascii wandeln.

von Karl H. (kbuchegg)


Lesenswert?

K. R. schrieb:

Mach dir doch erst mal ein paar vernünftige Hilfsfunktionen. So was ....
1
  uart_putc('T');
2
  uart_putc('E');
3
  uart_putc('S');
4
  uart_putc('T');
5
  uart_putc(' ');
6
  uart_putc('D');
7
  uart_putc('E');
8
  uart_putc('V');
9
  uart_putc('I');
10
  uart_putc('C');
11
  uart_putc('E');
12
  uart_putc(' ');
13
  uart_putc('R');
14
  uart_putc('E');
15
  uart_putc('A');
16
  uart_putc('D');
17
  uart_putc('Y');

ist doch Unsinn.
1
void uart_puts( const char* str )
2
{
3
  while( *str )
4
    uart_putc( *str++ );
5
}

damit kannst du dann sofort erst mal schreiben
1
void welcome(void)
2
{
3
  uart_puts( "TEST DEVICE READY\r\n" );
4
}

Gut.
Weiters ist diese Funktion sofort nützlich, weil sich daraus sofort eine 
Zahlenausgabe zusammensetzen lässt
1
void uart_puti( uint16_t value )
2
{
3
  char buffer[8];
4
  utoa( value, buffer, 10 );
5
  uart_puts( buffer );
6
}

welche gleich mal hier ...
1
int main()
2
{
3
....
4
5
  while(1)
6
  {
7
    uart_getc();
8
9
    uint16_t adw = adc_read(0);
10
    uart_puti( adw );
11
    uart_puts( "\r\n" );
12
  }
zum Einsatz kommt.

Alternativ hätte man azum Testen auch so vorgehen können
1
...
2
int main()
3
{
4
  char buffer[20];
5
...
6
  while(1)
7
  {
8
    uart_getc();
9
10
    uint16_t adw = adc_read(0);
11
    sprintf( buffer, "ADC Wert: %u\r\n", adw );
12
    uart_prints( buffer );
13
  }
14
}

Probier beide mal aus. Mal sehen ob dein Problem nicht einfach nur darin 
besteht, dass du die Ausgabe in deinem Terminal fehlinterpretierst.

von Karl H. (kbuchegg)


Lesenswert?

Wenn du die Vcc an den ADC anschliessen willst, dann solltest du hier
1
void adc_init(void) 
2
{
3
  // die Versorgungsspannung AVcc als Refernz wählen:
4
  //ADMUX = (1<<REFS0);    
5
  // oder interne Referenzspannung als Referenz für den ADC wählen:
6
   ADMUX = (1<<REFS1) | (1<<REFS0);
7
...
dann aber auch die korrekte Referenzspannung dafür auswählen.

Wie ist der AREF Pin deines µC eigentlich beschaltet?

von A. B. (developer_x)


Lesenswert?

Danke erstmal für eure Tipps.

Ich kriege eigentlich nur den einen konstanten Wert rein: 1023

Wenn ich AREF mit VCC (5V) verbinde (obwohl ich eine Interne Spannung 
verwende, hatte ich zumindest gedacht), dann habe ich ne leichte 
Varianz:
> wenn ich dann an Channel 0 z.B. 5V anschließe bin ich bei ca 430-390.
> Wenn ich Channel 0 an 0V (GND) anschließe, bin ich bei Werten ca. bei 350-360.

Ich hätte da schon etwas mehr an Variabilität erwartet. Sollten die 
Werte nicht bei AREF = 5V  zwischen 5V und 0V an Channel 0 nicht 
zwischen 0 und 2^14 liegen?

von A. B. (developer_x)


Lesenswert?

Wenn ich das ganze an Channel 1 anschließe, und teste, kommen ähnliche 
Werte wie bei Channel 0 raus.

von Georg G. (df2au)


Lesenswert?

AVCC ist beschaltet?

von A. B. (developer_x)


Lesenswert?

ja, mit VCC verbunden

von A. B. (developer_x)


Lesenswert?

Keiner eine Idee?

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.