ADC wandelt nicht

OP #4868401
Lesenswert?

Hallo,

Ich habe ein Problem mit dem ADC am AT90CAN128. Ich bekomme, unabhängig 
von der Eingangspannung, konstante Ausgangswerte im Unteren einstelligem 
Bereich. Wenn ich Parameter wie Referenzspannung und Prescaler ändere, 
ändert sich nur der konstante Wert den ich auslese.
Es ist Möglich das ein Defekter Spannungsregler kurzzeitig mehr als die 
erlaubten 5V auf das Board gegeben hat, alle anderen Funktionen sind 
jedoch noch intakt.
Bevor ich jetzt 15€ in einen neuen Chip investiere, wollte ich vorher 
mal Menschen mit mehr Ahnung fragen, ob ich nicht vielleicht einfach zu 
doof bin und einen groben Fehler gemacht habe...

Mein für den ADC verantwortlicher Code sieht so aus, natürlich hier sehr 
geschrumpft. Die Ausgabe über den Bus und den ganzen Rest habe ich 
rausreduziert:
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <inttypes.h>
4
#include <stdbool.h>
5

6
#define F_CPU 16000000ULL
7
#include <util/delay.h>
8

9
uint16_t uadc;
10

11
void PORT_Init()
12
{
13
  
14
  PORTE = 0b00011000;
15
  DDRE = 0b00011000;    //Led set as output (Bit4 = 1) 
16
    
17
  PORTF = 0b00000000; // PF 0 als Input für adc
18
  DDRF = 0b00000000;
19
  }
20

21

22
void Reg_Init(void)
23
  {
24
  //ADC
25
  
26
  ADMUX= (1<<REFS1) | (1<<REFS0) | (0<<MUX4) | (0<<MUX3) | (0<<MUX2) | (0<<MUX1)| (0<<MUX0) | (0<<ADLAR); 
27
// 5v=Ref Input=ADC0 Gain=1 Rechtsbuendiger RegisterOutput 
28
  ADCSRA= (1<<ADEN)  | (1<<ADPS2) | (1<<ADPS1); //AD An
29
  ADCSRA |= (1<<ADSC);    //  ADC warmlaufen  lassen
30

31
  }
32

33

34
void WDT_off(void)
35
  {
36
  cli();
37
  /* Write logical one to WDCE and WDE */
38
  WDTCR = (1<<WDCE) | (1<<WDE);
39
  /* Turn off WDT */
40
  WDTCR = 0x00;
41
  }
42

43
void sleep(uint32_t i) 
44
{
45
  while(i--)
46
    _delay_ms(1);
47
}
48

49
int main()
50
  {
51
  WDT_off();
52
  PORT_Init();
53
  Reg_Init();
54

55

56
  
57
  while (1)
58
      {  
59
          ADCSRA = (1<<ADSC); 
60
          while (ADCSRA & (1<<ADSC) ) {};          // auf Abschluss der Konvertierung warten
61
          uadc=ADCL+(2<<ADCH);                //Auslesen und zusammenfügen des Konvertierungsergebnisses  
62
          sleep(100);
63
      }
64

65
  
66
    
67
  
68

69
    }
#4868452
Lesenswert?

Du startest in der init den ADC, fragst aber nicht ab. Ohne Abfrage ist 
das Register blockiert.
Once ADCL is read, ADC access to Data Registers
is blocked. This means that if ADCL has been read, and a conversion 
completes before ADCH is
read, neither register is updated and the result from the conversion is 
lost. When ADCH is read,
ADC access to the ADCH and ADCL Registers is re-enabled.
#4868458
Lesenswert?

Also, Reg_Init
Nullen braucht man nicht setzen, das macht deinen Code nur 
unübersichtlich.
Den ADC zu warmlaufen zu lassen ist ebenfalls unnötig, nicht auf das 
Ende der Wandlung zu warten ist schon ein recht grober Schnitzer ;)

Sleep()

Autsch, tut das nicht weh? delay_ms kann problemlos mehrere Sekunden 
rennen, was soll denn diese Schleife? Total überflüssig.

Zur main
Man kann statt ADCL und ADCH zu verheiraten auch gleich ADC abspeichern 
;)

Eigentlich sollte der Code laufen, zumindest sehe ich hier nichts warum 
er es nicht tun sollte. Bzgl. Referenzquelle hab ich nicht geschaut, 
nehme aber an, dass das richtig ist. Ich denke, das ist nicht der 
Problemcode ;)
Moderator #4868474
Lesenswert?

Statt

1
          ADCSRA = (1<<ADSC);

muss es heißen:

1
          ADCSRA |= (1<<ADSC);

Sonst setzt du die in

1
  ADCSRA= (1<<ADEN)  | (1<<ADPS2) | (1<<ADPS1); //AD An

gemachten Einstellung wieder zurück.

1
          uadc=ADCL+(2<<ADCH);

Hier ist nicht garantiert, dass ADCL und ADCH in der richtigen
Reihenfolge (ADCL zuerst) gelesen werden. Außerdem sollte es statt
2<<ADCH wohl ADCH<<8 heißen. Einfacher und zuverlässiger geht es mit

1
          uadc=ADC;
OP #4868569
Lesenswert?

Ich danke euch, irgendwo da hat der Teufel gesessen ;)

Ich bin froh das hier auch immer Kommentare zum Programmierstil kommen. 
Gerade wenn man ein ungeduldiger Mensch ist und mit Dingen an anfängt, 
deren Grundlagen zwar Theoretisch kennt, aber noch nicht verinnerlicht 
hat, ist das unglaublich hilfreich.

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