AVR ADC Wertespanne inkorrekt

OP #3452917
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
#3452938
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.
OP #3452945
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
#3452988
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.
OP #3452992
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
OP #3453003
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!
#3453006
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
#3453009
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
#3453104
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 ?
#3453127
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren