diyundso.de
Verwenden der internen ADC eines AVRs
Bei AVRs mit einem internen ADC kann mit der folgenden Vorgehensweise der Wert einer Spannung an ADCx ermittelt werden.
Die Messauflösung beträgt 10 Bit. Damit liegt der Messwert x zwischen 0V = 0 <= x <= 1023 = Referenzspannung
Initialisierung
Zunächst wird eine Referenzspannungsquelle ausgewählt:
//interne Referenzspannung (oft 2,56V, siehe Datenblatt)
ADMUX = 0xC0;
//AVCC
ADMUX = 0x40;
//AREF
ADMUX = 0x00;
Aktivieren des ADC:
ADCSRA = 0x80; //ADC aktivieren, Rest 0 setzen
Anschließend wird ein Vorteiler für den ADC gewählt. Die Frequenz sollte bei 100-200kHz liegen:
ADCSRA |= 0x01; //Vorteiler 2
ADCSRA |= 0x02; //Vorteiler 4
ADCSRA |= 0x03; //Vorteiler 8
ADCSRA |= 0x04; //Vorteiler 16
ADCSRA |= 0x05; //Vorteiler 32
ADCSRA |= 0x06; //Vorteiler 64
ADCSRA |= 0x07; //Vorteiler 128
Konvertierung starten:
ADCSRA |= (1<<6); //Konvertierung starten
Warten auf den Abschluss der Konvertierung:
while(ADCSRA & (1<<6)){};
Ergebnis auslesen:
uint16_t ergebnis = 0;
//Bei AVRs mit 16-bit Registern für den Messwert des ADCs
ergebnis=ADCW;
//Bei AVRs mit zwei 8-Bit-Registern für den Messwert
ergebnis = ADCL;
ergebnis += (ADCH<<8);
Eigentliche Messung
Zum Beginn der eigentlichen Messung muss als erstes der zu messende Kanal ausgewählt werden:
uint8_t kanal = 2; //z.B. aus ADC2
ADMUX &= (0xE0); //Vorhandenen Wert fuer den Kanal loeschen
//den Wert fuer den Kanal schreiben, dabei die vorderen 3 Bits vor evtl. fehlern schuetzen
ADMUX |= (kanal&(0x1F));
ADCSRA |= (1<<6); //Konvertierung starten
Anschließend kann wie bei der Initialisierung auf den Abschluss der Messung gewartet, und der Wert ausgelesen werden
Fertiger Code zum Ausführen von Messungen
#include <avr/io.h>
void adc_init (void){
//interne Referenzspannung
//ADMUX = 0xC0;
//AVCC
//ADMUX = 0x40;
//AREF
ADMUX = 0x00;
ADCSRA = 0x80; //ADC aktivieren, Rest 0 setzen
//ADCSRA |= 0x01; //Vorteiler 2
//ADCSRA |= 0x02; //Vorteiler 4
//ADCSRA |= 0x03; //Vorteiler 8
//ADCSRA |= 0x04; //Vorteiler 16
ADCSRA |= 0x05; //Vorteiler 32
//ADCSRA |= 0x06; //Vorteiler 64
//ADCSRA |= 0x07; //Vorteiler 128
ADCSRA |= (1<<6); //Konvertierung starten
while(ADCSRA & (1<<6)){}; //Kovertierung beendet
uint16_t ergebnis = 0;
ergebnis = ADCL;
ergebnis += (ADCH<<8);
}
uint16_t adc_read (uint8_t kanal){
static uint8_t init = 0;
if(init==0){adc_init(); init++;} //beim ersten Aufruf zunaechst initialisieren
ADMUX &= (0xE0); //Vorhandenen Wert fuer den Kanal loeschen
//den Wert fuer den Kanal schreiben, dabei die vorderen 3 Bits vor evtl. fehlern schuetzen
ADMUX |= (kanal&(0x1F));
ADCSRA |= (1<<6); //Konvertierung starten
while(ADCSRA & (1<<6)){}; //Kovertierung beendet
uint16_t ergebnis = 0;
ergebnis = ADCL;
ergebnis += (ADCH<<8);
return ergebnis; //Ergebnis zurueckgeben
}
double adc_read_avg (uint8_t kanal, uint16_t anzahl){
uint32_t summe = 0;
for (uint16_t i = 1; i<=anzahl; i++){ //anzahl = Anzahl der Durchlaeufe
summe+=adc_read(kanal);
}
return ((double)summe/(double)anzahl); //Durchschnitt zurueckgeben
}
Benutzung des Codes
Vorbereitung
1. Wählen einer Referenzspannungsquelle in adc_init()
2. Wählen eines Vorteilers zum Erreichen von 100-200kHz in adc_init()
Funktionsaufruf
Der Aufruf von:
adc_read(uint8_t x);
liefert den Wert einer Einzelmessung von ADCx als uint16_t
adc_read_avg(uint8_t x, uint16_t n);
liefert den gemittelten Wert von n Messungen an ADCx als double