forked from microfarad-de/LiCharger
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathLiCharger.cpp
153 lines (122 loc) · 5.14 KB
/
LiCharger.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
/*
* Lithium-Ion Battery Charger Class
*
* This source file can be found under:
* http://www.github.com/arduino-library/LiCharger
*
* Please visit:
* http://www.microfarad.de
* http://www.github.com/microfarad-de
* http://www.github.com/arduino-library
*
* Copyright (C) 2019 Karim Hraibi (khraibi at gmail.com)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "LiCharger.h"
/*
* Configuration parameters
*/
#define V_MAX 4150000 // 4.15 V - Maximum allowed battery voltage per cell in µV
#define V_START_MAX 4100000 // 4.10 V - Start charging below this voltage per cell in µV
#define V_START_MIN 2200000 // 2.20 V - Start charging above this voltage per cell in µV (lower than V_MIN to overcome BMS shutdown)
#define V_SURGE 4250000 // 4.25 V - maximum allowed surge voltage threshold per cell in µV
#define V_SAFE 2800000 // 2.80 V - Charge with reduced current I_safe below this voltage per cell in µV
#define V_WINDOW 2000 // 0.002 V - Do not regulate voltage when within +/- this window (per cell) in µV
#define I_WINDOW 15000 // 0.015 A - Do not regulate current when within +/- this window in µA
#define I_FULL 200 // 200 mA - End of charge current in mA
#define I_SAFE_DIVIDER 10 // Divide I_chrg by this value to calculate I_safe, which is the reduced safety charging current
#define START_DELAY 2000 // Time duration in ms during which V shall be between V_START_MIN and V_START_MAX before starting to charge
#define FULL_DELAY 20000 // Time duration in ms during which I_full shall not be exceeded in order to assume that battery is full
#define UPDATE_DELAY 100 // Time interval in ms for updating the output by one increment
#define ERROR_DELAY 150 // Time duration in ms during which I or V shall be out of bounds in order to trigger an error condition
void LiChargerClass::initialize ( uint8_t nCells, uint16_t iChrg, void (*callbackFct)(uint8_t pwm) ) {
this->nCells = nCells;
this->iChrg = iChrg;
this->callbackFct = callbackFct;
this->state = LI_CHARGER_STATE_STANDBY_E;
}
void LiChargerClass::loopHandler (uint32_t v, uint32_t i) {
uint32_t ts = millis ();
if (!active) return;
// Main state machine
switch (state) {
case LI_CHARGER_STATE_STANDBY_E:
startTs = ts;
pwm = 0;
callbackFct (pwm);
state = LI_CHARGER_STATE_STANDBY;
case LI_CHARGER_STATE_STANDBY:
// Start charging if V stays within bounds during DELAY_CHARGE
if ( v < (uint32_t)V_START_MIN * nCells || v > (uint32_t)V_START_MAX * nCells) startTs = ts;
if (ts - startTs > START_DELAY) {
state = LI_CHARGER_STATE_CHARGE_E;
}
break;
case LI_CHARGER_STATE_CHARGE_E:
updateTs = ts;
fullTs = ts;
errorTs = ts;
iMax = (uint32_t)iChrg * 1000 / I_SAFE_DIVIDER;
safeCharge = true;
state = LI_CHARGER_STATE_CHARGE;
case LI_CHARGER_STATE_CHARGE:
// CC-CV Regulation:
// Run the regulation routine at the preset interval
if (ts - updateTs > UPDATE_DELAY) {
updateTs = ts;
// Regulate voltage and current with the CC-CV algorithm
if ( ( v > (uint32_t)V_MAX * nCells + (uint32_t)V_WINDOW * nCells ) ||
( i > iMax + (uint32_t)I_WINDOW ) ) {
if (pwm > 0) pwm--;
}
else if ( ( v < (uint32_t)V_MAX * nCells - (uint32_t)V_WINDOW * nCells ) &&
( i < iMax - (uint32_t)I_WINDOW ) ) {
if (pwm < 255) pwm++;
}
// Update the PWM duty cycle
callbackFct (pwm);
}
// Terminate safety charging if voltage is higher than V_SAFE
if (v > (uint32_t)V_SAFE * nCells && safeCharge) {
safeCharge = false;
iMax = (uint32_t)iChrg * 1000;
}
// End of Charge Detection:
// Report battery full if I_full has not been exceeded during FULL_DELAY (ignore during safety charging)
if ( i > (uint32_t)I_FULL * 1000 || safeCharge ) fullTs = ts;
if (ts - fullTs > FULL_DELAY) {
state = LI_CHARGER_STATE_STANDBY_E;
}
// Error Detection:
// Abort charging if V suddenly increases beyound V_SURGEs during TIMEOUT_ERROR
if (v < (uint32_t)V_SURGE * nCells) errorTs = ts;
if (ts - errorTs > ERROR_DELAY) {
state = LI_CHARGER_STATE_STANDBY_E;
}
break;
default:
break;
}
}
void LiChargerClass::start (void) {
active = true;
}
void LiChargerClass::stop (void) {
active = false;
pwm = 0;
callbackFct (pwm);
state = LI_CHARGER_STATE_STANDBY_E;
}