Es wird alles intern geschaltet. Extern wird nur AVCC an VCC gelegt, der AREF-Pin bleibt frei bzw bekommt nen 100n nach GND.
Die 1,23V kann man über das ADMUX-Register auf den ADC-Eingang legen. Im Datenblatt ist ein Tabelle, die die Zuordnung ADMUX-Wert->ADC-Pin angibt. Darin steht neben den "normalen" Eingängen auch die Codes für Vbg. Beim Mega8 ist das die 0b1110. Meine ADC-Routine bekommt als Parameter die Kanalnummer übergeben. Normalerweise also 0 bis 7. Nun bekommt sie einfach die 14, und dann wird die Bandgap-Spannung gemessen.
Die 1,23V sind nur ein interne Zwischenspannung, die man sonst kaum zu Gesicht bekommt. Sie wird noch mal verstärkt, um die 2,56V zu erzeugen.
Getestet hab ich mit einem Mega8 und einem Mega32.
Code für den M8:
Code:
uint16_t ReadChannel(uint8_t mux)
{
uint8_t i;
uint16_t result = 0;
ADMUX = mux; // Kanal waehlen
ADMUX|=(1<<REFS0); //Referenz: AVCC
//ADMUX|=(1<<REFS1)|(1<<REFS0); //interne Referenz
/*"Dummy-Readout"*/
ADCSR |= (1<<ADSC); // eine ADC-Wandlung
while ( ADCSR & (1<<ADSC) ); // auf Abschluss der Konvertierung warten
/* Eigentliche Messung - Mittelwert aus 4 aufeinanderfolgenden Wandlungen */
for(i=0;i<4;i++)
{
ADCSR |= (1<<ADSC); // eine Wandlung "single conversion"
while ( ADCSR & (1<<ADSC) ); // auf Abschluss der Konvertierung warten
result += ADCW; // Wandlungsergebnisse aufaddieren
}
result /= 4; // Summe durch vier teilen = arithm. Mittelwert
return result;
} //end.ReadChannel
void akkutest(void)
{
uint16_t akkumess;
//Bandgap messen, Ref= AVCC = Akkuspannung
akkumess=ReadChannel(14);
if(akkumess<350) {/*...*/} //mehr als 3,5V
else if(akkumess<410) {/*...*/} //mehr als 3V
else {/*...*/} //weniger als 3V
}
Beim M32 ist der Code die 0b11110, also ReadChannel(30);
Lesezeichen