Hallo,
ich versuche die Batterie mit den internen Bordmitteln des ATxmega32E5
zu messen (Interne 1V Referenz und AVCC/10), da ich ein
Batteriebetriebenes Projekt hab und nicht noch extern eine Referenz und
einen Spannungsteiler einsetzen wollte, was zu zusätzlichem
Stromverbrauch führen würde.
Bei 3.0V, meiner normalen 2xAA Batteriespannung funktioniert die Messung
relativ genau ( (0.3 *2047) / 1 ) = 614, gewandelt 597 = 3% Fehler.
Wenn ich nun die Spannung des Speisegerätes runterdrehe, geht erst auch
der Messwert linear runter. Aber ab einer Spannung von 2.76V und weiter
unten sinkt plötzlich der gewandelte Wert rapide innerhalb von nur ein
paar millivolt auf etwa 40% (230) und bleibt dort, auch wenn ich die
Spannung noch weiter absenke.
Ich hab schon vieles ausprobiert und getestet, aber das Verhalten ist
immer dasselbe. Ich hab den Code mal auf eine möglichst einfache
Konfiguration gesetzt (keine Mittelung, kein Gain usw). Auch die Sample
Rate hab ich auf 8kHz runtergedrückt, weil es im Datenblatt heisst, dass
die internen Signale nur langsamer gesampelt werden können (Manual S.352
mitte), jedoch hab ich im Datenblatt dazu nichts gefunden.
Auch der Versuch mit der umgekehrten Variante (int. Bandgap referenz als
Eingang und AVCC/1.6 als referenz) hat nicht gefruchtet. Der Wert
springt (logischerweise umgekehrt) von 1208(3V) auf 2047(2.73V)
Hier mal der Code:
1 | void adc_init(void) {
|
2 | ADCA.CTRLA = ADC_ENABLE_bm; // Enable ADC
|
3 | ADCA.CTRLB = ADC_CURRLIMIT_HIGH_gc | ADC_CONMODE_bm | ADC_RESOLUTION_MT12BIT_gc; // No power saving, signed singleended mode, average resolution
|
4 | ADCA.REFCTRL = ADC_REFSEL_INT1V_gc; // Use internal 1V reference (same as DAC)
|
5 | ADCA.EVCTRL = ADC_EVACT_NONE_gc; // Do not use events
|
6 | ADCA.PRESCALER = ADC_PRESCALER_DIV512_gc; // ADC clock = 8kHz speed
|
7 | ADCA.SAMPCTRL = 0x10; // Sampling time: shorter sampling time = lower impedance.
|
8 |
|
9 | ADCA.CH0.CTRL = ADC_CH_GAIN_1X_gc | ADC_CH_INPUTMODE_INTERNAL_gc; // x gain, use internal input (from DAC)
|
10 | ADCA.CH0.MUXCTRL = ADC_CH_MUXINT_SCALEDVCC_gc; // Use 1/10 scaled VCC as input to ADC
|
11 | ADCA.CH0.INTCTRL = ADC_CH_INTMODE_COMPLETE_gc | ADC_CH_INTLVL_OFF_gc; // No interrupts
|
12 | ADCA.CH0.SCAN = 0; // No channel scanning
|
13 | // ADCA.CH0.AVGCTRL = ADC_CH_SAMPNUM_1024X_gc | (4 << ADC_CH_RIGHTSHIFT_gp); // Oversampling to 16-bit resolution 1024 = best stability
|
14 | ADCA.CH0.AVGCTRL = ADC_CH_SAMPNUM_1X_gc; // No oversampling
|
15 | }
|
16 |
|
17 | // Test with internal bandgap reference as input and AVCC as reference (inverse measuring)
|
18 | /*void adc_init(void) {
|
19 | ADCA.CTRLA = ADC_ENABLE_bm; // Enable ADC
|
20 | ADCA.CTRLB = ADC_CURRLIMIT_HIGH_gc | ADC_CONMODE_bm | ADC_RESOLUTION_MT12BIT_gc; // No power saving, signed singleended mode, average resolution
|
21 | ADCA.REFCTRL = ADC_REFSEL_INTVCC_gc; // ==> Use internal AVCC/1.6
|
22 | ADCA.EVCTRL = ADC_EVACT_NONE_gc; // Do not use events
|
23 | ADCA.PRESCALER = ADC_PRESCALER_DIV8_gc; // ADC clock = 0.5 MHz speed
|
24 | ADCA.SAMPCTRL = 0x10; // Sampling time: shorter sampling time = lower impedance.
|
25 |
|
26 | ADCA.CH0.CTRL = ADC_CH_GAIN_1X_gc | ADC_CH_INPUTMODE_INTERNAL_gc; // x gain, use internal input (from DAC)
|
27 | ADCA.CH0.MUXCTRL = ADC_CH_MUXINT_BANDGAP_gc; // Use Bandgap reference as input to ADC
|
28 | ADCA.CH0.INTCTRL = ADC_CH_INTMODE_COMPLETE_gc | ADC_CH_INTLVL_OFF_gc; // No interrupts
|
29 | ADCA.CH0.SCAN = 0; // No channel scanning
|
30 | ADCA.CH0.AVGCTRL = ADC_CH_SAMPNUM_1024X_gc | (4 << ADC_CH_RIGHTSHIFT_gp); // Oversampling to 16-bit resolution 1024 = best stability
|
31 | }*/
|
32 |
|
33 | // returns the battery voltage in x10mv - 800mV (For correct value add 80(x10mV) )
|
34 | uint16_t ubat_read(void) {
|
35 | uint16_t res;
|
36 | uint16_t adc_res;
|
37 | // PORTD_OUTSET = 0x02;
|
38 | ADCA.CH0.INTFLAGS = ADC_CH_IF_bm; // Clear ADC interrupt flag
|
39 | ADCA.CH0.CTRL |= ADC_CH_START_bm; // Start ADC single conversion
|
40 | while (!(ADCA.CH0.INTFLAGS & ADC_CH_IF_bm)); // Wait for ADC to complete
|
41 | adc_res = ADCA.CH0.RES;
|
42 | // res = (adc_res * UBAT_FACT) - 80; // Return result in x10mV (243 + 80 = 2.23V)
|
43 | // PORTD_OUTCLR = 0x02;
|
44 | // return res;
|
45 | return adc_res;
|
46 | }
|
Anfangs hab ich das ganze auf einem Steckbrett zusammengebaut und
getestet. Dies hat auch super funktioniert.
Dann hab ich eine Leiterplatte machen lassen und darauf funktioniert's
nun nicht mehr, obwohl ich die Verdrahtung schon überprüft hab :-( .
Zum Schema: Einfach nur UBat an VCC, und mit einem Filter wie im DB auf
AVCC. Beide GND zusammen auf GND.