123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372 |
- /* includes ----------------------------------------------------------*/
- #include "global.h"
- /* typedef -----------------------------------------------------------*/
- /* define ------------------------------------------------------------*/
- /* macro -------------------------------------------------------------*/
- /* variables ---------------------------------------------------------*/
- global_par s_global_par;
- /* function prototypes -----------------------------------------------*/
- // 定义指令周期数,用于实现1ms的延时
- // 假设时钟频率为72MHz,每个指令周期为1/72MHz = 13.889ns
- // 因此,1ms需要72000个指令周期
- #define INSTRUCTION_CYCLES_PER_MS 72000
- // 延时函数
- void global_delay_ms(uint32_t ms) {
- uint32_t i;
- uint32_t cycles = ms * INSTRUCTION_CYCLES_PER_MS; // 计算需要消耗的指令周期数
- // 消耗指令周期
- for (i = 0; i < cycles; ++i) {
- __NOP(); // 使用NOP指令来消耗一个指令周期
- }
- }
- /**
- * @brief 中控板初始化
- * @param p_param_boot : 参数区指针
- * @param p_rs485RecDate:485接收数据区的指针
- * @note NONE
- * @retval 无
- */
- void centralCtrSys_Init(param_boot *p_param_boot, global_par *p_global_par){
- uint8_t recBack = 0;
- rs485RecDate *p_rs485RecDate = &s_rs485RecDate;
- // 1. 从flash中读出VIN
- Read_ParamArea(); // 读出参数区的所有数据
- // 2. 与车通信获取vin数据(读取所有寄存器的值)
- modbus_read_holding_registers(0x01, 0x0000, 67);
- global_delay_ms(1000); // 延时3s
- // 3. vin码比对
- if(s_comData.vinRecSuccess == 1){ // 成功获取到车辆数据
- if(memcmp(p_param_boot->vin, p_rs485RecDate->VIN, 26) != 0){ // 比对不成功
- // 备份新的VIN码
- memcpy(p_param_boot->vin, p_rs485RecDate->VIN, 26);
- Write_paramArea();
- // 置位中控板迁移事件
- BIT_SET(p_global_par->ctrEvent, CtrlPanelMigration);
- }
- }
- // 4. 初始化4g模块 4g模块在这里不好处理 放在任务中,围栏数据也一样
- // 5. 读取96位(或者说是3个32位的字)的唯一ID
- GetUniqueID(s_messageDate.devId);
- // 6. 陀螺仪的初始化
- recBack = atk_ms6050_init();
- if(recBack != 0){
- // printf("ATK-MS6050 init failed!\r\n");
- BIT_SET(s_comData.Malfunction, gyroscope); // 置位陀螺仪数据异常故障
- }
- // printf("ATK-MS6050 init\r\n");
-
- recBack = atk_ms6050_dmp_init();
- if(recBack != 0){
- // printf("ATK-MS6050 DMP init failed!\r\n");
- BIT_SET(s_comData.Malfunction, gyroscope); // 置位陀螺仪数据异常故障
- }
- // printf("ATK-MS6050 DMP init!\r\n");
- // 7. 外部flash初始化
- norflash_init();
- }
- // 车本体故障判断
- void fault_car(rs485RecDate *p_rs485RecDate, comData *p_comData){
- uint16_t errorLevel = 0;
- /* 尝试获取互斥量,等待无限长时间 */
- if(osMutexAcquire(mutex_rs485RecDateHandle, 1000) == osOK)
- {
- errorLevel = p_rs485RecDate->alarmLevel;
- /* 访问完成,释放互斥量 */
- osMutexRelease(mutex_rs485RecDateHandle);
- }
- // 存在车故障
- if(errorLevel != 0){
- BIT_SET(s_comData.Malfunction, carError); // 置位车故障
- }else{
- BIT_CLEAR(s_comData.Malfunction, carError); // 清除车故障
- }
- }
- /**
- * @brief 中控板故障检测
- * @param p_global_par:global_par的全局参数指针
- * @note 周期为1s1次 清除除电池故障的其他故障
- * @retval 无
- */
- void faultDetection(global_par *p_global_par){
- // 参数定义
- static uint16_t timesCnt_gps = 0; // gps记时
- static uint8_t errorCnt_gyro = 0; // 陀螺仪数据故障滤波次数
- static uint16_t timesOut_ota = 0; // OTA超时计数
- static uint16_t timesCnt_runFence; // 超运行围栏计数
- static uint16_t timesCnt_outSpeed; // 超速计时器
- comData *p_comData = &s_comData;
- param_boot *p_param_boot = &s_param_boot;
- // 开启超级权限 不判断所有故障
- if(p_global_par->superUser == 1){
- p_comData->Malfunction = 0; // 清除所有故障
- return;
- }
- // 1. 车本体故障判断
- fault_car(&s_rs485RecDate, &s_comData); // 车故障判断
- // 2. 超出围栏故障判断
- if(p_comData->fenceStatus == 1){
- if(timesCnt_runFence < p_param_boot->fenceBreach_Timeout){
- timesCnt_runFence++;
- }else{
- timesCnt_runFence = p_param_boot->fenceBreach_Timeout;
- BIT_SET(s_comData.Malfunction, fence);
- }
- }else{
- timesCnt_runFence = 0;
- BIT_CLEAR(s_comData.Malfunction, fence);
- }
- // 3. GPS信号丢失
- // 获取gps失败,但陀螺仪数据正常的情况下,一分钟之后置位gps故障
- // 获取gps失败,陀螺仪数据异常,直接置位gps故障
- if((p_global_par->positionErrorCnt >= 3) && (BIT_CHECK(s_comData.Malfunction, fence) == 0)){
- if(timesCnt_gps < FILTER_TIME_GPS){ // 4分钟滤波时间
- timesCnt_gps++;
- }else{
- timesCnt_gps = FILTER_TIME_GPS;
- BIT_SET(s_comData.Malfunction, positionError);
- }
- }else if((p_global_par->positionErrorCnt >= 3) && (BIT_CHECK(s_comData.Malfunction, fence) == 1)){
- timesCnt_gps = 0;
- BIT_SET(s_comData.Malfunction, positionError);
- }else{
- timesCnt_gps = 0;
- }
- if(p_global_par->positionErrorCnt == 0){ // 清除gps故障
- BIT_CLEAR(s_comData.Malfunction, positionError);
- }
- // 4. MQTT通信异常
- if(p_global_par->mqttTimeoutCnt >= PUBLISH_TIME_MS){
- BIT_SET(s_comData.Malfunction, errorMqtt); // 置位MQTT故障
- }
- if(p_global_par->mqttTimeoutCnt == 0){ // 清除MQTT故障
- BIT_CLEAR(s_comData.Malfunction, errorMqtt);
- }
- // 5. 4G模块初始化故障
- if(p_global_par->InitFaultFlag_4G == 1){
- BIT_SET(s_comData.Malfunction, init_4G_error); // 置位4g模块初始化故障
- }else{
- BIT_CLEAR(s_comData.Malfunction, init_4G_error); // 清除4g模块初始化故障
- }
- // 6. 485通信故障
- if(p_global_par->timeoutCnt_485 >= TIMEOUT_485){
- BIT_SET(s_comData.Malfunction, com485); // 置位485通信故障
- }
- if(p_global_par->timeoutCnt_485 == 0){
- BIT_CLEAR(s_comData.Malfunction, com485); // 置位485通信故障
- }
- // 7. 陀螺仪数据故障-- 获取的姿态角数据全部为0
- if(p_global_par->gyroDataFaultFlag == 1){
- if(errorCnt_gyro < FILTER_TIME_gyro){
- errorCnt_gyro++;
- }else{
- errorCnt_gyro = FILTER_TIME_gyro;
- BIT_SET(s_comData.Malfunction, gyroscope); // 置位陀螺仪数据异常故障
- }
- }else{
- errorCnt_gyro = 0;
- BIT_CLEAR(s_comData.Malfunction, gyroscope);
- }
- // 8. 超速故障
- if(s_rs485RecDate.vehicleSpeed > s_param_boot.speed_limit){
- if(timesCnt_outSpeed < s_param_boot.overspeed_Timeout){
- timesCnt_outSpeed++;
- }else{
- timesCnt_outSpeed = s_param_boot.overspeed_Timeout;
- BIT_SET(s_comData.Malfunction, outSpeed); // 置位超速故障
- }
- }else{
- timesCnt_outSpeed = 0;
- BIT_CLEAR(s_comData.Malfunction, outSpeed); // 清零超速故障
- }
- // 9. 升级故障--开始升级后,开始记时,2分钟还未升级成功的话,置位升级故障,
- // 退出升级,此次升级失败,旧版本运行,清除升级状态变量、标志、数据,重启释放
- // OTA开始后任务周期为200ms
- if(p_global_par->otaUpgradeStartFlag == 1){
- if(timesOut_ota < TIME_OUT_OTA){
- timesOut_ota++;
- }else{
- timesOut_ota = TIME_OUT_OTA;
- BIT_SET(s_comData.Malfunction, OTA_fault); // 置位OTA异常故障
- }
- }
- }
- /**
- * @brief 控制蜂鸣器响停
- * @param count 当前计数
- * @param on_threshold 响的阈值
- * @param off_threshold 停的阈值
- * @retval 无
- */
- void beep_control(uint8_t count, uint8_t on_threshold, uint8_t off_threshold) {
- if (count < on_threshold) {
- GPIO_BEEP(GPIO_PIN_SET);
- } else if (count < off_threshold) {
- GPIO_BEEP(GPIO_PIN_RESET);
- }
- }
- /**
- * @brief 控制蜂鸣器响应
- * @note 根据不同条件控制蜂鸣器的响停 进入周期为100ms
- * @param 无
- * @retval 无
- */
- void control_beep_response(void) {
- global_par *p_global_par = &s_global_par;
- // 蜂鸣器计数器
- static uint8_t beep_count_fence = 0;
- // static uint8_t beep_count_fault = 0;
- static uint8_t beep_count_ota = 0;
- // 超出围栏 500ms频率响应
- if (BIT_CHECK(s_comData.Malfunction, fence)) {
- beep_control(beep_count_fence, 5, 10);
- beep_count_fence = (beep_count_fence >= 10) ? 0 : beep_count_fence + 1;
- }
- // OTA升级 2s的响应频率
- else if (p_global_par->otaUpgradeStartFlag == 1) {
- beep_control(beep_count_ota, 20, 40);
- beep_count_ota = (beep_count_ota >= 40) ? 0 : beep_count_ota + 1;
- }
- // 不存在蜂鸣器响应,蜂鸣器应关闭
- else{
- GPIO_BEEP(GPIO_PIN_RESET);
- }
- }
- // 格式转换函数
- void formatDateTimeAndMalfunction(uint16_t year, uint8_t month, uint8_t day,
- uint8_t hour, uint8_t minute, uint8_t sec,
- uint32_t malfunction, char *output) {
- // 确保提供的output数组足够大
- // 格式化字符串为 YYYYMMDD-HHMM:0xXXXXXXXX 格式
- sprintf(output, "%04u%02u%02u-%02u%02u%02u:0x%08X,",
- year, month, day, hour, minute, sec, malfunction);
- output[29] = '\0'; // 确保字符串以空字符结尾
- }
- /**
- * @brief 历史故障存储
- * @note 此函数1s1次
- * @param 无
- * @retval 无
- */
- void storeFaultRecord(void) {
- uint16_t id = 0;
- char storeFaultData[30] = {0};
- static uint32_t fault_log = 0; // 用来同当前故障数据对比,看是否产生故障变化
- static uint16_t timeCnt_delay = 0; // 存在故障
-
- id = norflash_read_id(); /* 读取FLASH ID */
- if((id == 0) || (id == 0XFFFF)) { // 检测不到FLASH芯片
- return;
- }
- // 检查是否存在故障
- if (s_comData.Malfunction == 0) {
- return; // 如果没有故障,直接返回
- }
- // 检查是否产生故障变化或者到达计时时间
- if((fault_log == s_comData.Malfunction) && (timeCnt_delay < FAULT_RECORD_TIME)){
- timeCnt_delay++;
- return; // 如果没有故障变化或者未到达计时时间,直接返回
- }else{
- // 更新计数值和故障log
- timeCnt_delay = 0;
- fault_log = s_comData.Malfunction;
- }
- // 存储格式转换成 这样的20240513-172203:0x0000000f,字符串数据
- formatDateTimeAndMalfunction(s_nmea_utc_time.year,s_nmea_utc_time.month,s_nmea_utc_time.date,
- s_nmea_utc_time.hour,s_nmea_utc_time.min,s_nmea_utc_time.sec,s_comData.Malfunction, storeFaultData);
- // 写入数据
- norflash_write((uint8_t *)storeFaultData, s_param_boot.nextFaultAddr, strlen(storeFaultData));
- // 更新索引
- s_param_boot.faultRecordIndex = (s_param_boot.faultRecordIndex < MAX_RECORDS) ? (s_param_boot.faultRecordIndex + 1) : 0 ;
- // 更新地址
- s_param_boot.nextFaultAddr += strlen(storeFaultData);
- if(s_param_boot.faultRecordIndex == 0){
- s_param_boot.nextFaultAddr = 0;
- }
- // 保存最新的索引和地址数据
- Write_paramArea();
- }
- /**
- * @brief 更新保存的时间信息
- * @note 此函数1s1次
- * @param 无
- * @retval 无
- */
- void refreshSavedTime(void){
- static uint8_t timesCnt = 0;
- // 未获取到时间数据,则不保存
- if(s_global_par.time_stamp_flag != 1){
- return;
- }
- s_param_boot.year = s_nmea_utc_time.year;
- s_param_boot.month = s_nmea_utc_time.month;
- s_param_boot.date = s_nmea_utc_time.date;
- s_param_boot.hour = s_nmea_utc_time.hour;
- s_param_boot.min = s_nmea_utc_time.min;
- s_param_boot.sec = s_nmea_utc_time.sec;
- // 10s保存一次时间数据,发生故障时保存一次,固件更新时保存一次
- if(timesCnt < times_10s){
- timesCnt++;
- }else{
- timesCnt = 0;
- Write_paramArea();
- }
- }
|