12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052 |
- /* 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 */
|