Wahrscheinlich hab ich irgendwo einen dämlichen Fehler, aber ich finde
ihn nicht: Ich messe mit dem ADC eine Spannung an einem Poti. Das Poti
ist zwischen VCC und GND geschaltet, AVCC ist mit einer 10µH Spule
entstört und dient auch als Referenz (Siehe Schaltung anbei, die
Speisung erfolgt über ein 24V Netzteil). Die Initialisierung sieht so
aus:
1 | DDRA = 0; // Ports initialisieren
|
2 | DDRB = 0;
|
3 |
|
4 | PORTA = 0xFF ^ (1 << PINA0); // Pullups auf allen Ports aktivieren -> Stromsparen, außer Analogeingang
|
5 | PORTB = 0xFF;
|
6 |
|
7 | ADCSRA = 1 << ADEN | 1 << ADIE | 1 << ADPS1 | 1 << ADPS2 | 1 << ADATE; // ADC aktivieren, Interrupt aktivieren, Free Running Mode, Vorteiler 64 --> 8MHz/64 = 125kHz
|
8 | ADMUX = 0; // AVCC als Referenz, ADC0 als Eingang
|
9 |
|
10 | sei(); // Interrupt-Enable
|
11 | ADCSRA |= 1 << ADSC; // Messung starten
|
In der Interrupt-Routine speichere ich den ADC Wert in ein Array:
1 | uint8_t ADC_Index;
|
2 | uint16_t ADC_Values[64];
|
3 | ISR(ADC_vect)
|
4 | {
|
5 | ADC_Index = (ADC_Index + 1)%64;
|
6 |
|
7 | ADC_Values[ADC_Index] = 0x3FF - ADCW;
|
8 | }
|
Und zu guter Letzt die Auswertung:
1 | uint16_t ADC_Sum = 0;
|
2 | for(uint16_t i:ADC_Values)
|
3 | ADC_Sum+=i;
|
4 |
|
5 | if(ADC_Sum < (5UL*64UL))
|
6 | { /*Als Erkennung des Endanschlags (*)*/ }
|
7 | else
|
8 | {
|
9 | ADC_Sum = ADC_Sum >> 6;
|
10 | /* Weiterverarbeitung (**)*/
|
11 | }
|
Das Problem ist, dass, wenn das Poti am Anschlag steht, zunächst - wie
gewünscht - der Code bei (*), nach einigen Minuten dann aber der Code
bei (**) ausgeführt wird. Die Spannung zwischen VCC und ADC0 beträgt
hier aber immernoch 0,0mV (maximale Auflösung vom Multimeter) und der
Widerstand des Potis am Anschlag liegt deutlich unter 1 Ohm. Trotzdem
scheint der ADC mit der Zeit immer kleinere Werte zu messen. Drehe ich
am Poti, springen die Werte wieder auf die richtige Position. Das
Problem hab ich nur am linken Anschlag, wenn das Poti ADC0 mit VCC
verbindet, an allen anderen Positionen sind die Werte stabil.