Forum: Mikrocontroller und Digitale Elektronik AVR ADC Wertespanne inkorrekt


von A. B. (developer_x)


Lesenswert?

Sehr geehrtes Forum,
ich habe mich gestern schonmal gemeldet.

Ich habe meinen MC (ATMEGA 88 PA) mit RS232 Verbindung und Anschluss
an ADC0. Mein MC soll mir auf einen Befehl hin immer den neuesten 
abgelesenen AD-Wert, der an Kanal 0 anliegt, senden.
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 = (0<<REFS1) | (0<<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
   // Kanal waehlen, ohne andere Bits zu beeinflußen --> Channel 0
36
  ADMUX = (0<<MUX3) | (0<<MUX2) | (0<<MUX1) | (0<<MUX0);
37
38
  /* nach Aktivieren des ADC wird ein "Dummy-Readout" empfohlen, man liest
39
     also einen Wert und verwirft diesen, um den ADC "warmlaufen zu lassen" */
40
 
41
  ADCSRA |= (1<<ADSC);                  // eine ADC-Wandlung 
42
  while (ADCSRA & (1<<ADSC) )           // auf Abschluss der Konvertierung warten
43
  {
44
  }
45
  /* ADCW muss einmal gelesen werden, sonst wird Ergebnis der nächsten
46
     Wandlung nicht übernommen. */
47
  (void) ADCW;
48
}
49
50
/* USART - Senden eines einzelnen Zeichens */
51
int uart_putc(unsigned char c)
52
{
53
    while (!(UCSR0A & (1<<UDRE0)))  /* warten bis Senden moeglich */
54
    {
55
    }  
56
57
    UDR0 = c;                      /* sende Zeichen */
58
    return 0;
59
}
60
void uart_puts( const char* str )
61
{
62
  while( *str )
63
    uart_putc( *str++ );
64
}
65
void uart_puti( uint16_t value )
66
{
67
  char buffer[8];
68
  utoa( value, buffer, 10 );
69
  uart_puts( buffer );
70
}
71
72
/* Zeichen empfangen */
73
uint8_t uart_getc(void)
74
{
75
    while (!(UCSR0A & (1<<RXC0)))   // warten bis Zeichen verfuegbar
76
        ;
77
    return UDR0;                   // Zeichen aus UDR an Aufrufer zurueckgeben
78
}
79
80
/* ADC Einzelmessung */
81
uint16_t adc_read( uint8_t channel )
82
{
83
  ADCSRA |= (1<<ADSC);            // eine Wandlung "single conversion"
84
  
85
  while (ADCSRA & (1<<ADSC) )     // auf Abschluss der Konvertierung warten
86
  { 
87
  }
88
89
  return ADCW;                    // ADC auslesen und zurückgeben
90
}
91
92
void welcome(void)
93
{
94
  uart_puts("Test Device Ready");
95
}
96
97
int main (void) 
98
{    
99
  uart_init();
100
  adc_init();
101
102
  welcome();
103
104
  while(1)
105
  {
106
    uart_getc();
107
108
    uint16_t adw = adc_read(0);
109
    
110
    uart_putc('>');
111
      uart_puti(adw);
112
  }              
113
  return 0;                 
114
}

Es stellt sich heraus dass die Werte bei 0V im Bereich von 350 liegen,
und bei 5v im Bereich von 400. Es gibt natürlich kleine Schwankungen, 
das ist ja normal, aber ich kann nicht wirklich messen, wie viel 
Spannung am ADC anliegt, da diese Werte einfach falsch sind.

Liegt es am Code oder doch am Anschluss?

Ich habe VCC mit AVCC verbunden, und die beiden GND Pins. Pin AREF habe 
ich an 5V angeschlossen, und Channel 0 über ein Potentiometer. Ich habe 
auch schon mit einem Multimeter nachgemessen, ob das POTI kaputt ist, 
ist es allerdings nicht.

Woran können diese komischen Werte liegen?
1
Test Device Ready>349>366>354>354>351>352>388>401>415>416>416>416>415>407>405>404
2
>410>407>408>392>393>407>401>402>405>406>350>353>355>354>356>350>360>
3
358>346>345>348>350>347>355>354>363>350

: Bearbeitet durch User
von STK500-Besitzer (Gast)


Lesenswert?

K. R. schrieb:
> Ich habe VCC mit AVCC verbunden, und die beiden GND Pins. Pin AREF habe
> ich an 5V angeschlossen

schon mal falsch. ARef braucht nur einen Kondensator gegen GND.

von A. B. (developer_x)


Lesenswert?

So ich habe jetzt einen Kondesator gegen GND angeschlossne, und nun hat 
mein ADC nur noch den Wert 1023.

von Thomas E. (thomase)


Lesenswert?

> ADMUX = (0<<MUX3) | (0<<MUX2) | (0<<MUX1) | (0<<MUX0);

damit schaltest du deine oben eingestellte Referenzspannung wieder ab.
Mal davon abgesehen, daß das Nullschieben sowieso Blödsinn ist, schiesst 
du dir hiermit gerade ins Knie.

