global(2009).c 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. /* includes ----------------------------------------------------------*/
  2. #include "global.h"
  3. /* typedef -----------------------------------------------------------*/
  4. /* define ------------------------------------------------------------*/
  5. /* macro -------------------------------------------------------------*/
  6. /* variables ---------------------------------------------------------*/
  7. global_par s_global_par;
  8. /* function prototypes -----------------------------------------------*/
  9. // 定义指令周期数,用于实现1ms的延时
  10. // 假设时钟频率为72MHz,每个指令周期为1/72MHz = 13.889ns
  11. // 因此,1ms需要72000个指令周期
  12. #define INSTRUCTION_CYCLES_PER_MS 72000
  13. // 延时函数
  14. void global_delay_ms(uint32_t ms) {
  15. uint32_t i;
  16. uint32_t cycles = ms * INSTRUCTION_CYCLES_PER_MS; // 计算需要消耗的指令周期数
  17. // 消耗指令周期
  18. for (i = 0; i < cycles; ++i) {
  19. __NOP(); // 使用NOP指令来消耗一个指令周期
  20. }
  21. }
  22. /**
  23. * @brief 中控板初始化
  24. * @param p_param_boot : 参数区指针
  25. * @param p_rs485RecDate:485接收数据区的指针
  26. * @note NONE
  27. * @retval 无
  28. */
  29. void centralCtrSys_Init(param_boot *p_param_boot, global_par *p_global_par){
  30. uint8_t recBack = 0;
  31. rs485RecDate *p_rs485RecDate = &s_rs485RecDate;
  32. // 1. 从flash中读出VIN
  33. Read_ParamArea(); // 读出参数区的所有数据
  34. // 2. 与车通信获取vin数据(读取所有寄存器的值)
  35. modbus_read_holding_registers(0x01, 0x0000, 67);
  36. global_delay_ms(1000); // 延时3s
  37. // 3. vin码比对
  38. if(s_comData.vinRecSuccess == 1){ // 成功获取到车辆数据
  39. if(memcmp(p_param_boot->vin, p_rs485RecDate->VIN, 26) != 0){ // 比对不成功
  40. // 备份新的VIN码
  41. memcpy(p_param_boot->vin, p_rs485RecDate->VIN, 26);
  42. Write_paramArea();
  43. // 置位中控板迁移事件
  44. BIT_SET(p_global_par->ctrEvent, CtrlPanelMigration);
  45. }
  46. }
  47. // 4. 初始化4g模块 4g模块在这里不好处理 放在任务中,围栏数据也一样
  48. // 5. 读取96位(或者说是3个32位的字)的唯一ID
  49. GetUniqueID(s_messageDate.devId);
  50. // 6. 陀螺仪的初始化
  51. recBack = atk_ms6050_init();
  52. if(recBack != 0){
  53. printf("ATK-MS6050 init failed!\r\n");
  54. BIT_SET(s_comData.Malfunction, gyroscope); // 置位陀螺仪数据异常故障
  55. }
  56. printf("ATK-MS6050 init\r\n");
  57. recBack = atk_ms6050_dmp_init();
  58. if(recBack != 0){
  59. printf("ATK-MS6050 DMP init failed!\r\n");
  60. BIT_SET(s_comData.Malfunction, gyroscope); // 置位陀螺仪数据异常故障
  61. }
  62. printf("ATK-MS6050 DMP init!\r\n");
  63. // 7. 外部flash初始化
  64. norflash_init();
  65. }
  66. // 电池故障判断
  67. void fault_bat(rs485RecDate *p_rs485RecDate, comData *p_comData){
  68. uint16_t errorLevel = 0;
  69. /* 尝试获取互斥量,等待无限长时间 */
  70. if(osMutexAcquire(mutex_rs485RecDateHandle, osWaitForever) == osOK)
  71. {
  72. errorLevel = p_rs485RecDate->alarmLevel;
  73. /* 访问完成,释放互斥量 */
  74. osMutexRelease(mutex_rs485RecDateHandle);
  75. }
  76. // 存在电池故障
  77. if(errorLevel != 0){
  78. BIT_SET(s_comData.Malfunction, batError); // 置位电池故障
  79. }else{
  80. BIT_CLEAR(s_comData.Malfunction, batError); // 清除电池故障
  81. }
  82. }
  83. /**
  84. * @brief 中控板故障检测
  85. * @param p_global_par:global_par的全局参数指针
  86. * @note 周期为1s1次 清除除电池故障的其他故障
  87. * @retval 无
  88. */
  89. void faultDetection(global_par *p_global_par){
  90. // 参数定义
  91. static uint8_t timesCnt_gps = 0; // gps记时
  92. static uint8_t errorCnt_gyro = 0; // 陀螺仪数据故障滤波次数
  93. static uint16_t timesOut_ota = 0; // OTA超时计数
  94. comData *p_comData = &s_comData;
  95. // 开启超级权限 不判断所有故障
  96. if(p_global_par->superUser == 1){
  97. s_comData.Malfunction = 0; // 清除所有故障
  98. return;
  99. }
  100. // 1. 电池故障判断
  101. fault_bat(&s_rs485RecDate, &s_comData); // 电池故障判断
  102. // 2. 超出围栏故障判断
  103. if(p_comData->fenceStatus == 1){
  104. BIT_SET(s_comData.Malfunction, fence);
  105. }else{
  106. BIT_CLEAR(s_comData.Malfunction, fence);
  107. }
  108. // 3. GPS信号丢失
  109. // 获取gps失败,但陀螺仪数据正常的情况下,一分钟之后置位gps故障
  110. // 获取gps失败,陀螺仪数据异常,直接置位gps故障
  111. if((p_global_par->positionErrorCnt >= 3) && (BIT_CHECK(s_comData.Malfunction, fence) == 0)){
  112. if(timesCnt_gps < 240){ // 4分钟滤波时间
  113. timesCnt_gps++;
  114. }else{
  115. timesCnt_gps = 240;
  116. BIT_SET(s_comData.Malfunction, positionError);
  117. }
  118. }else if((p_global_par->positionErrorCnt >= 3) && (BIT_CHECK(s_comData.Malfunction, fence) == 1)){
  119. timesCnt_gps = 0;
  120. BIT_SET(s_comData.Malfunction, positionError);
  121. }else{
  122. timesCnt_gps = 0;
  123. }
  124. if(p_global_par->positionErrorCnt == 0){ // 清除gps故障
  125. BIT_CLEAR(s_comData.Malfunction, positionError);
  126. }
  127. // 4. MQTT通信异常
  128. if(p_global_par->mqttTimeoutCnt >= PUBLISH_TIME_MS){
  129. BIT_SET(s_comData.Malfunction, errorMqtt); // 置位MQTT故障
  130. }
  131. if(p_global_par->mqttTimeoutCnt == 0){ // 清除MQTT故障
  132. BIT_CLEAR(s_comData.Malfunction, errorMqtt);
  133. }
  134. // 5. 4G模块初始化故障
  135. if(p_global_par->InitFaultFlag_4G == 1){
  136. BIT_SET(s_comData.Malfunction, init_4G_error); // 置位4g模块初始化故障
  137. }else{
  138. BIT_CLEAR(s_comData.Malfunction, init_4G_error); // 清除4g模块初始化故障
  139. }
  140. // 6. 485通信故障
  141. if(p_global_par->timeoutCnt_485 >= TIMEOUT_485){
  142. BIT_SET(s_comData.Malfunction, com485); // 置位485通信故障
  143. }
  144. if(p_global_par->timeoutCnt_485 == 0){
  145. BIT_CLEAR(s_comData.Malfunction, com485); // 置位485通信故障
  146. }
  147. // 7. 陀螺仪数据故障-- 获取的姿态角数据全部为0
  148. if(p_global_par->gyroDataFaultFlag == 1){
  149. if(errorCnt_gyro < FILTER_TIME_gyro){
  150. errorCnt_gyro++;
  151. }else{
  152. errorCnt_gyro = FILTER_TIME_gyro;
  153. BIT_SET(s_comData.Malfunction, gyroscope); // 置位陀螺仪数据异常故障
  154. }
  155. }else{
  156. errorCnt_gyro = 0;
  157. BIT_CLEAR(s_comData.Malfunction, gyroscope);
  158. }
  159. // 8. 升级故障--开始升级后,开始记时,2分钟还未升级成功的话,置位升级故障,
  160. // 退出升级,此次升级失败,旧版本运行,清除升级状态变量、标志、数据,重启释放
  161. if(p_global_par->otaUpgradeStartFlag == 1){
  162. if(timesOut_ota < TIME_OUT_OTA){
  163. timesOut_ota++;
  164. }else{
  165. timesOut_ota = TIME_OUT_OTA;
  166. BIT_SET(s_comData.Malfunction, OTA_fault); // 置位OTA异常故障
  167. }
  168. }
  169. }
  170. /**
  171. * @brief 控制蜂鸣器响停
  172. * @param count 当前计数
  173. * @param on_threshold 响的阈值
  174. * @param off_threshold 停的阈值
  175. * @retval 无
  176. */
  177. void beep_control(uint8_t count, uint8_t on_threshold, uint8_t off_threshold) {
  178. if (count < on_threshold) {
  179. GPIO_BEEP(GPIO_PIN_SET);
  180. } else if (count < off_threshold) {
  181. GPIO_BEEP(GPIO_PIN_RESET);
  182. }
  183. }
  184. /**
  185. * @brief 控制蜂鸣器响应
  186. * @note 根据不同条件控制蜂鸣器的响停 进入周期为100ms
  187. * @param 无
  188. * @retval 无
  189. */
  190. void control_beep_response(void) {
  191. comData *p_comData = &s_comData;
  192. global_par *p_global_par = &s_global_par;
  193. // 蜂鸣器计数器
  194. static uint8_t beep_count_fence = 0;
  195. // static uint8_t beep_count_fault = 0;
  196. static uint8_t beep_count_ota = 0;
  197. // 超出围栏 500ms频率响应
  198. if (p_comData->fenceStatus == 1) {
  199. beep_control(beep_count_fence, 5, 10);
  200. beep_count_fence = (beep_count_fence >= 10) ? 0 : beep_count_fence + 1;
  201. }
  202. // 运行中限制车速的故障 1s的频率响应
  203. // else if ((BIT_CHECK(s_comData.Malfunction, fence))
  204. // || (BIT_CHECK(s_comData.Malfunction, batError))
  205. // || (BIT_CHECK(s_comData.Malfunction, positionError))){
  206. // beep_control(beep_count_fault, 10, 20);
  207. // beep_count_fault = (beep_count_fault >= 20) ? 0 : beep_count_fault + 1;
  208. // }
  209. // OTA升级 2s的响应频率
  210. else if (p_global_par->otaUpgradeStartFlag == 1) {
  211. beep_control(beep_count_ota, 20, 40);
  212. beep_count_ota = (beep_count_ota >= 40) ? 0 : beep_count_ota + 1;
  213. }
  214. // 不存在蜂鸣器响应,蜂鸣器应关闭
  215. else{
  216. GPIO_BEEP(GPIO_PIN_RESET);
  217. }
  218. }
  219. void formatDateTimeAndMalfunction(uint16_t year, uint8_t month, uint8_t day,
  220. uint8_t hour, uint8_t minute, uint8_t sec,
  221. uint32_t malfunction, char *output) {
  222. // 确保提供的output数组足够大
  223. // 格式化字符串为 YYYYMMDD-HHMM:0xXXXXXXXX 格式
  224. sprintf(output, "%04u%02u%02u-%02u%02u:0x%08X",
  225. year, month, day, hour, minute, malfunction);
  226. // 添加逗号和空格
  227. output[26] = ',';
  228. output[27] = '\0'; // 确保字符串以空字符结尾
  229. }
  230. /**
  231. * @brief 历史故障存储
  232. * @note none
  233. * @param 无
  234. * @retval 无
  235. */
  236. uint32_t recordIndex = 0; // 下一个记录的索引
  237. uint32_t nextAddress = 0; // 下一个记录的地址
  238. void storeFaultRecord(void) {
  239. uint16_t id = 0;
  240. char storeFaultData[30] = {0};
  241. id = norflash_read_id(); /* 读取FLASH ID */
  242. if((id == 0) || (id == 0XFFFF)) { // 检测不到FLASH芯片
  243. return;
  244. }
  245. // 存储格式转换成 这样的20240513-1722:0x0000000f,字符串数据
  246. formatDateTimeAndMalfunction(s_nmea_utc_time.year,s_nmea_utc_time.month,s_nmea_utc_time.date,
  247. s_nmea_utc_time.hour,s_nmea_utc_time.min,s_nmea_utc_time.sec,s_comData.Malfunction, storeFaultData);
  248. // 写入数据
  249. norflash_write(storeFaultData, nextAddress, strlen(storeFaultData));
  250. // 更新索引
  251. recordIndex = (recordIndex + 1) % MAX_RECORDS;
  252. // 更新地址
  253. nextAddress += strlen(storeFaultData);
  254. }