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?