]> www.fi.muni.cz Git - bike-lights.git/blob - firmware/battery.c
battery.c: rework
[bike-lights.git] / firmware / battery.c
1 #include <avr/io.h>
2
3 #include "lights.h"
4
5 #define BATTERY_ADC_SHIFT       6
6 #define RESISTOR_HI     1500    // kOhm
7 #define RESISTOR_LO      100    // kOhm
8
9 static volatile uint16_t battery_adcval;
10 volatile unsigned char battery_critical;
11
12 void init_battery()
13 {
14         battery_adcval = 0;
15         battery_critical = 0;
16 }
17
18 void battery_adc(uint16_t adcval)
19 {
20         if (battery_adcval == 0) {
21                 battery_adcval = adcval << BATTERY_ADC_SHIFT;
22         } else { // running average
23                 battery_adcval += (adcval
24                         - (battery_adcval >> BATTERY_ADC_SHIFT));
25         }
26 }
27
28 unsigned char battery_100mv()
29 {
30         /*
31          * This is tricky: we need to maintain precision, so we first
32          * multiply adcval by as big number as possible to fit uint16_t,
33          * then divide to get the final value,
34          * and finally type-cast it to unsigned char.
35          * We don't do running average, as the required precision
36          * is coarse (0.1 V).
37          */
38         return (unsigned char)
39                 ((uint16_t)(
40                 (battery_adcval >> BATTERY_ADC_SHIFT)
41                 * (11                                      // 1.1V
42                 * (RESISTOR_HI+RESISTOR_LO)/RESISTOR_LO    // resistor ratio
43                 / 4)) >> 8);                               // divide by 1024
44 }
45
46 /* convert value in mV to value of ADC shifted by BATTERY_ADC_SHIFT */
47 #define MV_TO_ADC(x) \
48         ((uint16_t)(((uint32_t)(x) * 1024 * (1 << BATTERY_ADC_SHIFT)) \
49                 / ((uint32_t) 1100 \
50                         * ((RESISTOR_HI+RESISTOR_LO)/RESISTOR_LO))))
51
52 /* convert value in mV to upper 8 bits of ADC value << BATTERY_ADC_SHIFT */
53 #define MV_TO_ADC8(x)   ((unsigned char)(MV_TO_ADC(x) >> 8))
54
55 /*
56  * Returns number from 1 to 10 (1 = battery almost empty, 10 = full)
57  * Lithium cells have voltage from about 2.9V to 4.1V. We consider battery
58  * above 4V full, and under 3.2V critically low. We guess whether
59  * the battery has two or three cells - voltages above 8.6V are considered
60  * from three-cell battery.
61  */
62 unsigned char battery_gauge()
63 {
64         unsigned char b8 = battery_adcval >> 8;
65         unsigned char rv;
66
67         if        (b8 < MV_TO_ADC8(2 * 3200)) {
68                 rv = 1;
69         } else if (b8 < MV_TO_ADC8(2 * 3475)) {
70                 rv = 2;
71         } else if (b8 < MV_TO_ADC8(2 * 3577)) {
72                 rv = 3;
73         } else if (b8 < MV_TO_ADC8(2 * 3620)) {
74                 rv = 4;
75         } else if (b8 < MV_TO_ADC8(2 * 3741)) {
76                 rv = 5;
77         } else if (b8 < MV_TO_ADC8(2 * 3775)) {
78                 rv = 6;
79         } else if (b8 < MV_TO_ADC8(2 * 3844)) {
80                 rv = 7;
81         } else if (b8 < MV_TO_ADC8(2 * 3930)) {
82                 rv = 8;
83         } else if (b8 < MV_TO_ADC8(2 * 4000)) {
84                 rv = 9;
85         } else if (b8 < MV_TO_ADC8(2 * 4300)) {
86                 rv = 10;
87         } else if (b8 < MV_TO_ADC8(3 * 3200)) { // three-cell battery
88                 rv = 1;
89         } else if (b8 < MV_TO_ADC8(3 * 3475)) {
90                 rv = 2;
91         } else if (b8 < MV_TO_ADC8(3 * 3577)) {
92                 rv = 3;
93         } else if (b8 < MV_TO_ADC8(3 * 3620)) {
94                 rv = 4;
95         } else if (b8 < MV_TO_ADC8(3 * 3741)) {
96                 rv = 5;
97         } else if (b8 < MV_TO_ADC8(3 * 3775)) {
98                 rv = 6;
99         } else if (b8 < MV_TO_ADC8(3 * 3844)) {
100                 rv = 7;
101         } else if (b8 < MV_TO_ADC8(3 * 3930)) {
102                 rv = 8;
103         } else if (b8 < MV_TO_ADC8(3 * 4000)) {
104                 rv = 9;
105         } else {
106                 rv = 10;
107         }
108
109         if (rv == 1)
110                 battery_critical = 1;
111
112 #if 0
113         log_byte(0xbb);
114         log_byte(rv);
115         log_flush();
116 #endif
117
118         return rv;
119 }