Forum: Mikrocontroller und Digitale Elektronik ADC wandelt nicht


von Mechatronk A. (mechatronk)


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
    }

von User (Gast)


Lesenswert?


von Hubert G. (hubertg)


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.

von M. K. (sylaina)


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 ;)

von M. K. (sylaina)


Lesenswert?

Hubert G. schrieb:
> Du startest in der init den ADC, fragst aber nicht ab. Ohne Abfrage ist
> das Register blockiert.

Nein, das ist nicht das Problem ;)

von Yalu X. (yalu) (Moderator)


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;

von Mechatronk A. (mechatronk)


Lesenswert?

Ich danke für die Hinweise, ich bau es mal um und schau was es gibt!

Grüße

Andi

von Mechatronk A. (mechatronk)


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.

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.