#include "common.h" #include "drv_usart.h" #include "app_rs485_1.h" #include "app.h" #include "hardware_test.h" #include "app_end_ctr.h" #include "drv_io.h" //uart1 static uint8_t app_rs485_buf[TX_BUFFER_SIZE]; static uint8_t bms_addr = SUB_BMS_ADDRESS_1; SUB_BMS_COM sub_rs485_time_out_1; SUB_BMS_INFO sub_bms_info_1; DELAY_COMMON send_delay; uint8_t RS485_busy_1 = 0; uint8_t sub_bms_1_connect = 0; uint8_t cang_wei = CW_CHE_SHANG_NO_CHARGER; TEST_INFO test_info; static int8_t Get_Check_Sum_1(uint16_t*value,uint8_t*data,uint16_t size) { uint32_t checksum; if((NULL==value)||(NULL==data)||(0==size)) { return 0; } // checksum = 0; while(size>1) { checksum += *(uint16_t*)data; data += 2; size -= 2; } // if(size>0) { checksum += *data; } // while(checksum>>16) { checksum = (checksum&0xFFFF)+(checksum>>16); } // *value = (uint16_t)~checksum; return 1; } uint8_t SUB_BMS_1_DEC(void) { return sub_bms_1_connect; } void RS485_Communication_Time_Out_1(void) { if(sub_bms_info_1.rs485_connect) { sub_bms_info_1.conn_state = SUB_BMS_CONT_NO485; } else { sub_bms_info_1.conn_state = SUB_BMS_DISC_NO485; } if(sub_bms_info_1.rs485_time_out) return; memset(&sub_bms_info_1.packet_common,0x00,sizeof(sub_bms_info_1.packet_common)); memset(&sub_bms_info_1.bat_dev_info,0x00,sizeof(sub_bms_info_1.bat_dev_info)); memset(&sub_bms_info_1.bat_times,0x00,sizeof(sub_bms_info_1.bat_times)); memset(&sub_bms_info_1.cell_vol,0x00,sizeof(sub_bms_info_1.cell_vol)); memset(&sub_bms_info_1.temp_other,0x00,sizeof(sub_bms_info_1.temp_other)); memset(&sub_bms_info_1.sub_bms_cmd,0x00,sizeof(sub_bms_info_1.sub_bms_cmd)); sub_bms_info_1.rs485_time_out = 1; sub_bms_info_1.sub_bms_cmd.operate = OP_READ_INFO; // sub_bms_1_connect = 0; } static int8_t Handle_Sub_BMS_CMD_1(uint8_t *data) { static uint8_t send_times = 0; COMMAND_BODY *bms = (COMMAND_BODY *)data; int8_t bStatus; uint16_t count; SUB_BMS_INFO *temp_bms; do { if(bms->type != bms_addr || bms->dir != BMS_DIR || bms->bStatus == 0) break; memset(&sub_rs485_time_out_1,0x00,sizeof(sub_rs485_time_out_1)); g_event &= ~SUB_BMS_1_RS485_DISC_EVENT; temp_bms = &sub_bms_info_1; temp_bms->rs485_time_out = 0; // sub_bms_1_connect = 1; RS485_busy_1 = 0; if(sub_bms_info_1.rs485_connect) { sub_bms_info_1.conn_state = SUB_BMS_CONT_HV485; } else { sub_bms_info_1.conn_state = SUB_BMS_DISC_HV485; } //CRC count = bms->checksum; bms->checksum = 0; bStatus = Get_Check_Sum_1((void*)&bms->checksum,data,bms->size); if(1!=bStatus || count != bms->checksum) { break; } //handle frame count = sizeof(COMMAND_BODY); memcpy(&temp_bms->packet_common,&data[count],sizeof(temp_bms->packet_common)); count += sizeof(temp_bms->packet_common); //bang zi ce shi start //temp_bms ->packet_common.m_percent /= 2; //bang zi ce shi end if((temp_bms->packet_common.operate_result&0x01) != 0x01) break; switch((temp_bms->packet_common.operate_result&0xF0)>>4) { case OP_NONE: break; case OP_BOND: break; case OP_WRITE_SN: break; case OP_PAIR: break; case OP_UPDATE_PAIR: break; case OP_READ_INFO: memcpy(&temp_bms->bat_dev_info,&data[count],sizeof(temp_bms->bat_dev_info)); count += sizeof(temp_bms->bat_dev_info); break; case OP_ALARM_TIMES: memcpy(&temp_bms->bat_times,&data[count],sizeof(temp_bms->bat_times)); count += sizeof(temp_bms->bat_times); break; case OP_CELL_VOL: memcpy(&temp_bms->cell_vol,&data[count],sizeof(temp_bms->cell_vol)); count += sizeof(temp_bms->cell_vol); break; case OP_TEMP_OTHER: memcpy(&temp_bms->temp_other,&data[count],sizeof(temp_bms->temp_other)); count += sizeof(temp_bms->temp_other); break; case OP_OPEN_FET: break; case OP_CLEAR_PAIR: break; case OP_UPDATE_SOFTWARE_REQ: break; case OP_UPDATE_SOFTWARE: break; default:break; } if(((temp_bms->packet_common.operate_result&0xF0)>>4) == temp_bms->sub_bms_cmd.operate) { memset(&temp_bms->sub_bms_cmd,0x00,sizeof(temp_bms->sub_bms_cmd)); ++send_times; if(send_times > 90) { temp_bms->sub_bms_cmd.operate = OP_ALARM_TIMES; send_times = 0; } else if(send_times > 60) { temp_bms->sub_bms_cmd.operate = OP_CELL_VOL; } else if(send_times > 30) { temp_bms->sub_bms_cmd.operate = OP_TEMP_OTHER; } else temp_bms->sub_bms_cmd.operate = OP_NONE; } return 1; }while(0); return 0; } static int8_t Send_Sub_BMS_CMD_1(void) { int8_t bStatus;// 默认需要回复 COMMAND_BODY*body = (COMMAND_BODY*)app_rs485_buf; uint8_t *buf = app_rs485_buf; SUB_BMS_INFO *temp_bms; temp_bms = &sub_bms_info_1; // 填帧头 body->size = sizeof(COMMAND_BODY); body->type = bms_addr; body->protocol = 'B'; body->cmd = SET_COMMAND; body->dir = BMS_DIR; body->checksum = 0; body->bStatus = 0; // 填帧数据 //实时转速 buf[body->size++] = 0; //本次电门打开已经行驶的里程 buf[body->size++] = 0; buf[body->size++] = 0; buf[body->size++] = 0; buf[body->size++] = 0; //电门开关信号 buf[body->size++] = 0; //操作 buf[body->size++] = temp_bms->sub_bms_cmd.operate; //对码 buf[body->size++] = cang_wei; buf[body->size++] = 0; buf[body->size++] = 0; buf[body->size++] = 0; //更换对码,新对码 buf[body->size++] = 0; buf[body->size++] = 0; buf[body->size++] = 0; buf[body->size++] = 0; switch(temp_bms->sub_bms_cmd.operate) { case OP_NONE: break; case OP_BOND: break; case OP_WRITE_SN: switch(temp_bms->sub_bms_cmd.param) { case 3: buf[body->size++] = (uint8_t)(temp_bms->sub_bms_cmd.param); break; case 4: buf[body->size++] = (uint8_t)(temp_bms->sub_bms_cmd.param); buf[body->size++] = (uint8_t)(update_bat.ub_total>>0); buf[body->size++] = (uint8_t)(update_bat.ub_total>>8); buf[body->size++] = 0; buf[body->size++] = 0; buf[body->size++] = (uint8_t)(update_bat.ub_sq>>0); buf[body->size++] = (uint8_t)(update_bat.ub_sq>>8); buf[body->size++] = 0; buf[body->size++] = 0; memcpy(&buf[body->size],update_bat.ub_data,update_bat.ub_len); body->size += update_bat.ub_len; break; } break; case OP_PAIR: break; case OP_UPDATE_PAIR: break; case OP_READ_INFO: break; case OP_ALARM_TIMES: break; case OP_CELL_VOL: break; case OP_OPEN_FET: buf[body->size++] = (uint8_t)(temp_bms->sub_bms_cmd.param); break; case OP_UPDATE_SOFTWARE_REQ: break; case OP_UPDATE_SOFTWARE: break; case OP_CLEAR_PAIR: break; default:break; } bStatus = Get_Check_Sum_1((void*)&body->checksum,(void*)body,body->size); if(1!=bStatus) { return 0; } Send_Data_RS485(buf,body->size); sub_rs485_time_out_1.set = 1; sub_rs485_time_out_1.count = 0; RS485_busy_1 = 1; return 1; } void Send_Sub_BMS_1_CMD(void) { if(RS485_busy_1) return; Send_Sub_BMS_CMD_1(); } void Check_Sub_BMS_1(void) { if(SUB_BMS_1_DEC()) { if(sub_bms_info_1.rs485_connect == 0) { sub_bms_info_1.rs485_connect = 1; sub_bms_info_1.sub_bms_cmd.operate = OP_READ_INFO; } } else { if(sub_bms_info_1.rs485_connect) { // memset(&sub_bms_info_1,0x00,sizeof(sub_bms_info_1)); memset(&sub_rs485_time_out_1,0x00,sizeof(sub_rs485_time_out_1)); RS485_busy_1 = 0; //sub_bms_1_lt_state = SUB_BMS_DISC_NO485; sub_bms_info_1.sub_bms_cmd.operate = OP_READ_INFO; if(cb_operate_state == CB_BAT1) { //Power_On_Normal(0); } } } } int8_t Handle_RS485_1_Data(void) { uint16_t len = Get_RS485_Data(app_rs485_buf,sizeof(app_rs485_buf)); if(len != app_rs485_buf[0]) { if(memcmp(app_rs485_buf,"zhengjiceshi",12) == 0 && ht_mode == 0) { Writer_HT_Flash(1); __set_FAULTMASK(1); NVIC_SystemReset(); } //idra-test-start RS485_Print(0x22,app_rs485_buf,len); //idra-test-end return 0; } if((app_rs485_buf[0] > sizeof(COMMAND_BODY))) { if(!Handle_Sub_BMS_CMD_1(app_rs485_buf)) { //idra-test-start RS485_Print(0x22,app_rs485_buf,len); //idra-test-end return 0; } } return 1; } void Sub_BMS_1_Initial(void) { Usart1_Initial(); memset(&sub_rs485_time_out_1,0x00,sizeof(sub_rs485_time_out_1)); memset(&sub_bms_info_1,0x00,sizeof(sub_bms_info_1)); send_delay.set = 1; send_delay.count = 0; sub_bms_info_1.sub_bms_cmd.operate = OP_READ_INFO; } void Sub_BMS_1_lt_State(void) { switch(sub_bms_info_1.conn_state) { case SUB_BMS_INVALID_STATUS: break; case SUB_BMS_DISC_NO485: break; case SUB_BMS_DISC_HV485: break; case SUB_BMS_CONT_HV485: break; case SUB_BMS_CONT_NO485: break; } } static shark_battery_exit_t shark_battery_is_normal_raw(SUB_BMS_INFO *info) { uint16_t work_status; if (info->define_error != D_BMS_ERROR_NO) { return SHARK_BATT_EXIT_ERROR; } if (info->test_error != D_BMS_ERROR_NO) { return SHARK_BATT_EXIT_ERROR; } work_status = info->packet_common.work_status; work_status &= ~(ST_CHRG_CUR | ST_DISCHRG_CUR | ST_OVRDISCHRG_CUR | ST_SMALL_CURRENT_OVER); if (IS_CHARGER_ON()) { work_status &= ~(ST_OVRDISCHRG_VOL | ST_PDOWN | ST_UDR_TEMPE_DISCHRG | ST_OVR_TEMPE_DISCHRG); } else { work_status &= ~(ST_OVRCHRG_VOL | ST_OVR_TEMPE_CHRG | ST_UDR_TEMPE_CHRG); } if(work_status) { return SHARK_BATT_EXIT_ERROR; } if (info->conn_state != SUB_BMS_CONT_HV485) { if (end_ctr_self_ss_new.xl_sta == 0 || info->state == SHARK_BATT_STATE_IDLE) { return SHARK_BATT_EXIT_485; } } if (update_bat.ub_bat != UPDATE_BAT_NO) { if (update_bat.ub_bat == UPDATE_BAT_1 && info == &sub_bms_info_1) { return SHARK_BATT_EXIT_UPGRADE; } if (update_bat.ub_bat == UPDATE_BAT_2 && info == &sub_bms_info_2) { return SHARK_BATT_EXIT_UPGRADE; } } return SHARK_BATT_EXIT_SUCCESS; } shark_battery_exit_t shark_battery_is_normal(SUB_BMS_INFO *info) { info->exit_code = shark_battery_is_normal_raw(info); return info->exit_code; } shark_bool shark_battery_is_normal_power_on(SUB_BMS_INFO *info) { if (shark_battery_is_normal(info) == SHARK_BATT_EXIT_SUCCESS) { if (shark_battery_is_power_full(info)) { return shark_true; } info->exit_code = SHARK_BATT_EXIT_POWER; } return shark_false; } shark_battery_exit_t Is_Sub_BMS_1_Normal(void) { return shark_battery_is_normal(&sub_bms_info_1); } int8_t Operate_Sub_BMS_1_CD(uint8_t on) { uint8_t cd_fet,rtn; uint16_t i,timeout = RS485_COM_TIMEOUT; sub_bms_info_1.sub_bms_cmd.operate = OP_OPEN_FET; switch(on) { case 1: cd_fet = 0x03; break; case 0: cd_fet = 0x00; break; case 2: cd_fet = 0x04; timeout = 2000; break; default: cd_fet = 0x00; break; } sub_bms_info_1.sub_bms_cmd.param = cd_fet; g_event &= ~RS485_RECEIVE_END_EVENT; Send_Sub_BMS_CMD_1(); cd_fet <<= 1; rtn = 0; for(i = 0; i < timeout/10;i++) { delay_1ms(10); if(g_event & RS485_RECEIVE_END_EVENT) { g_event &= ~RS485_RECEIVE_END_EVENT; Handle_RS485_1_Data(); if(on != 2) { if((sub_bms_info_1.packet_common.bms_status & cd_fet) == cd_fet) { rtn = 1; } } else { rtn = 1; } break; } } return rtn; } static u8 shark_battery_get_power_param(shark_battery_power_t power) { switch (power) { case SHARK_BATT_POWER_SMALL: return 0x04; case SHARK_BATT_POWER_FULL: return 0x03; default: return 0x00; } } static void shark_battery_set_power_param(SUB_BMS_INFO *info, shark_battery_power_t power) { info->sub_bms_cmd.operate = OP_OPEN_FET; info->sub_bms_cmd.param = shark_battery_get_power_param(power); } shark_battery_power_t shark_battery_get_power(SUB_BMS_INFO *info) { if (info->conn_state != SUB_BMS_CONT_HV485) { return SHARK_BATT_POWER_FAULT; } if ((info->packet_common.bms_status & BMS_POWER_ALL) == BMS_POWER_ALL) { return SHARK_BATT_POWER_ALL; } if ((info->packet_common.bms_status & BMS_POWER_FULL) == BMS_POWER_FULL) { return SHARK_BATT_POWER_FULL; } if ((info->packet_common.bms_status & BMS_POWER_SMALL) == BMS_POWER_SMALL) { return SHARK_BATT_POWER_SMALL; } return SHARK_BATT_POWER_OFF; } shark_bool shark_battery_check_power(SUB_BMS_INFO *info, shark_battery_power_t power) { switch (power) { case SHARK_BATT_POWER_SMALL: return SHARK_BOOL((info->packet_common.bms_status & BMS_POWER_SMALL) == BMS_POWER_SMALL); case SHARK_BATT_POWER_FULL: return SHARK_BOOL((info->packet_common.bms_status & BMS_POWER_FULL) == BMS_POWER_FULL); case SHARK_BATT_POWER_ALL: return SHARK_BOOL((info->packet_common.bms_status & BMS_POWER_ALL) == BMS_POWER_ALL); default: return SHARK_BOOL((info->packet_common.bms_status & BMS_POWER_ALL) == 0); } } u8 shark_battery_set_power(shark_battery_power_t power1, shark_battery_power_t power2, u8 mask) { u64 time = shark_get_time() + 200; u8 success = 0; u8 times; while (sub_bms_info_1.conn_state == SUB_BMS_CONT_HV485 && RS485_busy_1) { if (time < shark_get_time_safe()) { break; } } while (sub_bms_info_2.conn_state == SUB_BMS_CONT_HV485 && RS485_busy_2) { if (time < shark_get_time_safe()) { break; } } sub_bms_info_1.conn_state = SUB_BMS_DISC_HV485; sub_bms_info_2.conn_state = SUB_BMS_DISC_HV485; for (times = 0; times < 3; times++) { shark_battery_set_power_param(&sub_bms_info_1, power1); g_event &= ~RS485_RECEIVE_END_EVENT; shark_battery_set_power_param(&sub_bms_info_2, power2); g_event &= ~RS485_2_RECEIVE_END_EVENT; Send_Sub_BMS_CMD_1(); Send_Sub_BMS_CMD_2(); time = shark_get_time() + 200; while (time > shark_get_time_safe()) { if(g_event & RS485_RECEIVE_END_EVENT) { g_event &= ~RS485_RECEIVE_END_EVENT; Handle_RS485_1_Data(); if (shark_battery_check_power(&sub_bms_info_1, power1)) { success |= 1; } } if (g_event & RS485_2_RECEIVE_END_EVENT) { g_event &= ~RS485_2_RECEIVE_END_EVENT; Handle_RS485_2_Data(); if (shark_battery_check_power(&sub_bms_info_2, power2)) { success |= 2; } } if ((success & mask) == mask) { return mask; } } } return success; } u8 shark_battery_detect(void) { u64 time = shark_get_time() + 200; u8 success = 0; u8 times; while (sub_bms_info_1.conn_state == SUB_BMS_CONT_HV485 && RS485_busy_1) { if (time < shark_get_time_safe()) { break; } } while (sub_bms_info_2.conn_state == SUB_BMS_CONT_HV485 && RS485_busy_2) { if (time < shark_get_time_safe()) { break; } } sub_bms_info_1.conn_state = SUB_BMS_DISC_HV485; sub_bms_info_2.conn_state = SUB_BMS_DISC_HV485; for (times = 0; times < 3; times++) { sub_bms_info_1.sub_bms_cmd.operate = OP_READ_INFO; g_event &= ~RS485_RECEIVE_END_EVENT; sub_bms_info_2.sub_bms_cmd.operate = OP_READ_INFO; g_event &= ~RS485_2_RECEIVE_END_EVENT; Send_Sub_BMS_CMD_1(); Send_Sub_BMS_CMD_2(); time = shark_get_time() + 200; while (time > shark_get_time_safe()) { if(g_event & RS485_RECEIVE_END_EVENT) { g_event &= ~RS485_RECEIVE_END_EVENT; Handle_RS485_1_Data(); if (sub_bms_info_1.conn_state == SUB_BMS_CONT_HV485) { success |= 1; } } if (g_event & RS485_2_RECEIVE_END_EVENT) { g_event &= ~RS485_2_RECEIVE_END_EVENT; Handle_RS485_2_Data(); if (sub_bms_info_2.conn_state == SUB_BMS_CONT_HV485) { success |= 2; } } if (success == 3) { return 3; } } } return success; } int8_t Update_Sub_BMS_1_Software(uint8_t step) { uint8_t rtn; uint16_t i,timeout = RS485_COM_UPDATE_TIMEOUT; switch(step) { case UPDATE_STEP_NO: return 0; case UPDATE_STEP_REQ: sub_bms_info_1.sub_bms_cmd.operate = OP_WRITE_SN; sub_bms_info_1.sub_bms_cmd.param = 0x03; break; case UPDATE_STEP_DATA: sub_bms_info_1.sub_bms_cmd.operate = OP_WRITE_SN; sub_bms_info_1.sub_bms_cmd.param = 0x04; break; default: return 0; } g_event &= ~RS485_RECEIVE_END_EVENT; Send_Sub_BMS_CMD_1(); rtn = 0; for(i = 0; i < timeout/10;i++) { delay_1ms(10); if(g_event & RS485_RECEIVE_END_EVENT) { g_event &= ~RS485_RECEIVE_END_EVENT; rtn = Handle_RS485_1_Data(); break; } } return rtn; } uint8_t Sub_BMS_1_COM_Finish(void) { return sub_bms_info_1.conn_state; } void Save_Test_Info_To_Flash(uint8_t *data,uint16_t len) { uint32_t capacity = (REG32(0x1FFFF7E0) & 0xFFFF) << 10; uint32_t address = 0x08000000 + (capacity - TEST_INFO_FLASH_ADDRESS); uint8_t i = 0; uint32_t df_value = 0x0325; fmc_unlock(); Flash_flag_clear(); fmc_page_erase(address); Flash_flag_clear(); fmc_lock(); fmc_unlock(); i = 0; while(iti_flag != TI_VALID_FLAG_KEY) { test_info.ti_flag = TI_VALID_FLAG_KEY; Save_Test_Info_To_Flash((uint8_t *)&test_info,sizeof(test_info)); } else { test_info = *temp_test_info; test_info.ti_set = 0; } } void Save_Test_Info(void) { //if(test_info.ti_set == 0) // return; Save_Test_Info_To_Flash((uint8_t*)&test_info, sizeof(test_info)); } void Ca_Chu_Test_Info(void) { memset(&test_info, 0x00,sizeof(test_info)); test_info.ti_flag = TI_VALID_FLAG_KEY; Save_Test_Info_To_Flash((uint8_t *)&test_info,sizeof(test_info)); } void Check_Enable_Test_Info(void) { if(cb_operate_state == CB_BAT1_BAT2_SERIES) test_info.ti_set = 1; else test_info.ti_set = 0; } void shark_bms_set_vgs(shark_bms_vgs_t mask, uint8_t enable) { static uint8_t shark_bms_vgs_mask; println("fl: %d %d", mask, enable); if (enable) { shark_bms_vgs_mask |= mask; gpio_bit_reset(GPIO_PORT_FL, GPIO_PIN_FL); } else { shark_bms_vgs_mask &= ~mask; if (shark_bms_vgs_mask == 0) { gpio_bit_set(GPIO_PORT_FL, GPIO_PIN_FL); println("fl disabled"); } } } void shark_bms_set_mos(shark_bool ss, shark_bool s11, shark_bool s21) { println("S11:%d, S21:%d, SS:%d", s11, s21, ss); shark_bms_set_vgs(SHARK_BMS_VGS_FV, s11); if (ss == 0) { gpio_bit_reset(GPIO_PORT_SS, GPIO_PIN_SS); } if (s11 == 0) { gpio_bit_reset(GPIO_PORT_S11, GPIO_PIN_S11); } if (s21 == 0) { gpio_bit_reset(GPIO_PORT_S21, GPIO_PIN_S21); } if (ss != 0) { gpio_bit_set(GPIO_PORT_SS, GPIO_PIN_SS); } if (s11 != 0) { gpio_bit_set(GPIO_PORT_S11, GPIO_PIN_S11); } if (s21 != 0) { gpio_bit_set(GPIO_PORT_S21, GPIO_PIN_S21); } }