ADC: Kanalumschaltung reisst AVR aus dem Konzept

OP #1738086
Lesenswert?

Hallihallo zusammen,

ich habe ein Problem mit meinem AVR; genauer: dessen ADC. Es handelt 
sich um einen ATMega644, an 20MHz. Programmiert in C unter WinAVR 
20090313.

Der ADC wird wie folgt initialisiert:
1
ADMUX |= (1<<REFS0); //AREF = AVCC
2
ADMUX |= ((1<<MUX1) | (1<<MUX2) | (1<<MUX3) | (1<<MUX4)); //select internal Bandgap-reference as input
3
  
4
//ADC enable; ADCstart; ADC free running; Samplefreq = 156kHz, no interrupt
5
ADCSRA |= ((1<<ADEN) | (1<<ADSC) | (1<<ADATE) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0));

Das funktioniert soweit tiptop. Der ADC läuft und misst brav seine 
Bandgap-Referenz.

Nun muss ich aber eine Messung auf einem anderen Kanal machen. Dazu 
wechsle ich den Kanal. Der Folgende Code zeigt den Kanalwechsel mit der 
Messung (8 Messungen). Danach wird wieder auf die Bandgap-Referenz als 
ADC-Eingang umgeschaltet.
1
ADCSRA = 0; //Disable ADC;
2
ADMUX &= ~((1<<MUX0) | (1<<MUX1) | (1<<MUX2) | (1<<MUX3) | (1<<MUX4));//ADC Input Channel: ADC0
3
ADCSRA |= ((1<<ADEN) | (1<<ADIE) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0));//start ADC; no free running, 156kHz, interrupt enabled
4
ADCSRA |= (1<<ADSC);//start first conversion
5

6
ADCfinish = 0;
7
for(uint8_t k = 0; k<8; k++)
8
{
9

10
    while(ADCfinish == 0){}//wait until conv.compl.Interrupt
11

12
    ADCfinish = 0;
13
    resulthelper = ADCL; //read out the 10-bit value.
14
    resulthelper = resulthelper + (ADCH<<8);
15
    result = result + resulthelper;
16
        
17
}
18

19
//now: switch back to bandgap-reference:
20
ADCSRA = 0; //Disable ADC;
21
ADMUX |= ((1<<MUX1) | (1<<MUX2) | (1<<MUX3) | (1<<MUX4)); //select internal Bandgap-reference as input
22

23
//ADC enable; ADCstart; ADC free running; Samplefreq = 156kHz, no interrupt
24
ADCSRA |= ((1<<ADEN) | (1<<ADSC) | (1<<ADATE) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0));

Und hier noch die Interruptroutine:
1
ISR(ADC_vect)
2
{
3

4
  ADCfinish = 1;
5
  ADCSRA |= (1<<ADSC); //start next conversion.
6
}

Das Ganze nochmals in Kürze:
Standardmässig ist die Bandgap-Referenz ADC-Eingang, der ADC läuft free 
running und hat den conversion complete interrupt ausgeschaltet.

Es muss für 8 Messungen auf Kanal 0 umgeschaltet werden. Dazu wird der 
ADC komplett abgeschaltet, der Kanal gewechselt, und wieder 
angeschaltet, diesmal Interruptgesteuert.
Dann wird gemessen. In jeder ISR wird die nächste Messung ausgelöst.
Nach den 8 Messungen muss wieder auf die Bandgap-Referenz und free 
running umgeschaltet werden ==> ADC abschalten, Kanal wechseln, neu 
konfiguriert wieder anschalten.

Die Messwerte, welche beim Achtmaligen Messen entstehen, sind korrekt. 
Der ADC arbeitet also richtig.

ABER: Er haut mir irgendwie den Rest des AVR aus den Socken. An einem 
AVR-Pin hängt eine LED. Diese wird ganz zu beginn des AVR-Programms 
eingeschaltet und dann folgt nie mehr eine Anweisung, um diese LED 
wieder auszuschalten.
Führe ich aber die Kanalumschaltung und die 8 Messungen aus, so erlischt 
die LED! Ohne dass dafür irgendwo im Programm die Anweisung dafür stehen 
würde...Der AVR läuft jedoch weiter und tut so, als ob nichts 
wäre...Alle anderen funktionen funktionieren, nur die LED leuchtet nicht 
mehr...

Jetzt wollte ich nachfragen, ob meine Variante der ADC-Bedienung so in 
Ordnung ist. Kann sein, dass meine Methode etwas "holzig" und zu exakt 
ist, da ich jetzt schon viel probiert habe und noch keine Besserung 
eingetreten ist. Aber sollte die Methode im Prinzip funktionieren?

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