|= !!!

> Pin AREF habe ich an 5V angeschlossen,

AREF gehört nicht an Vcc, sondern über 100nF an GND. Nur wenn man 
wirklich eine externe Referenz hat, kommt die da ran.

mfg.

: Bearbeitet durch User
von A. B. (developer_x)


Lesenswert?

So. Nun sieht mein Code so aus :
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 = (0<<REFS1) | (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
   // Kanal waehlen, ohne andere Bits zu beeinflußen --> Channel 0
36
  ADMUX |= (0<<MUX3);
37
  ADMUX |= (0<<MUX2);  
38
  ADMUX |= (0<<MUX1);  
39
  ADMUX |= (0<<MUX0);
40
41
  /* nach Aktivieren des ADC wird ein "Dummy-Readout" empfohlen, man liest
42
     also einen Wert und verwirft diesen, um den ADC "warmlaufen zu lassen" */
43
 
44
  ADCSRA |= (1<<ADSC);                  // eine ADC-Wandlung 
45
  while (ADCSRA & (1<<ADSC) )           // auf Abschluss der Konvertierung warten
46
  {
47
  }
48
  /* ADCW muss einmal gelesen werden, sonst wird Ergebnis der nächsten
49
     Wandlung nicht übernommen. */
50
  (void) ADCW;
51
}
52
53
/* USART - Senden eines einzelnen Zeichens */
54
int uart_putc(unsigned char c)
55
{
56
    while (!(UCSR0A & (1<<UDRE0)))  /* warten bis Senden moeglich */
57
    {
58
    }  
59
60
    UDR0 = c;                      /* sende Zeichen */
61
    return 0;
62
}
63
void uart_puts( const char* str )
64
{
65
  while( *str )
66
    uart_putc( *str++ );
67
}
68
void uart_puti( uint16_t value )
69
{
70
  char buffer[8];
71
  utoa( value, buffer, 10 );
72
  uart_puts( buffer );
73
}
74
75
/* Zeichen empfangen */
76
uint8_t uart_getc(void)
77
{
78
    while (!(UCSR0A & (1<<RXC0)))   // warten bis Zeichen verfuegbar
79
        ;
80
    return UDR0;                   // Zeichen aus UDR an Aufrufer zurueckgeben
81
}
82
83
/* ADC Einzelmessung */
84
uint16_t adc_read( uint8_t channel )
85
{
86
  ADCSRA |= (1<<ADSC);            // eine Wandlung "single conversion"
87
  
88
  while (ADCSRA & (1<<ADSC) )     // auf Abschluss der Konvertierung warten
89
  { 
90
  }
91
92
  return ADCW;                    // ADC auslesen und zurückgeben
93
}
94
95
void welcome(void)
96
{
97
  uart_puts("Test Device Ready");
98
}
99
100
int main (void) 
101
{    
102
  uart_init();
103
  adc_init();
104
105
  welcome();
106
107
  while(1)
108
  {
109
    uart_getc();
110
111
    uint16_t adw = adc_read(0);
112
    
113
    uart_putc('>');
114
      uart_puti(adw);
115
  }              
116
  return 0;                 
117
}

Es kommen aber wieder die blöden Werte zwischen 350 und 400.
Ich habe das extra so angeschalten:
1
  // die Versorgungsspannung AVcc als Refernz wählen:
2
  ADMUX = (0<<REFS1) | (1<<REFS0);
Da es doch im Datenblatt heißt für REFS1 = 0 und REFS0 =1 :
AVCC with external capacitor at AREF pin

: Bearbeitet durch User
von STK500-Besitzer (Gast)


Lesenswert?

hast du schon mal den Eingang auf GND gelegt?
Welche Werte bekommst du dann?
Welchen Widerstand hat dein Poti?

von STK500-Besitzer (Gast)


Lesenswert?

wie hast du das Poti angeschlossen? Hast du einen Schaltplan?

von A. B. (developer_x)


Lesenswert?

Nach wievor keine Änderung. Auch bei GND nicht, auch bei VCC nicht.

Widerstand, da steht: 100K025M

von A. B. (developer_x)


Lesenswert?

*Wie bereits erwähnt habe ich nachgemessen, ob die Spannung sich durchs 
drehen verändert, und ob der Poti korrekt angeschlossen ist: JA er ist 
korrekt angeschlossen.

Ich versteh nur beim Bestne willen nicht warum das nicht klappen will..

von Karl H. (kbuchegg)


Lesenswert?

K. R. schrieb:
> Nach wievor keine Änderung. Auch bei GND nicht, auch bei VCC nicht.
>
> Widerstand, da steht: 100K025M


100k ist ein wenig viel.
10k wären gut.

UNd das beantwortet nicht die Frage, wie es angeschlossen ist

1
   -----+--------------> 5V
2
        |
3
       +-+
4
      \| | 10k
5
       \ |
6
       |+-----------------------> zum ADC Pin
