/* USER CODE BEGIN Header */ /** ****************************************************************************** * File Name : freertos.c * Description : Code for freertos applications ****************************************************************************** * @attention * * Copyright (c) 2024 STMicroelectronics. * All rights reserved. * * This software is licensed under terms that can be found in the LICENSE file * in the root directory of this software component. * If no LICENSE file comes with this software, it is provided AS-IS. * ****************************************************************************** */ /* USER CODE END Header */ /* Includes ------------------------------------------------------------------*/ #include "FreeRTOS.h" #include "task.h" #include "main.h" #include "cmsis_os.h" /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ #include "semphr.h" #include "i2c.h" #include "can.h" #include "usart.h" #include "gpio.h" #include "rtc.h" #include "iwdg.h" /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ /* USER CODE BEGIN PTD */ /* USER CODE END PTD */ /* Private define ------------------------------------------------------------*/ /* USER CODE BEGIN PD */ #define MAX_RETRY_COUNT 3 #define ROWS 24 // 温度点矩阵的行数 #define COLS 32 // 温度点矩阵的列数 #define MAX_CAN_MSG_LEN 8 #define NUM_TEMP_DATA 18 // 9 个温度点,每个点两条数据 volatile uint8_t Ambient_temperature; volatile uint8_t systemlevel = 0; volatile uint8_t dataReadyFlag = 0;// 标志位或状态 uint8_t canMsgBuffer1[MAX_CAN_MSG_LEN] = {0}; // 第一个 CAN 消息缓冲区 uint8_t canMsgBuffer2[MAX_CAN_MSG_LEN] = {0}; // 第二个 CAN 消息缓冲区 uint8_t summaryBuffer[MAX_CAN_MSG_LEN] = {0}; // 存放最大值、最小值和平均值的缓冲区 uint8_t canMsgBuffer1_tmp[MAX_CAN_MSG_LEN] = {0}; // 第一个 CAN 消息缓冲区 uint8_t canMsgBuffer2_tmp[MAX_CAN_MSG_LEN] = {0}; // 第二个 CAN 消息缓冲区 uint8_t summaryBuffer_tmp[MAX_CAN_MSG_LEN] = {0}; // 存放最大值、最小值和平均值的缓冲区 uint8_t debugBuffer1_tmp[MAX_CAN_MSG_LEN] = {0}; // 包含预警等级加温度的全部数据缓冲区 uint8_t debugBuffer2_tmp[MAX_CAN_MSG_LEN] = {0}; // 包含预警等级加温度的全部数据缓冲区 #define DATA_MOVING (0) #define DATA_READY (1) #define STOP2_READY (2) uint8_t data_Flag = DATA_MOVING; volatile bool taskEnabled = true; // 任务状态,初始为启动状态 /** * @breaf 内部flash参数定义 */ #define FLASH_LAST_PAGE_ADDR 0x0801FC00 // STM32L431CCT6 内部Flash第127页起始地址 #define FLASH_SECOND_LAST_PAGE_ADDR 0x08018800 // STM32L431CCT6 内部Flash第126页起始地址 uint16_t NODE_ID; // 初始节点ID 01 //温度传感器ID从 16 开始,16 代表 01 号小板 FlashData flash_data = { .first_threshold = 60, // 一级阈值 60 .second_threshold = 100, // 二级阈值 100 .delay_receivedValue = 1, // 初始上报频率 2s .Emissivity = 95, // 初始发射率 0.95(后续除100) }; extern uint16_t eeMLX90640[832]; extern int status; bool MLX_powered = false; int failCount = 0; // 新增失败计数器 extern uint32_t start_tick; uint32_t end_tick = 0; /* USER CODE END PD */ /* Private macro -------------------------------------------------------------*/ /* USER CODE BEGIN PM */ volatile uint8_t stop2WakeupFlag = 0;// STOP2 唤醒标志 void Configure_GPIOs_For_LowPower(void); void Enter_LPStop2Mode(void); void Wakeup_LPStop2Mode(void); void Enable_RTC_Wakeup(uint16_t delay_time); void control_MLX90640_power(bool enable) ; void printCurrentRTCTime(void); /* USER CODE END PM */ /* Private variables ---------------------------------------------------------*/ /* USER CODE BEGIN Variables */ extern paramsMLX90640 mlx90640; extern float mlx90640To[768]; extern uint16_t frame[834]; extern uint16_t blockNumber; /* USER CODE END Variables */ /* Definitions for readTempTask */ osThreadId_t readTempTaskHandle; const osThreadAttr_t readTempTask_attributes = { .name = "readTempTask", .stack_size = 256 * 4, .priority = (osPriority_t) osPriorityNormal, }; /* Definitions for sendTempTask */ osThreadId_t sendTempTaskHandle; const osThreadAttr_t sendTempTask_attributes = { .name = "sendTempTask", .stack_size = 256 * 4, .priority = (osPriority_t) osPriorityHigh, }; /* Definitions for Common */ osThreadId_t CommonHandle; const osThreadAttr_t Common_attributes = { .name = "Common", .stack_size = 128 * 4, .priority = (osPriority_t) osPriorityRealtime, }; /* Definitions for dataMutex */ osMutexId_t dataMutexHandle; const osMutexAttr_t dataMutex_attributes = { .name = "dataMutex" }; /* Definitions for dataReadySem */ osSemaphoreId_t dataReadySemHandle; const osSemaphoreAttr_t dataReadySem_attributes = { .name = "dataReadySem" }; /* Private function prototypes -----------------------------------------------*/ /* USER CODE BEGIN FunctionPrototypes */ void lowpower_wakeup(void); void lowpower_sleep(void); void CAN_ErrorHandler(TickType_t *pxPreviousWakeTime, uint32_t *send_interval); void CAN_TemperatureSend(uint8_t *sequence, uint32_t *send_interval); int MLX90640_ReadFrameData(void); int ProcessTemperatureData(void); void Read_NODE_ID_From_Flash(void); void Read_parameter_From_Flash(void); void Save_NODEID_To_Flash(uint8_t NODE_ID) ; void Save_parameter_To_Flash(uint8_t first_threshold ,uint8_t second_threshold ,uint8_t delay_receivedValue ,uint8_t Emissivity); void CAN_Send_Msg(uint8_t *msg,uint8_t len,uint32_t node_id, uint8_t sequence, uint8_t slice_num, uint8_t slice_id); void CAN_Send_extId(uint16_t *data, uint8_t len, uint32_t node_id, uint8_t sequence, uint8_t slice_num, uint8_t slice_id); void CAN_Send_Parameter(uint32_t node_id, uint8_t len, FlashData *flash_data, uint8_t sequence, uint8_t slice_num, uint8_t slice_id) ; /* USER CODE END FunctionPrototypes */ void ReadTemperatureTask(void *argument); void SendTemperatureTask(void *argument); void CommonTask(void *argument); void MX_FREERTOS_Init(void); /* (MISRA C 2004 rule 8.1) */ /** * @brief FreeRTOS initialization * @param None * @retval None */ void MX_FREERTOS_Init(void) { /* USER CODE BEGIN Init */ Read_parameter_From_Flash(); Read_NODE_ID_From_Flash(); /* USER CODE END Init */ /* Create the mutex(es) */ /* creation of dataMutex */ dataMutexHandle = osMutexNew(&dataMutex_attributes); /* USER CODE BEGIN RTOS_MUTEX */ /* add mutexes, ... */ /* USER CODE END RTOS_MUTEX */ /* Create the semaphores(s) */ /* creation of dataReadySem */ dataReadySemHandle = osSemaphoreNew(1, 1, &dataReadySem_attributes); /* USER CODE BEGIN RTOS_SEMAPHORES */ /* add semaphores, ... */ /* USER CODE END RTOS_SEMAPHORES */ /* USER CODE BEGIN RTOS_TIMERS */ /* start timers, add new ones, ... */ /* USER CODE END RTOS_TIMERS */ /* USER CODE BEGIN RTOS_QUEUES */ /* add queues, ... */ /* USER CODE END RTOS_QUEUES */ /* Create the thread(s) */ /* creation of readTempTask */ readTempTaskHandle = osThreadNew(ReadTemperatureTask, NULL, &readTempTask_attributes); /* creation of sendTempTask */ sendTempTaskHandle = osThreadNew(SendTemperatureTask, NULL, &sendTempTask_attributes); /* creation of Common */ CommonHandle = osThreadNew(CommonTask, NULL, &Common_attributes); /* USER CODE BEGIN RTOS_THREADS */ /* add threads, ... */ /* USER CODE END RTOS_THREADS */ /* USER CODE BEGIN RTOS_EVENTS */ /* add events, ... */ /* USER CODE END RTOS_EVENTS */ } /* USER CODE BEGIN Header_ReadTemperatureTask */ /** * @brief Function implementing the readTempTask thread. * @param argument: Not used * @retval None */ /* USER CODE END Header_ReadTemperatureTask */ void ReadTemperatureTask(void *argument) { /* USER CODE BEGIN ReadTemperatureTask */ TickType_t pxPreviousWakeTime = xTaskGetTickCount(); uint8_t sequence =0; uint32_t send_interval = 0; for(;;) { // 读取并校验有效帧 if (MLX90640_ReadFrameData()) { // control_MLX90640_power(false); int validData = ProcessTemperatureData(); if (validData == 1) { // 1. CAN 错误处理 CAN_ErrorHandler(&pxPreviousWakeTime, &send_interval); // 如果仍然处于 Bus-Off 等待状态,就跳过发送流程 if (hcan1.Instance->ESR & CAN_ESR_BOFF) { continue; } CAN_TemperatureSend(&sequence, &send_interval); send_interval++; Enter_LPStop2Mode(); } } osDelay(10); } /* USER CODE END ReadTemperatureTask */ } /* USER CODE BEGIN Header_SendTemperatureTask */ /** * @brief Function implementing the sendTempTask thread. * @param argument: Not used * @retval None */ /* USER CODE END Header_SendTemperatureTask */ void SendTemperatureTask(void *argument) { /* USER CODE BEGIN SendTemperatureTask */ // TickType_t pxPreviousWakeTime = xTaskGetTickCount(); // // uint8_t sequence =0; // uint32_t send_interval = 0; for (;;) { // // 1. CAN 错误处理 // CAN_ErrorHandler(&pxPreviousWakeTime, &send_interval); // // 如果仍然处于 Bus-Off 等待状态,就跳过发送流程 // if (hcan1.Instance->ESR & CAN_ESR_BOFF) // { // continue; // } osDelay( 100 ); } /* USER CODE END SendTemperatureTask */ } /* USER CODE BEGIN Header_CommonTask */ /** * @brief Function implementing the Common thread. * @param argument: Not used * @retval None */ /* USER CODE END Header_CommonTask */ void CommonTask(void *argument) { /* USER CODE BEGIN CommonTask */ /* Infinite loop */ // uint16_t counter = 0; // LED 闪烁计数器 // uint16_t led_flash_threshold = 50; // 默认慢闪 for(;;) { osDelay(10); // counter++; // // 1. 获取当前 CAN 错误状态 // uint32_t can_esr = hcan1.Instance->ESR; // uint8_t tec = (can_esr >> 16) & 0xFF; // uint8_t rec = (can_esr >> 24) & 0xFF; // // 2. 判断当前状态并设置 LED 闪烁速度 // if (can_esr & CAN_ESR_BOFF) // { // // Bus-Off 快闪 50ms (10ms * 5) // led_flash_threshold = 5; // } // else if (tec >= 128 || rec >= 128) // { // // Error Passive 中闪 200ms (10ms * 20) // led_flash_threshold = 20; // } // else // { // // 正常 慢闪 500ms (10ms * 50) // led_flash_threshold = 50; // } // // 3. 按照不同状态执行 LED 闪烁 // if (counter >= led_flash_threshold) // { // HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_4); // 切换 LED 状态 // counter = 0; // 重置计数器 // } // // 4. 喂狗 // HAL_IWDG_Refresh(&hiwdg); } /* USER CODE END CommonTask */ } /* Private application code --------------------------------------------------*/ /* USER CODE BEGIN Application */ void lowpower_wakeup(void) { DEBUG_PRINTF("1\r\n"); HAL_I2C_DeInit(&hi2c1); MX_I2C1_Init(); HAL_GPIO_WritePin(GPIOA, GPIO_PIN_9|GPIO_PIN_10, GPIO_PIN_SET); control_MLX90640_power(true); HAL_Delay(50); MLX90640_SetRefreshRate(MLX90640_ADDR, RefreshRate8HZ); // 设置帧率�??0-7对应0.5,1,2,4,8,16,32,64HZ�?? status = MLX90640_DumpEE(MLX90640_ADDR, eeMLX90640); // 读取像素校正参数 status = MLX90640_ExtractParameters(eeMLX90640, &mlx90640); // 解析校正参数 } void lowpower_sleep(void) { control_MLX90640_power(false); Configure_GPIOs_For_LowPower(); HAL_GPIO_WritePin(GPIOA, GPIO_PIN_9|GPIO_PIN_10, GPIO_PIN_RESET); } // CAN 错误状态处理函数 void CAN_ErrorHandler(TickType_t *pxPreviousWakeTime, uint32_t *send_interval) { static uint32_t last_busoff_time = 0; // 上次 Bus-Off 恢复时间 static uint8_t bus_off_flag = 0; // Bus-Off 状态标志 uint32_t can_esr = hcan1.Instance->ESR; uint8_t tec = (can_esr >> 16) & 0xFF; uint8_t rec = (can_esr >> 24) & 0xFF; // 1. Bus-Off 状态处理 if (can_esr & CAN_ESR_BOFF) { if (bus_off_flag == 0) { DEBUG_PRINTF(" [CAN ERROR] Bus-Off detected! TEC = %d, REC = %d\n", tec, rec); bus_off_flag = 1; last_busoff_time = HAL_GetTick(); } // 等待1秒后重启 CAN if (HAL_GetTick() - last_busoff_time > 1000) { DEBUG_PRINTF("[CAN] Restarting CAN after Bus-Off...\n"); HAL_CAN_Stop(&hcan1); HAL_CAN_DeInit(&hcan1); MX_CAN1_Init(); HAL_CAN_Start(&hcan1); // 激活中断 HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING | CAN_IT_BUSOFF); DEBUG_PRINTF("[CAN] CAN restarted after Bus-Off\n"); bus_off_flag = 0; } // 跳过本次发送,等待恢复 vTaskDelayUntil(pxPreviousWakeTime, pdMS_TO_TICKS(10)); (*send_interval)++; } } // CAN 温度数据发送函数 void CAN_TemperatureSend(uint8_t *sequence, uint32_t *send_interval) { // if (*send_interval >= 100 * flash_data.delay_receivedValue) // { CAN_Send_Msg(canMsgBuffer1, 8, NODE_ID, *sequence, 2, 1); CAN_Send_Msg(canMsgBuffer2, 8, NODE_ID, *sequence, 2, 2); control_MLX90640_power(false); (*sequence)++; if (*sequence > 0xFF) { *sequence = 0; } *send_interval = 0; // DEBUG_PRINTF("Send Temperature Data - Sequence: %d\n", *sequence); // printCurrentRTCTime(); // } } // MLX90640读取温度函数 int MLX90640_ReadFrameData(void) { int validFrame = 0; while (!validFrame) { DEBUG_PRINTF("[MLX] Start reading frame data\r\n"); // control_MLX90640_power(true); int status = MLX90640_GetFrameData(MLX90640_ADDR, frame); if (status < 0) { DEBUG_PRINTF("[MLX] Failed to get frame data, status=%d, retrying...\r\n", status); MX_I2C1_Init(); continue; } float vdd = MLX90640_GetVdd(frame, &mlx90640); float Ta = MLX90640_GetTa(frame, &mlx90640); Ambient_temperature = (uint8_t)Ta; DEBUG_PRINTF("vdd %.1f Ta %.1f\r\n", vdd, Ta); if (vdd < 2.5f || vdd > 5.5f || Ta < -40 || Ta > 85) { DEBUG_PRINTF("Failed vdd %.1f Ta %.1f\r\n", vdd, Ta); failCount++; if (failCount >= 5) { DEBUG_PRINTF("[MLX] Failed 5 times, system resetting\r\n"); NVIC_SystemReset(); // 软复位 } continue; } float tr = Ta - TA_SHIFT; float emissivity = flash_data.Emissivity / 100.0f; MLX90640_CalculateTo(frame, &mlx90640, emissivity, tr, mlx90640To); MLX90640_BadPixelsCorrection(mlx90640.brokenPixels, mlx90640To, 1, &mlx90640); MLX90640_BadPixelsCorrection(mlx90640.outlierPixels, mlx90640To, 1, &mlx90640); // 数据有效性检查 int oddSum = 0, evenSum = 0; for (int i = 0; i < 768; i++) { if (mlx90640To[i] < -40 || mlx90640To[i] > 255) { DEBUG_PRINTF("[MLX] Temperature point[%d] invalid, value=%.1f, retrying...\r\n", i, mlx90640To[i]); validFrame = 0; break; } if (i % 2 == 0) evenSum += mlx90640To[i]; else oddSum += mlx90640To[i]; } if (oddSum == 0 || evenSum == 0) { DEBUG_PRINTF("[MLX] Odd or even sum is zero, invalid data, retrying...\r\n"); validFrame = 0; continue; } validFrame = 1; control_MLX90640_power(false); end_tick = osKernelGetTickCount(); DEBUG_PRINTF("MLX_end_tick %lu\r\n",end_tick); DEBUG_PRINTF("Elapsed time: %lu ms\r\n", end_tick - start_tick); } return validFrame; } // 处理MLX90640读取到的温度数据 int ProcessTemperatureData(void) { DEBUG_PRINTF("[Process] Start processing temperature data\r\n"); // 初始化最大值、最小值、平均值、最大值坐标 float maxTemp = mlx90640To[0]; float minTemp = mlx90640To[0]; float sumTemp = 0; int maxIndex = 0; int minIndex = 0; for (int i = 0; i < 768; i++) { if (mlx90640To[i] > maxTemp) { maxTemp = mlx90640To[i]; maxIndex = i; } else if (mlx90640To[i] == maxTemp && i < maxIndex) { maxIndex = i; // 选择第一个最大值索引 } if (mlx90640To[i] < minTemp) { minTemp = mlx90640To[i]; minIndex = i; } sumTemp += mlx90640To[i]; } DEBUG_PRINTF("[Process] MaxTemp=%.1f maxIndex=%d, MinTemp=%.1f minIndex=%d\r\n", maxTemp, maxIndex, minTemp, minIndex); float avgTemp = sumTemp / 768; // 判断系统预警等级 if ((uint8_t)maxTemp <= flash_data.first_threshold) { systemlevel = 0; } else if ((uint8_t)maxTemp > flash_data.first_threshold && (uint8_t)maxTemp <= flash_data.second_threshold) { systemlevel = 1; } else { systemlevel = 2; } // 填充数据 debugBuffer1_tmp[0] = (uint8_t)systemlevel; debugBuffer1_tmp[1] = (uint8_t)maxTemp; debugBuffer1_tmp[2] = (uint8_t)minTemp; debugBuffer1_tmp[3] = (uint8_t)avgTemp; debugBuffer1_tmp[4] = Ambient_temperature; // 最大值点坐标 int maxRow = maxIndex / COLS; int maxCol = maxIndex % COLS; // 确定九宫格范围 int startRow = (maxRow > 0) ? maxRow - 1 : 0; int endRow = (maxRow < ROWS - 1) ? maxRow + 1 : ROWS - 1; int startCol = (maxCol > 0) ? maxCol - 1 : 0; int endCol = (maxCol < COLS - 1) ? maxCol + 1 : COLS - 1; // 填充九宫格数据 int dataIndex = 0; memset(debugBuffer2_tmp, 0, sizeof(debugBuffer2_tmp)); for (int r = startRow; r <= endRow; r++) { for (int c = startCol; c <= endCol; c++) { int temp = (int)mlx90640To[r * COLS + c]; // 舍去小数部分 if (dataIndex < 1) { debugBuffer1_tmp[dataIndex + 7] = (uint8_t)temp; } else { debugBuffer2_tmp[dataIndex - 1] = (uint8_t)temp; } dataIndex++; } } // 填充最大值点坐标 debugBuffer1_tmp[5] = (uint8_t)maxCol; debugBuffer1_tmp[6] = (uint8_t)maxRow; uint8_t zeroCount = 0; // 统计 debugBuffer2_tmp 中 0 的数量 for (int i = 0; i < sizeof(debugBuffer2_tmp); i++) { if (debugBuffer2_tmp[i] == 0) { zeroCount++; } } // 如果 0 的数量在 3 到 6 之间(包含 3 和 6),直接返回 0 if (zeroCount >= 3 && zeroCount <= 6) { return 0; } if( (debugBuffer1_tmp[0] == 0 && debugBuffer1_tmp[1] <= flash_data.first_threshold) ||(debugBuffer1_tmp[0] == 1 && (flash_data.first_threshold < debugBuffer1_tmp[1] && debugBuffer1_tmp[1] <= flash_data.second_threshold)) ||(debugBuffer1_tmp[0] == 2 && debugBuffer1_tmp[1] > flash_data.second_threshold) ) { taskENTER_CRITICAL(); // CAN 消息打包 memcpy(canMsgBuffer1, debugBuffer1_tmp, 8); memcpy(canMsgBuffer2, debugBuffer2_tmp, 8); taskEXIT_CRITICAL(); return 1; } return 0; // DEBUG_PRINTF("ProcessTemperatureData() complete. MaxCol: %d, MaxRow: %d\r\n", maxCol, maxRow); } /** * @breaf 内部flash相关函数 */ void Read_NODE_ID_From_Flash(void) // 从 Flash 读取 NODE_ID { NODE_ID = *((uint8_t *)FLASH_SECOND_LAST_PAGE_ADDR); if (NODE_ID == 0xFF) { NODE_ID = 15 + 30 ; }else{ NODE_ID = NODE_ID; } DEBUG_PRINTF("Loaded data: NODE_ID=%u\n",NODE_ID); } void Read_parameter_From_Flash(void) // 从 Flash 读取 parameter { uint8_t *flash_ptr = (uint8_t *)FLASH_LAST_PAGE_ADDR; if (flash_ptr[0] == 0xFF) { flash_data.first_threshold = 60; }else{ flash_data.first_threshold = flash_ptr[0]; } if (flash_ptr[1] == 0xFF) { flash_data.second_threshold = 100; }else{ flash_data.second_threshold = flash_ptr[1]; } if (flash_ptr[2] == 0xFF) { flash_data.delay_receivedValue = 30; }else{ flash_data.delay_receivedValue = flash_ptr[2]; } if (flash_ptr[3] == 0xFF) { flash_data.Emissivity = 95; }else{ flash_data.Emissivity = flash_ptr[3]; } DEBUG_PRINTF("Loaded data: first_threshold=%u, second_threshold=%u , delay_receivedValue=%u ,Emissivity=%u\n", flash_data.first_threshold, flash_data.second_threshold, flash_data.delay_receivedValue, flash_data.Emissivity); } void Save_NODEID_To_Flash(uint8_t NODE_ID) // 向 Flash 写入 NODE_ID { uint8_t nodeIDData[4] = { NODE_ID, 0, 0, 0 }; uint8_t readnodeIDData[4]; if (Flash_WriteRead(FLASH_SECOND_LAST_PAGE_ADDR, nodeIDData, sizeof(nodeIDData), readnodeIDData) != SUCCESS) { DEBUG_PRINTF("Failed to save NODE_ID to flash\n"); } else { DEBUG_PRINTF("NODE_ID saved to flash: %u\n", nodeIDData[0]); } } void Save_parameter_To_Flash(uint8_t first_threshold ,uint8_t second_threshold ,uint8_t delay_receivedValue ,uint8_t Emissivity) // 向 Flash 写入 parameter { uint8_t parameter[4] = { first_threshold, second_threshold, delay_receivedValue, Emissivity}; uint8_t readparameterData[4]; if (Flash_WriteRead(FLASH_LAST_PAGE_ADDR, parameter, sizeof(parameter), readparameterData) != SUCCESS) { DEBUG_PRINTF("Failed to save Parameter to flash\n"); } else { DEBUG_PRINTF("Parameter saved to flash: [%u] [%u] [%u] [%u]\n", parameter[0], parameter[1], parameter[2], parameter[3]); } } /** * @breaf CAN相关函数 */ //主板ID 0x00100000 HAL_StatusTypeDef CAN_FilterInit(void)// 初始化CAN过滤器 { CAN_FilterTypeDef CAN_FilterInitStructure; // 选择要初始化的过滤器 CAN_FilterInitStructure.FilterBank = 0; // 选择过滤器的过滤库,CAN总线支持多个过滤器 CAN_FilterInitStructure.FilterMode = CAN_FILTERMODE_IDMASK; // 设置过滤模式为ID掩码模式,即根据ID和掩码进行过滤 CAN_FilterInitStructure.FilterScale = CAN_FILTERSCALE_32BIT; // 选择32位的过滤器(过滤器ID + 掩码总共32位) CAN_FilterInitStructure.FilterFIFOAssignment = CAN_FILTER_FIFO0; // 指定过滤器分配给FIFO0,用于接收来自CAN总线的消息 // 配置第一个过滤器接收 0x00100000 CAN_FilterInitStructure.FilterIdHigh = (0x00100000 >> 13) & 0xFFFF; // 高 16 位 CAN_FilterInitStructure.FilterIdLow = ((0x00100000 << 3) & 0xFFFF) | (1 << 2); // 低 16 位 + IDE 位 CAN_FilterInitStructure.FilterMaskIdHigh = 0xFFFF; // 掩码的高16位设置为全1,表示不对该部分进行匹配过滤 CAN_FilterInitStructure.FilterMaskIdLow = 0xFFFF; CAN_FilterInitStructure.FilterActivation = CAN_FILTER_ENABLE; // 启用该过滤器,只有符合条件的消息才会通过 if (HAL_CAN_ConfigFilter(&hcan1, &CAN_FilterInitStructure) != HAL_OK) { Error_Handler(); return HAL_ERROR; } // 配置第二个过滤器接收 0x00110000 CAN_FilterInitStructure.FilterBank = 1; // 使用下一个过滤器 CAN_FilterInitStructure.FilterIdHigh = (0x00110000 >> 13) & 0xFFFF; CAN_FilterInitStructure.FilterIdLow = ((0x00110000 << 3) & 0xFFFF) | (1 << 2); if (HAL_CAN_ConfigFilter(&hcan1, &CAN_FilterInitStructure) != HAL_OK) { Error_Handler(); return HAL_ERROR; } if (HAL_CAN_Init(&hcan1) != HAL_OK)// 初始化CAN外设 { // 如果CAN初始化失败,打印错误信息并进入错误处理 uint32_t can_error = HAL_CAN_GetError(&hcan1); DEBUG_PRINTF("CAN Initialization Error: %ld\n", can_error); Error_Handler(); return HAL_ERROR; } return HAL_OK; } void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan) { CAN_RxHeaderTypeDef RX_Header; uint8_t rxData[8]; if (HAL_CAN_GetRxMessage(&hcan1, CAN_RX_FIFO0, &RX_Header, rxData) == HAL_OK) { if (RX_Header.ExtId == 0x00100000 && RX_Header.IDE == CAN_ID_EXT) { DEBUG_PRINTF("CANID received: 0x%08X\n", RX_Header.ExtId); if (rxData[1] == 0x00) { CAN_Send_Parameter(NODE_ID, 0, &flash_data, 0xFF, 0xFF, 0xFF); return; } // 更新 NODE_ID if (rxData[0] == 0xFF || rxData[0] == (uint8_t)(NODE_ID & 0xFF)) { NODE_ID = rxData[1]; // 保存到 Flash Save_NODEID_To_Flash(NODE_ID); // 应答 CAN_Send_extId(&NODE_ID, 1, NODE_ID, 0xFF, 0xFF, 0xFF); } else if (rxData[0] != (uint8_t)(NODE_ID & 0xFF)) { // 如果第一个字节和当前全局变量 NODE_ID 不一致,则不执行 return; } } else if(RX_Header.ExtId == 0x00110000 && RX_Header.IDE == CAN_ID_EXT) { DEBUG_PRINTF("CANID received: 0x%08X\n", RX_Header.ExtId); if(rxData[0]==0 || rxData[1]==0 || rxData[2]==0 || rxData[3]==0 ) { CAN_Send_Parameter(NODE_ID, 0, &flash_data, 0xFF, 0xFF, 0xFF); return; } // 更新 first_threshold 和 delay_receivedValue 和 Emissivity flash_data.first_threshold = rxData[0]; flash_data.second_threshold = rxData[1]; flash_data.delay_receivedValue = rxData[2]; flash_data.Emissivity = rxData[3]; // 保存到 Flash Save_parameter_To_Flash(flash_data.first_threshold ,flash_data.second_threshold ,flash_data.delay_receivedValue ,flash_data.Emissivity); // 应答 CAN_Send_Parameter(NODE_ID, 4, &flash_data, 0xFF, 0xFF, 0xFF); } else { DEBUG_PRINTF("CANID mismatched!\n"); } } else { DEBUG_PRINTF("CAN receive failed!Error code: 0x%08lX\n", HAL_CAN_GetError(&hcan1)); } } void CAN_Send_Msg(uint8_t *msg,uint8_t len,uint32_t node_id, uint8_t sequence, uint8_t slice_num, uint8_t slice_id) { CAN_TxHeaderTypeDef Tx_Header; uint32_t TxMailBox; uint32_t ret_status = 0; // 0000 0000 0011 0000 0000 0000 0000 0000 Tx_Header.ExtId = (1U << 28) // 数据标志位 1 | ((node_id & 0xFF) << 20) // 节点 ID,占 8 位 | ((sequence & 0xFF) << 12) // 序列号,占 8 位 | ((slice_num & 0xF) << 8) // 分片总数,占 4 位 | ((slice_id & 0xF) << 4); // 当前分片 ID,占 4 位 Tx_Header.IDE = CAN_ID_EXT; Tx_Header.RTR = CAN_RTR_DATA; Tx_Header.DLC = len; ret_status = HAL_CAN_AddTxMessage(&hcan1,&Tx_Header,msg,&TxMailBox); if(0 != ret_status){ DEBUG_PRINTF("HAL_CAN_AddTxMessage failed , ret_status:0x%x \r\n", ret_status); DEBUG_PRINTF("hcan->ErrorCode: 0x%x \r\n", hcan1.ErrorCode); } } void CAN_Send_extId(uint16_t *data, uint8_t len, uint32_t node_id, uint8_t sequence, uint8_t slice_num, uint8_t slice_id) { // 配置 CAN 发送消息结构体 CAN_TxHeaderTypeDef Tx_Header; uint32_t txMailbox; Tx_Header.ExtId = (0U << 28) // 指令标志位 0 | ((node_id & 0xFF) << 20) // 节点 ID,占 8 位   | ((sequence & 0xFF) << 12) // 序列号,占 8 位   | ((slice_num & 0xF) << 8) // 分片总数,占 4 位   | ((slice_id & 0xF) << 4); // 当前分片 ID,占 4 位 Tx_Header.IDE = CAN_ID_EXT; // 扩展帧 Tx_Header.RTR = CAN_RTR_DATA; // 数据帧 Tx_Header.DLC = len; // 数据长度 if (HAL_CAN_AddTxMessage(&hcan1, &Tx_Header, (uint8_t *)data, &txMailbox) != HAL_OK) { DEBUG_PRINTF("CAN message send failed\n"); } else { // 将数据转换为十六进制字符串形式 char dataStr[len * 3]; // 每字节 3 个字符 (2个字符 + 空格) for (uint8_t i = 0; i < len; i++) { sprintf(&dataStr[i * 3], "%02X ", data[i]); } DEBUG_PRINTF("CAN message sent: ID=0x%08X, Data=%s\n", Tx_Header.ExtId, dataStr); } } void CAN_Send_Parameter(uint32_t node_id, uint8_t len, FlashData *flash_data, uint8_t sequence, uint8_t slice_num, uint8_t slice_id) { CAN_TxHeaderTypeDef Tx_Header; uint32_t TxMailBox; uint32_t ret_status = 0; uint8_t msg[8] = {0}; msg[0] = flash_data->first_threshold; msg[1] = flash_data->second_threshold; msg[2] = flash_data->delay_receivedValue; msg[3] = flash_data->Emissivity; msg[4] = 0; msg[5] = 0; msg[6] = 0; msg[7] = 0; Tx_Header.ExtId = (0U << 28) // 指令标志位 0 | ((node_id & 0xFF) << 20) // 节点 ID,占 8 位   | ((sequence & 0xFF) << 12) // 序列号,占 8 位   | ((slice_num & 0xF) << 8) // 分片总数,占 4 位   | ((slice_id & 0xF) << 4); // 当前分片 ID,占 4 位 Tx_Header.IDE = CAN_ID_EXT; Tx_Header.RTR = CAN_RTR_DATA; Tx_Header.DLC = len; ret_status = HAL_CAN_AddTxMessage(&hcan1,&Tx_Header,msg,&TxMailBox); if(0 != ret_status){ DEBUG_PRINTF("HAL_CAN_AddTxMessage failed , ret_status:0x%x \r\n", ret_status); DEBUG_PRINTF("hcan->ErrorCode: 0x%x \r\n", hcan1.ErrorCode); } } /** * @breaf 低功耗相关 */ void Configure_GPIOs_For_LowPower(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; // 启用承朿 GPIO 端口的时钿 __HAL_RCC_GPIOA_CLK_ENABLE(); __HAL_RCC_GPIOB_CLK_ENABLE(); __HAL_RCC_RTC_ENABLE(); __HAL_RCC_USART2_CLK_ENABLE(); GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;// 配置为模拟模式,禁用上拉/下拉 GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Pin = GPIO_PIN_All; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);// 配置 GPIOA GPIO_InitStruct.Pin = GPIO_PIN_All& ~(GPIO_PIN_15);// 配置 GPIOB HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); // 9 10 是IIC,11 12是CAN HAL_GPIO_WritePin(GPIOA, GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11|GPIO_PIN_12, GPIO_PIN_SET); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0|GPIO_PIN_15, GPIO_PIN_SET); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_4, GPIO_PIN_RESET); __HAL_RCC_GPIOA_CLK_DISABLE(); __HAL_RCC_GPIOB_CLK_DISABLE(); // 关闭外设时钟 __HAL_RCC_USART2_CLK_DISABLE(); __HAL_RCC_I2C1_CLK_DISABLE(); __HAL_RCC_CAN1_CLK_DISABLE(); } void Enter_LPStop2Mode(void) { DEBUG_PRINTF("Entering Stop2\n"); Configure_GPIOs_For_LowPower(); // 使能 RTC 唤醒 Enable_RTC_Wakeup(flash_data.delay_receivedValue); HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE2); // 配置调压器为低功耗模式 HAL_PWREx_EnterSTOP2Mode(PWR_STOPENTRY_WFI);// 进入 STOP2 低功耗模式 // // 重新初始化 CAN // MX_CAN1_Init(); // // 重新启动 CAN // HAL_CAN_Start(&hcan1); // HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING); // HAL_Delay(50); // SystemClock_Config(); // HAL_I2C_DeInit(&hi2c1); // MX_I2C1_Init(); // MX_CAN1_Init(); // 重新初始化 CAN // HAL_CAN_Start(&hcan1); // HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING); // DEBUG_PRINTF("Stop2 wakeup\n"); } void Wakeup_LPStop2Mode(void) { // 重新初始化系统时钟 SystemClock_Config(); NVIC_SystemReset(); // 直接执行软件复位 // // 重新初始化 CAN // MX_CAN1_Init(); // // 重新启动 CAN // HAL_CAN_Start(&hcan1); // HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING); // HAL_Delay(50); // SystemClock_Config(); // HAL_I2C_DeInit(&hi2c1); // MX_I2C1_Init(); // MX_CAN1_Init(); // 重新初始化 CAN // HAL_CAN_Start(&hcan1); // HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING); } void Enable_RTC_Wakeup(uint16_t delay_time) { HAL_RTCEx_DeactivateWakeUpTimer(&hrtc); // 先关闭 RTC 唤醒,防止冲突 // 计算唤醒时间 uint32_t wakeup_counter = delay_time - 9; // 设置 RTC 唤醒 HAL_RTCEx_SetWakeUpTimer_IT(&hrtc, delay_time, RTC_WAKEUPCLOCK_CK_SPRE_16BITS); DEBUG_PRINTF("RTC Wakeup Timer set for %d s\n", wakeup_counter); } void HAL_RTCEx_WakeUpTimerEventCallback(RTC_HandleTypeDef *hrtc) { DEBUG_PRINTF("RTC callback\n"); control_MLX90640_power(true); HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1); // 配置调压器为正常模式 NVIC_SystemReset(); // RTC 唤醒后执行软件复位 } void control_MLX90640_power(bool enable) // 三极管 徐 { // 低电平 供电,高电平 断电。 HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, enable ? GPIO_PIN_RESET : GPIO_PIN_SET); } //void control_MLX90640_power(bool enable) // 跳线 邢 //{ // // 高电平 供电,低电平 断电。 // HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, enable ? GPIO_PIN_SET : GPIO_PIN_RESET); //} void printCurrentRTCTime(void) { RTC_TimeTypeDef sTime = {0}; RTC_DateTypeDef sDate = {0}; char timeString[20]; // 用于存储格式化的时间字符串 char dataString[20]; // 用于存储格式化的时间字符串 // 获取当前时间 HAL_RTC_GetTime(&hrtc, &sTime, RTC_FORMAT_BIN); // 获取当前日期 HAL_RTC_GetDate(&hrtc, &sDate, RTC_FORMAT_BIN); // 格式化时间为字符串 "HH:MM:SS" snprintf(timeString, sizeof(timeString), "%02d:%02d:%02d", sTime.Hours, sTime.Minutes, sTime.Seconds); // 格式化日期为字符串 "YYYY/MM/DD" snprintf(dataString, sizeof(dataString), "20%02d/%02d/%02d", sDate.Year, sDate.Month, sDate.Date); // 打印日期 DEBUG_PRINTF("CurrentBeijingDateTime: %s-%s\n", dataString, timeString); } /* USER CODE END Application */