Forum: Mikrocontroller und Digitale Elektronik ADC wandelt nicht


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Mechatronk A. (mechatronk)


Bewertung
0 lesenswert
nicht 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)


Bewertung
1 lesenswert
nicht lesenswert

von Hubert G. (hubertg)


Bewertung
1 lesenswert
nicht 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)


Bewertung
1 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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)


Bewertung
1 lesenswert
nicht 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)


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

Grüße

Andi

von Mechatronk A. (mechatronk)


Bewertung
1 lesenswert
nicht 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

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.