remain_distance.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533
  1. /**
  2. ******************************************************************************
  3. * @file remain_distance.c
  4. * @author Damon
  5. * @version V1.5
  6. * @date 20190105
  7. * @brief 电池剩余续航里程统计
  8. ******************************************************************************
  9. * @attention
  10. *本功能模块输出计算结果为,剩余续航里程RemainDis.remainDistance
  11. *
  12. ******************************************************************************
  13. */
  14. #include "remain_distance.h"
  15. #include "battery_info.h"
  16. #include "eeprom_24c02.h"
  17. /*电流积分,最小值,单位mA*/
  18. #define CURRENT_MIN 130
  19. /*电流积分周期*/
  20. #define Q_ADD_TIME_MS 5
  21. extern const MC_AvgPower_Struct_t MC_AvgPower_Default;
  22. //续航计算相关参数
  23. Remain_Dis_t RemainDis = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFFFF, 0, 0, FALSE, 0};
  24. //电池信息
  25. Battery_Info_t Battery_Info;
  26. /******************************************************************************
  27. * @Function: void RD_getQRemainRecord( void )
  28. * @Discrible: 读取电池剩余电量
  29. * @Param:
  30. * @Return:
  31. * @Others: 此函数在系统上电时调用一次,读取电池剩余电量
  32. 已添加到RD_RemainDis_init(void),无需单独调用
  33. ******************************************************************************
  34. * @Recode date version author modify
  35. * ------------------------------------------------------------------
  36. * 20190815 V1.3 Damon modify
  37. *
  38. *******************************************************************************/
  39. static void RD_getQRemainRecord(uint16_t Volgate)
  40. {
  41. uint16_t BusVoltage;
  42. uint16_t i;
  43. uint16_t num,batteryTotalQ,batteryRemainQ;
  44. //获取母线初始电压
  45. BusVoltage = Volgate;
  46. //查表读取电池电量
  47. num = sizeof(battery_VoltageQuantity) / 4;
  48. batteryTotalQ = battery_VoltageQuantity[num-1][1];
  49. batteryRemainQ = batteryTotalQ;
  50. for(i=0; i<num; i++)
  51. {
  52. if(battery_VoltageQuantity[i][0] <= BusVoltage)
  53. {
  54. batteryRemainQ = batteryTotalQ - battery_VoltageQuantity[i][1] ; //A*s
  55. Battery_Info.Q_remain_record = batteryRemainQ * 10 / 36; //mAh
  56. break;
  57. }
  58. else//电池电压低于最小值
  59. {
  60. batteryRemainQ = 0;
  61. }
  62. }
  63. MC_RunInfo.SOC = batteryRemainQ * 100 / batteryTotalQ;
  64. Battery_Info.Q_remain_real = Battery_Info.Q_remain_record;
  65. }
  66. /******************************************************************************
  67. * @Function: void RD_RemainDis_init(void)
  68. * @Discrible: 模块功能初始化
  69. * @Param: uwWheelLength:轮胎周长,BusVoltage:母线电压
  70. * @Return:
  71. * @Others: 此函数在进入主循环前调用,调用后,标志位置位,开启模块的统计功能
  72. ******************************************************************************
  73. * @Recode date version author modify
  74. * ------------------------------------------------------------------
  75. * 20181221 V1.2 Damon modify
  76. *
  77. *******************************************************************************/
  78. void RD_RemainDis_Init(uint16_t uwWheelLength, TrueOrFalse_Flag_Struct_t BMS_COM_OK, uint16_t BusVoltage, uint8_t DesignVol, uint16_t BMS_RC)
  79. {
  80. Battery_Info.Q_discharged = 0;
  81. Battery_Info.Q_remain_real = 0;
  82. Battery_Info.Q_remain_record = BATTERY_TATAL_Q_MAH;
  83. Battery_Info.Q_remain_real_last = 0;
  84. if(BMS_COM_OK == TRUE) //电池通讯正常时,直接获取电池容量
  85. {
  86. Battery_Info.Q_remain_real = BMS_RC;
  87. }
  88. else //电池不含通讯时,根据母线电压估算剩余容量
  89. {
  90. // RD_getQRemainRecord(BusVoltage * 36 / DesignVol); //放电曲线是按照36V,针对48V或24V做等效转换
  91. }
  92. RemainDis.start = 0;
  93. RemainDis.I_motor = 0;
  94. RemainDis.acc_period = Q_ADD_TIME_MS;
  95. RemainDis.Q_add = 0;
  96. RemainDis.wheelLength = uwWheelLength;
  97. RemainDis.wheel_Count = 0;
  98. RemainDis.Power_per_km = 0;
  99. RemainDis.Power_per_km_average = 0;
  100. RemainDis.remainDistance = 0xFFFF;//码表显示---km
  101. RemainDis.flag_saveInfo = 0;
  102. RemainDis.flag_helpModeChange = 0;
  103. RemainDis.IsBMS_ComOK_Flag = FALSE;
  104. RemainDis.BMS_Com_DelayTimeCnt = HAL_GetTick();
  105. }
  106. /******************************************************************************
  107. * @Function: void RD_CalculateRemainDis(void)
  108. * @Discrible: 计算电池剩余续航里程
  109. * @Param:
  110. * @Return:
  111. * @Others: 计算平均功耗(中间变量),和剩余续航里程
  112. ******************************************************************************
  113. * @Recode date version author modify
  114. * ------------------------------------------------------------------
  115. * 20181210 V1.4 Damon modify
  116. *
  117. *******************************************************************************/
  118. void RD_CalculateRemainDis(uint32_t WheelTurnCnt, uint16_t RemainCap, uint8_t SOC, uint16_t BusCurrent)
  119. {
  120. /*以下宏定义会影响平均功耗计算结果的变化快慢
  121. WHEEL_COUNT_REFRESH_VALUE 电量统计周期,每10圈统计一次电量
  122. Q_FIFO_LENGTH 动态平均功耗,取平均值的长度。Power_per_km(10圈x25=250圈,即动态功耗是车轮骑行250圈的平均值)
  123. P_FIFO_LENGTH 对Power_per_km求平均值的长度,Power_per_km_average(250圈x10=-2500圈)
  124. 修改宏定义的大小,可以改变Power_per_km_average的更新快慢,最终影响剩余续航里程的更新快慢。
  125. */
  126. /*车轮圈数,最小的电量统计周期*/
  127. #define WHEEL_COUNT_REFRESH_VALUE 10
  128. /*动态平均功耗,缓存长度*/
  129. #define Q_FIFO_LENGTH 25 //25 250圈 约500m
  130. /*平均功耗,缓存长度*/
  131. #define P_FIFO_LENGTH 30 //约15KM
  132. static uint16_t Q_FIFO[Q_FIFO_LENGTH]={0};
  133. static uint16_t Q_Index=0;
  134. static uint32_t Q_sum=0;
  135. static uint8_t Q_fifo_full_falg=0;
  136. static int16_t Q_add_tmp=0;
  137. static int32_t PowerPerKmFltSum=0;
  138. uint8_t i;
  139. int32_t ptmp;
  140. static uint32_t RunTimeCnt = 0;
  141. static uint32_t WheelTurnCntOld = 0;
  142. if((HAL_GetTick() - RunTimeCnt) < Q_ADD_TIME_MS)//计算周期为Q_ADD_TIME_MS
  143. {
  144. return;
  145. }
  146. RunTimeCnt = HAL_GetTick();
  147. //更新母线电流值
  148. RemainDis.I_motor = BusCurrent;
  149. //更新计算周期内轮子圈数
  150. RemainDis.wheel_Count = WheelTurnCnt - WheelTurnCntOld;
  151. /*开始计算*/
  152. if(RemainDis.start == 1)
  153. {
  154. /*电池通讯中断超时2s判断*/
  155. if((HAL_GetTick() - RemainDis.BMS_Com_DelayTimeCnt) > 2000)
  156. {
  157. RemainDis.BMS_Com_DelayTimeCnt = HAL_GetTick();
  158. RemainDis.IsBMS_ComOK_Flag = FALSE;
  159. }
  160. else
  161. {
  162. //更新电池剩余容量
  163. Battery_Info.Q_remain_real = RemainCap;
  164. }
  165. /*助力档位切换后*/
  166. if( RemainDis.flag_helpModeChange == 1 )
  167. {
  168. RemainDis.flag_helpModeChange = 0;
  169. /*清空一级缓冲区数据*/
  170. for(i=0;i<Q_FIFO_LENGTH;i++)
  171. {
  172. Q_FIFO[i] = 0;
  173. }
  174. Q_Index = 0;
  175. Q_sum = 0;
  176. Q_fifo_full_falg=0;
  177. if(RemainDis.Power_per_km_average != 0)
  178. {
  179. /*赋值求平均值的总和*/
  180. PowerPerKmFltSum = RemainDis.Power_per_km_average << 8;
  181. }
  182. }
  183. /*轮圈数大于设定值,计算一次*/
  184. if( RemainDis.wheel_Count >= WHEEL_COUNT_REFRESH_VALUE)
  185. {
  186. WheelTurnCntOld = WheelTurnCnt;
  187. /*消耗电量信息来自电池*/
  188. if(RemainDis.IsBMS_ComOK_Flag == TRUE )
  189. {
  190. //更新电池剩余容量
  191. Battery_Info.Q_remain_real = RemainCap;
  192. //更新电池剩余电量
  193. Battery_Info.SOC = SOC;
  194. if(Battery_Info.Q_remain_real_last != 0)
  195. {
  196. Q_add_tmp = (int16_t)(Battery_Info.Q_remain_real_last - Battery_Info.Q_remain_real);
  197. /*充电状态,或由母线电流切换到电量信息计算时,此值会出现负数*/
  198. Q_add_tmp = (Q_add_tmp > 0) ? Q_add_tmp : 0;
  199. Q_add_tmp = (Q_add_tmp < 30) ? Q_add_tmp : 30;
  200. /*判断电池是否满充*/
  201. if( ( Q_add_tmp == 0 ) && ( Battery_Info.SOC == 100 ) )
  202. {
  203. /*当电池满充时,发出的电量信息会是标称值,
  204. 在Battery.SOC==100时不会随电量消耗尔减小*/
  205. /*置标志位,不计算更新*/
  206. }
  207. else
  208. {
  209. /*将一定轮圈数消耗的电量,写入FIFO,FIFO中的数据滑动求平均值*/
  210. Q_sum -= Q_FIFO[Q_Index];
  211. Q_sum += Q_add_tmp;
  212. Q_FIFO[Q_Index++] = Q_add_tmp;
  213. if(Q_Index>=Q_FIFO_LENGTH)
  214. {
  215. Q_Index = 0;
  216. Q_fifo_full_falg = 1;
  217. /*250圈,动态功耗刷新一次,置一次eeprom保存标志*/
  218. RemainDis.flag_saveInfo = 1;
  219. }
  220. /*
  221. wheelCount x WHEEL_LENGTH(cm)
  222. ------------------------------- (km) wheelCount=(Q_FIFO_LENGTH * WHEEL_COUNT_REFRESH_VALUE)
  223. 1000 x 100
  224. Q_sum(mA*h) x 1000 x 100
  225. ------------------------------- (mA*h/km)
  226. wheelCount x WHEEL_LENGTH
  227. */
  228. if( Q_sum > 0 )
  229. {
  230. /*缓存满后,求平均值*/
  231. if(Q_fifo_full_falg==1)
  232. {
  233. RemainDis.Power_per_km = (Q_sum * 1000 * 100 ) / ( Q_FIFO_LENGTH * WHEEL_COUNT_REFRESH_VALUE * RemainDis.wheelLength );
  234. }
  235. else
  236. {
  237. /*缓存数据未满,以当前有效数据个数求平均值*/
  238. RemainDis.Power_per_km = (Q_sum * 1000 * 100 ) / ( Q_Index * WHEEL_COUNT_REFRESH_VALUE * RemainDis.wheelLength );
  239. }
  240. }
  241. else
  242. {
  243. RemainDis.Power_per_km = 0;
  244. }
  245. /*电量缓存Q_FIFO计满一次,滑动滤波求平均值*/
  246. if(Q_Index==0)
  247. {
  248. ptmp = RemainDis.Power_per_km;
  249. PowerPerKmFltSum += ((ptmp << 8) - PowerPerKmFltSum) / P_FIFO_LENGTH;
  250. RemainDis.Power_per_km_average = (uint16_t)(PowerPerKmFltSum >> 8);
  251. }
  252. /*计算剩余续航里程*/
  253. if(RemainDis.Power_per_km_average > 0)
  254. {
  255. RemainDis.remainDistance = Battery_Info.Q_remain_real / RemainDis.Power_per_km_result;//单位km
  256. }
  257. else
  258. {
  259. RemainDis.remainDistance = 0xFFFF;//码表显示---km
  260. }
  261. }
  262. }
  263. }
  264. /*电量信息来自电池的计算,需要用到此数据*/
  265. Battery_Info.Q_remain_real_last = Battery_Info.Q_remain_real;
  266. }
  267. }
  268. }
  269. /******************************************************************************
  270. * @Function: void RD_saveAndUpdateInfo(uint8_t uwHelpMode)
  271. * @Discrible: 保存功耗数据到EEPROM
  272. * @Param:
  273. * @Return:
  274. * @Others: 每一公里,保存一次数据到eeprom;助力档位切换时,刷新计算的功耗数据。此函数在主循环中调用
  275. ******************************************************************************
  276. * @Recode date version author modify
  277. * ------------------------------------------------------------------
  278. * 20190105 V1.4 Damon modify
  279. *
  280. *******************************************************************************/
  281. void RD_SaveAndUpdateInfo(MC_GearSt_Struct_t GearSt, MC_AssistRunMode_Struct_t MC_AssistRunMode)
  282. {
  283. static MC_GearSt_Struct_t MC_GearSt_Old = MC_GearSt_OFF;
  284. static MC_AssistRunMode_Struct_t MC_AssistRunMode_Old = MC_AssistRunMode_INVALID;
  285. static uint16_t usPowerPerKmAverageLast =0;
  286. static uint16_t powerDefaultCurrentMode=0;
  287. int16_t sPercent;
  288. int32_t ltmp;
  289. if( ( (GearSt & 0x0F) != 0 ) && ( MC_AssistRunMode != MC_AssistRunMode_INVALID ))
  290. {
  291. RemainDis.start = 1;
  292. /*保存当前助力档位的数据到eeprom*/
  293. if( RemainDis.flag_saveInfo == 1 )
  294. {
  295. RemainDis.flag_saveInfo = 0;
  296. /*平均功耗值有更新时,执行保存数据相关操作*/
  297. if( RemainDis.Power_per_km_average != usPowerPerKmAverageLast )
  298. {
  299. if(RemainDis.Power_per_km_average != 0)
  300. {
  301. /*计算平均功耗,增减量的百分比,放大100倍*/
  302. ltmp = (int32_t)(RemainDis.Power_per_km_average - powerDefaultCurrentMode) * 100;
  303. sPercent = ltmp / powerDefaultCurrentMode;
  304. /*各档位关联*/
  305. /*不低于默认值30%*/
  306. if( (sPercent >= -30)&&(sPercent <= 455) )
  307. {
  308. /*更新平均功耗*/
  309. RemainDis.Power_per_km_result = powerDefaultCurrentMode * ( 100 + sPercent ) / 100;
  310. /*计算各档位增减后的值*/
  311. ltmp = MC_AvgPower_Default.GearSt_ECO;
  312. MC_AvgPower.GearSt_ECO = ltmp * ( 100 + sPercent ) / 100;
  313. ltmp = MC_AvgPower_Default.GearSt_NORM;
  314. MC_AvgPower.GearSt_NORM = ltmp * ( 100 + sPercent ) / 100;
  315. ltmp = MC_AvgPower_Default.GearSt_SPORT;
  316. MC_AvgPower.GearSt_SPORT = ltmp * ( 100 + sPercent ) / 100;
  317. ltmp = MC_AvgPower_Default.GearSt_TURBO;
  318. MC_AvgPower.GearSt_TURBO = ltmp * ( 100 + sPercent ) / 100;
  319. ltmp = MC_AvgPower_Default.GearSt_5;
  320. MC_AvgPower.GearSt_5 = ltmp * ( 100 + sPercent ) / 100;
  321. ltmp = MC_AvgPower_Default.GearSt_SMART;
  322. MC_AvgPower.GearSt_SMART = ltmp * ( 100 + sPercent ) / 100;
  323. ltmp = MC_AvgPower_Default.GearSt_SMART_T;
  324. MC_AvgPower.GearSt_SMART_T = ltmp * ( 100 + sPercent ) / 100;
  325. /*保存所有档位的更新数据*/
  326. SaveParamToEEprom_24C02(&I2C_Handle_EEPROM, EEPROM_24C02_ADDR_AVG_POWER, sizeof(MC_AvgPower_Struct_t), (uint8_t*)&MC_AvgPower.GearSt_ECO);
  327. }
  328. }
  329. /*备份平均功耗值*/
  330. usPowerPerKmAverageLast = RemainDis.Power_per_km_average;
  331. }
  332. }
  333. /*助力档位切换后,根据当前档位更新功耗数据*/
  334. if((GearSt != MC_GearSt_Old) || (MC_AssistRunMode != MC_AssistRunMode_Old))
  335. {
  336. switch(GearSt)
  337. {
  338. case MC_GearSt_Torque_ECO:
  339. RemainDis.Power_per_km_average = MC_AvgPower.GearSt_ECO;
  340. powerDefaultCurrentMode = MC_AvgPower_Default.GearSt_ECO;
  341. break;
  342. case MC_GearSt_Torque_NORM:
  343. RemainDis.Power_per_km_average = MC_AvgPower.GearSt_NORM;
  344. powerDefaultCurrentMode = MC_AvgPower_Default.GearSt_NORM;
  345. break;
  346. case MC_GearSt_Torque_SPORT:
  347. RemainDis.Power_per_km_average = MC_AvgPower.GearSt_SPORT;
  348. powerDefaultCurrentMode = MC_AvgPower_Default.GearSt_SPORT;
  349. break;
  350. case MC_GearSt_Torque_TURBO:
  351. RemainDis.Power_per_km_average = MC_AvgPower.GearSt_TURBO;
  352. powerDefaultCurrentMode = MC_AvgPower_Default.GearSt_TURBO;
  353. break;
  354. case MC_GearSt_Torque_5:
  355. RemainDis.Power_per_km_average = MC_AvgPower.GearSt_5;
  356. powerDefaultCurrentMode = MC_AvgPower_Default.GearSt_5;
  357. break;
  358. case MC_GearSt_SMART:
  359. RemainDis.Power_per_km_average = MC_AvgPower.GearSt_SMART;
  360. powerDefaultCurrentMode = MC_AvgPower_Default.GearSt_SMART;
  361. break;
  362. case MC_GearSt_SMART_T:
  363. RemainDis.Power_per_km_average = MC_AvgPower.GearSt_SMART_T;
  364. powerDefaultCurrentMode = MC_AvgPower_Default.GearSt_SMART_T;
  365. break;
  366. default:
  367. RemainDis.Power_per_km_average = 0;
  368. powerDefaultCurrentMode = 0;
  369. break;
  370. }
  371. /*备份平均功耗值*/
  372. usPowerPerKmAverageLast = RemainDis.Power_per_km_average;
  373. RemainDis.Power_per_km_result = RemainDis.Power_per_km_average;
  374. /*计算剩余续航里程*/
  375. if(RemainDis.Power_per_km_average > 0)
  376. {
  377. RemainDis.remainDistance = Battery_Info.Q_remain_real / RemainDis.Power_per_km_result;//单位km
  378. }
  379. else
  380. {
  381. RemainDis.remainDistance = 0xFFFF;//码表界面显示:---km
  382. }
  383. /*置标志位,在后续计算中,刷新相关数据*/
  384. RemainDis.flag_helpModeChange = 1;
  385. }
  386. }
  387. else
  388. {
  389. RemainDis.start = 0;
  390. RemainDis.Power_per_km_average = 0;
  391. RemainDis.Power_per_km_result = 0;
  392. RemainDis.remainDistance = 0xFFFF;//码表界面显示:---km
  393. }
  394. /*备份助力档位*/
  395. MC_GearSt_Old = GearSt;
  396. MC_AssistRunMode_Old = MC_AssistRunMode;
  397. }
  398. //运行周期200ms
  399. uint8_t Battery_SocCal(uint16_t Voltage_mV)
  400. {
  401. static uint16_t TimeDelayCnt = 0;
  402. static uint32_t FiltSum = 0;
  403. static uint8_t FiltCnt = 0;
  404. static uint8_t Result = 0, Result_Pre=0;
  405. static TrueOrFalse_Flag_Struct_t InitFlag = FALSE;
  406. uint16_t i;
  407. uint16_t TableNum;
  408. uint32_t batteryTotalQ, batteryRemainQ;
  409. uint16_t Vol_Avg = 0;
  410. TableNum = sizeof(battery_VoltageQuantity) / 4;
  411. batteryTotalQ = battery_VoltageQuantity[TableNum - 1][1];
  412. batteryRemainQ = batteryTotalQ;
  413. TimeDelayCnt++;
  414. //初始化电压上升较慢,开机时动态效果
  415. if(TimeDelayCnt <= 10) return 0;
  416. else if(TimeDelayCnt <= 15) return 10;
  417. else if(TimeDelayCnt <= 20) return 25;
  418. else if(TimeDelayCnt <= 25) return 45;
  419. else if(TimeDelayCnt <= 30) return 65;
  420. else if(TimeDelayCnt <= 35) return 85;
  421. else
  422. {
  423. if(InitFlag == FALSE)//等待约5s后,计算一次初始值
  424. {
  425. InitFlag = TRUE;
  426. for(i=0; i<TableNum; i++)
  427. {
  428. if(battery_VoltageQuantity[i][0] <= (Voltage_mV / 10))
  429. {
  430. batteryRemainQ = batteryTotalQ - battery_VoltageQuantity[i][1];
  431. break;
  432. }
  433. else//电池电压低于最小值
  434. {
  435. batteryRemainQ = 0;
  436. }
  437. }
  438. Result = batteryRemainQ * 100 / batteryTotalQ;
  439. }
  440. else//第一次计算后,采用25组电压平均值
  441. {
  442. Result_Pre = MC_RunInfo.SOC;
  443. Result = Result_Pre;
  444. //取25组数据的平均值计算SOC
  445. FiltSum += Voltage_mV;
  446. FiltCnt++;
  447. if(FiltCnt >= 25)
  448. {
  449. Vol_Avg = FiltSum / 25;
  450. FiltSum = 0;
  451. FiltCnt = 0;
  452. //查表计算SOC
  453. for(i=0; i<TableNum; i++)
  454. {
  455. if(battery_VoltageQuantity[i][0] <= (Vol_Avg / 10))
  456. {
  457. batteryRemainQ = batteryTotalQ - battery_VoltageQuantity[i][1] ; //A*s
  458. break;
  459. }
  460. else//电池电压低于最小值
  461. {
  462. batteryRemainQ = 0;
  463. }
  464. }
  465. Result = batteryRemainQ * 100 / batteryTotalQ;
  466. if(Result > Result_Pre)//电量上升时,突变较小,取上次计算值
  467. {
  468. if((Result < (Result_Pre + 30)) && (Result < 90))
  469. {
  470. Result = Result_Pre;
  471. }
  472. }
  473. }
  474. }
  475. return Result;
  476. }
  477. }