Forum: Mikrocontroller und Digitale Elektronik ATxmega: Batteriespannung messen mit int. Referenz und AVCC/10


von Thomas L. (delfinis)


Lesenswert?

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.

: Bearbeitet durch User
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.