From 5d0f6ceb47eed2282aeb11eb57eebc390add234e Mon Sep 17 00:00:00 2001 From: "Jan \"Yenya\" Kasprzak" Date: Thu, 28 Feb 2013 00:56:55 +0100 Subject: [PATCH] battery.c: rework We can use values in mV instead of 100 mV. We can also provide the battery level on scale from 1 to 10. --- firmware/battery.c | 97 ++++++++++++++++++++++++++++++++++++++++++++-- firmware/lights.h | 2 +- 2 files changed, 94 insertions(+), 5 deletions(-) diff --git a/firmware/battery.c b/firmware/battery.c index 01337db..d7123e9 100644 --- a/firmware/battery.c +++ b/firmware/battery.c @@ -2,17 +2,30 @@ #include "lights.h" +#define BATTERY_ADC_SHIFT 6 #define RESISTOR_HI 1500 // kOhm #define RESISTOR_LO 100 // kOhm -volatile unsigned char battery_100mv = 0; +static volatile uint16_t battery_adcval; +volatile unsigned char battery_critical; void init_battery() { - battery_100mv = 0; + battery_adcval = 0; + battery_critical = 0; } void battery_adc(uint16_t adcval) +{ + if (battery_adcval == 0) { + battery_adcval = adcval << BATTERY_ADC_SHIFT; + } else { // running average + battery_adcval += (adcval + - (battery_adcval >> BATTERY_ADC_SHIFT)); + } +} + +unsigned char battery_100mv() { /* * This is tricky: we need to maintain precision, so we first @@ -22,9 +35,85 @@ void battery_adc(uint16_t adcval) * We don't do running average, as the required precision * is coarse (0.1 V). */ - battery_100mv = (unsigned char) - ((uint16_t)(adcval * (11 // 1.1V + return (unsigned char) + ((uint16_t)( + (battery_adcval >> BATTERY_ADC_SHIFT) + * (11 // 1.1V * (RESISTOR_HI+RESISTOR_LO)/RESISTOR_LO // resistor ratio / 4)) >> 8); // divide by 1024 } +/* convert value in mV to value of ADC shifted by BATTERY_ADC_SHIFT */ +#define MV_TO_ADC(x) \ + ((uint16_t)(((uint32_t)(x) * 1024 * (1 << BATTERY_ADC_SHIFT)) \ + / ((uint32_t) 1100 \ + * ((RESISTOR_HI+RESISTOR_LO)/RESISTOR_LO)))) + +/* convert value in mV to upper 8 bits of ADC value << BATTERY_ADC_SHIFT */ +#define MV_TO_ADC8(x) ((unsigned char)(MV_TO_ADC(x) >> 8)) + +/* + * Returns number from 1 to 10 (1 = battery almost empty, 10 = full) + * Lithium cells have voltage from about 2.9V to 4.1V. We consider battery + * above 4V full, and under 3.2V critically low. We guess whether + * the battery has two or three cells - voltages above 8.6V are considered + * from three-cell battery. + */ +unsigned char battery_gauge() +{ + unsigned char b8 = battery_adcval >> 8; + unsigned char rv; + + if (b8 < MV_TO_ADC8(2 * 3200)) { + rv = 1; + } else if (b8 < MV_TO_ADC8(2 * 3475)) { + rv = 2; + } else if (b8 < MV_TO_ADC8(2 * 3577)) { + rv = 3; + } else if (b8 < MV_TO_ADC8(2 * 3620)) { + rv = 4; + } else if (b8 < MV_TO_ADC8(2 * 3741)) { + rv = 5; + } else if (b8 < MV_TO_ADC8(2 * 3775)) { + rv = 6; + } else if (b8 < MV_TO_ADC8(2 * 3844)) { + rv = 7; + } else if (b8 < MV_TO_ADC8(2 * 3930)) { + rv = 8; + } else if (b8 < MV_TO_ADC8(2 * 4000)) { + rv = 9; + } else if (b8 < MV_TO_ADC8(2 * 4300)) { + rv = 10; + } else if (b8 < MV_TO_ADC8(3 * 3200)) { // three-cell battery + rv = 1; + } else if (b8 < MV_TO_ADC8(3 * 3475)) { + rv = 2; + } else if (b8 < MV_TO_ADC8(3 * 3577)) { + rv = 3; + } else if (b8 < MV_TO_ADC8(3 * 3620)) { + rv = 4; + } else if (b8 < MV_TO_ADC8(3 * 3741)) { + rv = 5; + } else if (b8 < MV_TO_ADC8(3 * 3775)) { + rv = 6; + } else if (b8 < MV_TO_ADC8(3 * 3844)) { + rv = 7; + } else if (b8 < MV_TO_ADC8(3 * 3930)) { + rv = 8; + } else if (b8 < MV_TO_ADC8(3 * 4000)) { + rv = 9; + } else { + rv = 10; + } + + if (rv == 1) + battery_critical = 1; + +#if 0 + log_byte(0xbb); + log_byte(rv); + log_flush(); +#endif + + return rv; +} diff --git a/firmware/lights.h b/firmware/lights.h index 753e281..5032e11 100644 --- a/firmware/lights.h +++ b/firmware/lights.h @@ -88,9 +88,9 @@ pattern_t *buttons_setup_status0_pattern_select(); pattern_t *buttons_setup_status1_pattern_select(); /* battery.c */ -extern volatile unsigned char battery_100mv; void battery_adc(); void init_battery(); +unsigned char battery_gauge(); /* control.c */ extern pattern_t on1_pattern[]; -- 2.39.3