Hallo,
ich habe mich in letzter Zeit mit der Spannungsmessung der Batterien beschäftigt und möchte meine Erkenntnisse hier zur Diskussion stellen.
Meiner Meinung nach funktioniert die Akku-Spannungsmessung so wie sie in der Nibobeelib implementiert ist nicht.
Für die Messung der analogen Signale wird die AVcc als Referenzspannung benutzt, auch für die Messung der Akkuspannung. Da sich ein Spannungsteiler von 2*47K (R43,R44) am Eingang ADC4 (=VBAT) befindet, wird man immer den Wert von ca. 512 als Resultat der Akkuspannung erhalten.
Das kommt daher, dass der ADC immer den Wert 1024 für den Vollausschlag für die Spannung an AVcc heranzieht. Woher soll also der ADC wissen, dass die Akkuspannung und damit AVcc in die Knie geht?
Will man also die Akkuspannung messen, so braucht man eine Referenzspannung an AVcc, die konstant ist und von der Akkuspannung unabhängig ist. Dazu kann man die interne 2.56V Referenzspannung im ATMega16 benutzen.
Ich hoffe, dass ich das bis hierher richtig wiedergegeben habe und möchte mal nachfragen, ob ihr das genauso seht.
Nun habe ich hier mal ein kleines Programm geschrieben, das auf diese Weise zu den richtigen Ergebnissen führt. Da ich nicht in der Nibobeelib herumdoktern wollte, ist es gewissermassen ein "Workaround", um den Fehler zu korrigieren ohne die anderen ADKanäle zu stören oder zu verändern.
Vielleicht wird ja der Fehler in einer neuen Nibobeelib behoben.
Code:
int Batterie(void)
{
unsigned char temp1,temp2;
uint16_t ADCresult;
while ((ADMUX & 0x07) != 0x04);
cli();
while (!(ADCSRA & (1 << ADIF))); // wait for conversion complete
ADCSRA |= (1 << ADIF); // clear ADCIF
//Registerinhalte retten
temp1 = ADCSRA;
temp2 = ADMUX;
ADMUX = (1 << REFS0) | (1 << REFS1) | ANALOG_VOLT; //internal 2.56V reference with external capacitor
//ADCSRA löschen und neu setzen
ADCSRA = 0;
ADCSRA |= ((1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0)); //ADC clock = Clock/128
ADCSRA |= (1 << ADEN); //Enable ADC (das aktiviert die 2.56V Referenz)
//Warten bis Kondensator an ARef = 2.56V hat
//Messung an ARef ergab 1,2msec
delay(6); // = ca. 5*Tau
//1. ADC Wandlung starten und Ergebnis ignorieren
ADCSRA |= (1 << ADSC); // Start conversion
while (!(ADCSRA & (1 << ADIF))); // wait for conversion complete
ADCSRA |= (1 << ADIF); // clear ADCIF
//2. ADC Wandlung starten und Ergebnis übernehmen
ADCSRA |= (1 << ADSC); // Start conversion
while (!(ADCSRA & (1 << ADIF))); // wait for conversion complete
ADCSRA |= (1 << ADIF); // clear ADCIF
ADCresult = ADCL + (ADCH << 8);
//Registerinhalte wiederherstellen
ADMUX = temp2;
ADCSRA = temp1 & ~(1 << ADSC);
//Warten bis Kondensator an ARef = AVcc hat
//Messung ergab sehr steile Flanke
delay(2); //nicht notwendig, nur zur Sicherheit
ADCSRA |= (1 << ADSC); // Start conversion
sei();
return ADCresult;
}
Nun bin ich mal auf eure antworten gespannt.
Viele Grüsse
Skroete
Lesezeichen