Ver Fonte

重写被动均衡
1. 充电结束后判定压差,满足条件开始均衡
2. 均衡时间模式10分钟,期间不能采集电芯电压
3. 如果放电电流大于50mA,或者开始充电,结束均衡
4. 均衡期间不能休眠
Signed-off-by: huhui <huhui@sharkgulf.com>

huhui há 4 anos atrás
pai
commit
ed378d522a

+ 5 - 0
Application/app/sox/soc.c

@@ -480,6 +480,11 @@ uint32_t soc_get_charger_remain_time(void){
 	return charger_remain_time;
 }
 
+//not energy recovery when riding
+int soc_is_normal_charging(void) {
+	return _is_normal_charging();
+}
+
 static void soc_update_by_current_and_time(float current_now, float delta_time, uint8_t prev_charge_status){
 	double current = current_now / 1000.0f; //A
 	double delta_q = current * delta_time; 

+ 1 - 0
Application/app/sox/soc.h

@@ -38,5 +38,6 @@ u8 soc_get_version(void);
 void soc_set_version(u8 version);
 bool soc_is_force_full(void);
 void soc_clear_calibrate(int keep_cycle);
+int soc_is_normal_charging(void);
 
 

+ 133 - 33
Application/app/sox/state.c

@@ -29,7 +29,7 @@ static void _temperature_notify(void);
 static u32 _bms_main_task_handler(void);
 static void _debug_timer_handler(shark_timer_t *t);
 static void _process_power_down(void);
-static uint8_t calc_cell_voltage(void);
+static void calc_cell_voltage(void);
 static int _can_close_mos_no_hall(void);
 
 static bms_state_t _bms_state;
@@ -413,7 +413,8 @@ static void _process_deepsleep(s32 health){
 	if (!bms_work_is_normal()){
 		return; //测试模式下不休眠
 	}
-	if (ml5238_is_charging() || ml5238_is_discharging() || io_state()->charger_detect_irq || _bms_state.charging){
+	if (ml5238_is_charging() || ml5238_is_discharging() || io_state()->charger_detect_irq || _bms_state.charging || 
+		_bms_state.pack_balancing){
 		return;
 	}
 
@@ -630,48 +631,148 @@ static void _current_notify(void){
  * 木桶效应,目标是电压最高的那个cell,尽量压制,不让电压再升高,或者升高的尽量慢一些
 */
 static void _balance_timer_handler(shark_timer_t *t);
-
 static shark_timer_t _balance_timer = {.handler = _balance_timer_handler};
+static void _start_balance(uint16_t mask) {
+	int success = ml5238_cell_start_balance(mask);
+	if (success ) {
+		if (mask == 0) {
+			_bms_state.pack_balancing = 0;
+		}else {
+			_bms_state.pack_balancing = 1;
+		}
+	}
+}
 
-static debounce_t _cell_balance = {.count = 0, .max_count = 120, .init_count = 0};
+static void _stop_balance(void) {
+	_start_balance(0);
+}
 
 static void _balance_timer_handler(shark_timer_t *t){
-	ml5238_cell_start_balance(0);
-	_bms_state.pack_balancing = 0;
-	debounce_reset(_cell_balance);
+	_stop_balance();
+	if (_bms_state.pack_balancing) {
+		shark_timer_post(&_balance_timer, 1);
+	}
 }
 
-static uint32_t get_balance_mask(uint8_t current_max_index){
-	return BIT(current_max_index);
-}
 
-static void check_cell_balance(uint8_t current_max_index){
-	if (!_bms_state.charging || (_bms_state.cell_max_vol >= SIGLE_CELL_MAX_CHARGER_VOLTAGE) || !bms_work_is_normal()){ //not charging, need not do balance
-		if (_bms_state.pack_balancing){
-			debounce_reset(_cell_balance);
-			_bms_state.pack_balancing = ml5238_cell_start_balance(0);
-			shark_timer_cancel(&_balance_timer);
+static u16 _search_direct(u16 *delta_v, u8 current_cell, u8 *depth, u8 dir) {
+	u16 delta_next = 0;
+	u16 delta_prev = 0;
+	u8  idx_prev = 255;
+	u8  idx_next = 255;
+	u8  balance_idx = 255;
+	for (int i = 0; i < CELLS_NUM/2 + 1 ; i++) {
+		*depth ++;
+		//get the delta v of the prev and current
+		if (current_cell == 0) {
+			delta_prev = delta_v[CELLS_NUM - 1];
+			idx_prev = CELLS_NUM - 1;
+		}else {
+			delta_prev = delta_v[current_cell - 1];
+			idx_prev = current_cell - 1;
+		}
+		//get the delta v of the next and current
+		if (current_cell == CELLS_NUM - 1) {
+			delta_next = delta_v[0];
+			idx_next = 0;
+		}else {
+			delta_next = delta_v[current_cell + 1];
+			idx_next = current_cell + 1;
+		}
+		//use the max delta v of the prev and next
+		if (delta_prev >= delta_next) {
+			if(delta_prev >= MAX_DIFF_BETWEEN_MIN_MAX_CELL){
+				balance_idx = idx_prev; //balance with prev cell
+				break;
+			}
+		}else {
+			if(delta_next >= MAX_DIFF_BETWEEN_MIN_MAX_CELL){
+				balance_idx = idx_next; //balance with next cell
+				break;
+			}
+		}
+		if (dir == 1) {//search forword
+			current_cell = (current_cell + 1) % CELLS_NUM;
+		}else {        //search backwork
+			if (current_cell == 0) {
+				current_cell = CELLS_NUM - 1;
+			}else {
+				current_cell -= 1;
+			}
 		}
-		return;
-	}
-	if ((!_bms_state.pack_balancing && _bms_state.cell_max_vol < MAX_CELL_VOLTAGE_FOR_BALACNE) || _bms_state.pack_balancing){
-		debounce_reset(_cell_balance);
-		return;
 	}
-	if (_bms_state.cell_max_vol >= MAX_CELL_VOLTAGE_FOR_BALACNE){
-		debounce_inc(_cell_balance);
+	return balance_idx;
+}
+static u32 get_balance_maskV2(void) {
+	u16 delta_v[CELLS_NUM];
+	u16 *pcellv = measure_value()->cell_vol;
+
+	//calc the delta v of the Neighboring cells
+	delta_v[CELLS_NUM - 1] = abs(pcellv[CELLS_NUM-1] - pcellv[0]);
+	for (int i = 0; i < CELLS_NUM - 1; i++) {
+		delta_v[i] = pcellv[i] - pcellv[i + 1];
+	}
+	u8 depth_next, depth_prev;
+	u8 idx_next = _search_direct(delta_v, _bms_state.cell_index_of_max_vol, &depth_next, 1);// search from max to next....
+	u8 idx_prev = _search_direct(delta_v, _bms_state.cell_index_of_max_vol, &depth_next, 0);// search from max to prev
+	//chose the min depth whitch near from max voltage cell
+	if (depth_next < depth_prev) {
+		return BIT(idx_next);
+	}else if (depth_prev < depth_next) {
+		return BIT(idx_prev);
 	}else {
-		debounce_reset(_cell_balance);
+		if (idx_next < CELLS_NUM) {
+			return BIT(idx_next);
+		}
+		if (idx_prev < CELLS_NUM) {
+			return BIT(idx_prev);
+		}
+	}
+	return 0;
+}
+
+#define BALANCE_TIME (10 * 60) //S
+static u8 g_is_charging = 0;
+static u8 can_do_balance(void) {
+	u8 balance = 0;
+	//when stop normal(not energy recovery) charging, need check balance
+	if (g_is_charging && (!_bms_state.charging && soc_is_normal_charging())) {
+		balance = 1;
+	}
+	g_is_charging = _bms_state.charging;
+	//if already balancing, do nothing
+	if (_bms_state.pack_balancing) {
+		balance = 0;
+	}
+
+	return balance;
+}
+
+static u8 need_stop_balance(void) {
+	if (measure_value()->load_current < -50.0 || g_is_charging) {
+		return 1;
+	}
+	return 0;
+}
+
+static void check_cell_balance(void){
+	if (!can_do_balance()) {
+		if (need_stop_balance()) {
+			if (_bms_state.pack_balancing){
+				_stop_balance();
+				shark_timer_cancel(&_balance_timer);
+			}
+		}
+		return;
 	}
-	if (!_bms_state.pack_balancing && debounce_reach_max(_cell_balance)){
-		_bms_state.pack_balancing = 1;
-		ml5238_cell_start_balance(get_balance_mask(current_max_index));
-		shark_timer_post(&_balance_timer, 5 * 1000); //stop balance after 30s
-		debounce_reset(_cell_balance);
+	u16 mask = get_balance_maskV2();
+	if (mask) {
+		_start_balance(mask);
+		shark_timer_post(&_balance_timer, BALANCE_TIME * 1000); //stop balance after BALANCE_TIME
 	}
 }
 #endif
-static uint8_t calc_cell_voltage(void){
+static void calc_cell_voltage(void){
 	uint16_t voltage = 0;
 	uint16_t max_cell = 0;
 	uint16_t min_cell = 0xf000;
@@ -693,14 +794,13 @@ static uint8_t calc_cell_voltage(void){
 	_bms_state.cell_min_vol = min_cell;
 	_bms_state.cell_index_of_min_vol = min_index;
 	_bms_state.cell_index_of_max_vol = max_index;	
-	return max_index;
 }
 
 static void _voltage_notify(void){
-	uint8_t max_index = calc_cell_voltage();
+	calc_cell_voltage();
 	check_voltage_state(); //check health of cell voltage
 #if (ALLOW_5238_BALANCE==1)
-	check_cell_balance(max_index);
+	check_cell_balance();
 #endif
 }
 

+ 1 - 1
Application/app/sox/state.h

@@ -17,7 +17,7 @@
 #define MIN_DIFF_BT_5238_1180     500
 #define MIN_START_CHARGER_CURRENT 300 //ma, 如果有正向超过 MIN_START_CHARGER_CURRENT的电流,认为在充电
 #define MIN_START_LOADING_CURRENT 5  //ma, 如果有反向小于 MIN_START_LOADING_CURRENT的电流,认为在放电
-#define MAX_DIFF_BETWEEN_MIN_MAX_CELL 150 //0.15v ,压差超过这个值,开始balance
+#define MAX_DIFF_BETWEEN_MIN_MAX_CELL 100 //0.15v ,压差超过这个值,开始balance
 #define MIN_DIFF_BETWEEN_MIN_MAX_CELL 050 //0.05v, 牙差低于这个数据,停止balance
 #define MAX_CELL_VOLTAGE_FOR_BALACNE 3600
 #define CELL_FUSION_VOLTAGE      3500 //LFP电池在3.5v的时候,开始发散,需要判断是否要balance

+ 7 - 8
Application/bsp/ml5238.c

@@ -137,16 +137,15 @@ int ml5238_is_discharging(void){
 int ml5238_cell_start_balance(uint16_t balance_mask){
 	ml5238_write(ML5238_CBALH, (balance_mask >> 8) & 0xFF);
 	ml5238_write(ML5238_CBALL, balance_mask & 0xFF);
-	if (balance_mask == 0) { //stop balance need check
-		uint8_t datah = 0xFF;
-		uint8_t datal = 0xFF;
-		if ((ml5238_read(ML5238_CBALH, &datah) == 0) && (ml5238_read(ML5238_CBALL, &datal) == 0)) {
-			if ((datah == 0) && (datal == 0)) {
-				return 0;
-			}
+	uint8_t datah = 0xFF;
+	uint8_t datal = 0xFF;
+	if ((ml5238_read(ML5238_CBALH, &datah) == 0) && (ml5238_read(ML5238_CBALL, &datal) == 0)) {
+		if ((datah == ((balance_mask >> 8) & 0xFF)) && (datal == (balance_mask & 0xFF))) {
+			return 1;
 		}
 	}
-	return 1;
+
+	return 0;
 }