7
       | |
8
       +-+
9
        |
10
   -----+-------------- GND


> Ich versteh nur beim Bestne willen nicht warum das nicht klappen will..
Weil du irgendwo einen Fehler gemacht hast.

: Bearbeitet durch User
von A. B. (developer_x)


Lesenswert?

Karl Heinz schrieb:
> K. R. schrieb:
>> Nach wievor keine Änderung. Auch bei GND nicht, auch bei VCC nicht.
>>
>> Widerstand, da steht: 100K025M
>
> 100k ist ein wenig viel.
> 10k wären gut.
>
> UNd das beantwortet nicht die Frage, wie es angeschlossen ist
>
>    -----+--------------> 5V
>         |
>        +-+
>       \| | 10k
>        \ |
>        |+-----------------------> zum ADC Pin
>        | |
>        +-+
>         |
>    -----+-------------- GND

Genauso ist es angeschlossen.
Aber auch das will ja nicht klappen

von Karl H. (kbuchegg)


Lesenswert?

> *Wie bereits erwähnt habe ich nachgemessen, ob die Spannung sich durchs drehen 
verändert,

Wo hast du das gemessen?
Am Poti, oder warst du mit der Messspitze direkt am µC-Pin?

: Bearbeitet durch User
von A. B. (developer_x)


Lesenswert?

nur am poti, ich schau mal ob es auch direkt am ic pin so ist...

... seltsam! Die Spannung liegt am pin nicht an,
ES WAR EIN FLEXWIRE, der einfach irgendwie nicht mehr leitet.
JUHU!
DANKE MAN!
(Mit Flexwire meinte ich 
http://i00.i.aliimg.com/wsphoto/v0/734017820_1/Free-Shipping-65pcs-20-1300pcs-New-Solderless-font-b-Flexible-b-font-Breadboard-Jumper-wires-font.jpg)

Dass es auch an sowas liegen kann, blöd.
Jetzt funktioniert alles :D

Das ganze wollte ich bauen, um erstma zu schauen wie mein Atmega die 
werte einließt, um später z.B. Temperatur oder Lichtsensor 
anzuschließen.

Danke euch, danke!

von Patrick C. (pcrom)


Lesenswert?

Vergess nicht die porten richtig ein zu stellen. Ich benutze ATMEGA2560 
und musz dafuer :
DDRF=0x00; // Analoge Kanaele als EINGANG
PORTF=0x00; // Keine Pull-ups an die Analoge Kanaele
DIDR0=0x00; // Ausschalten von digitale Eingangspuffer

So aehnliche port-registers gibt es denke ich auch bei deinen Chip.

100k poti ist ok meiner meinung, aber bin dich sicher davon das er auch 
die gute Spannung gibt wenn angeschlossen.

Wenn man zB die pull-ups nicht de-activiert dann sind die noch immer da, 
auch wenn man die ADC register gut eingestellt hat.

Vielleicht hilft dieses ? Ich habe 2 stunden gebraucht um diesen bug bei 
mir zu entdecken

Patrick

von Karl H. (kbuchegg)


Lesenswert?

Patrick C. schrieb:
> Vergess nicht die porten richtig ein zu stellen.

Die sind nach einem Reset schon richtig eingestellt.

Schaden tut es nicht. Notwendig ist es aber nicht, wenn der Rest des 
Programms einigermassen in Ordnung ist.
So wie er C radebrechtet, soll er das lieber in Ruhe lassen. Die Gefahr, 
dass er sich ins eigene Knie schiesst ist höher.

> 100k poti ist ok meiner meinung
Atmel ist da anderer Meinung

: Bearbeitet durch User
von Patrick C. (pcrom)


Lesenswert?

> Patrick C. schrieb:
>> Vergess nicht die porten richtig ein zu stellen.
> Die sind nach einem Reset schon richtig eingestellt.
Sorry fehler - DIDR musz 1 sein, ist 0 eingestellt beim Reset

>> 100k poti ist ok meiner meinung
> Atmel ist da anderer Meinung
Ok, interessant. Wo kann ich das im datasheet zuruckfinden ?

von Karl H. (kbuchegg)


Lesenswert?

Patrick C. schrieb:

> Ok, interessant. Wo kann ich das im datasheet zuruckfinden ?

http://www.atmel.com/images/doc2545.pdf

Seite 251, "24.6.1 Analog input circuitry"
1
The ADC is optimized for analog signals with an output impedance of
2
approximately 10kΩ or less. If such a source is used, the sampling
3
time will be negligible. If a source with higher impedance is used,
4
the sampling time will depend on how long time the source needs to
5
charge the S/H capacitor, with can vary widely. The user is recommended
6
to only use low impedance sources with slowly varying signals, since
7
this minimizes the required charge transfer to the S/H capacitor.

von K.L. (Gast)


Lesenswert?

Häng einen kleinen nF-Kondensator an den Eingang und du kannst die 
Angaben im Datenblatt zur Quellimpedanz getrost ignorieren.

Gruß

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.