/* 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 "can.h" #include "iwdg.h" #include "rtc.h" #include "usart.h" /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ typedef StaticQueue_t osStaticMessageQDef_t; /* USER CODE BEGIN PTD */ /* USER CODE END PTD */ /* Private define ------------------------------------------------------------*/ /* USER CODE BEGIN PD */ uint8_t data_P01[8] = {0}; uint8_t data_P02[8] = {0}; /** * @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 从 2开始 ,0x02 代表 1 号小板 //typedef struct { // uint8_t second_threshold; // 二级警报阈值 // uint8_t delay_receivedValue; // 初始上报频率 // uint8_t reserve1; // uint8_t reserve2; //} FlashData; FlashData flash_data = { .second_threshold = 100, // 二级警报阈值 .delay_receivedValue = 1, // 初始上报频率 1s .reserve1 = 0, }; /* USER CODE END PD */ /* Private macro -------------------------------------------------------------*/ /* USER CODE BEGIN PM */ void CAN_ErrorCheck(void); /* USER CODE END PM */ /* Private variables ---------------------------------------------------------*/ /* USER CODE BEGIN Variables */ 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(uint16_t second_threshold, uint8_t delay_receivedValue); 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) ; 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) ; /* USER CODE END Variables */ /* Definitions for Readpressure */ osThreadId_t ReadpressureHandle; const osThreadAttr_t Readpressure_attributes = { .name = "Readpressure", .stack_size = 128 * 4, .priority = (osPriority_t) osPriorityNormal, }; /* Definitions for Senddata */ osThreadId_t SenddataHandle; const osThreadAttr_t Senddata_attributes = { .name = "Senddata", .stack_size = 128 * 4, .priority = (osPriority_t) osPriorityNormal, }; /* Definitions for Common */ osThreadId_t CommonHandle; const osThreadAttr_t Common_attributes = { .name = "Common", .stack_size = 128 * 4, .priority = (osPriority_t) osPriorityAboveNormal, }; /* Definitions for myQueue01 */ osMessageQueueId_t myQueue01Handle; const osMessageQueueAttr_t myQueue01_attributes = { .name = "myQueue01" }; /* Definitions for myQueue02 */ osMessageQueueId_t myQueue02Handle; uint8_t myQueue02Buffer[ 16 * sizeof( uint16_t ) ]; osStaticMessageQDef_t myQueue02ControlBlock; const osMessageQueueAttr_t myQueue02_attributes = { .name = "myQueue02", .cb_mem = &myQueue02ControlBlock, .cb_size = sizeof(myQueue02ControlBlock), .mq_mem = &myQueue02Buffer, .mq_size = sizeof(myQueue02Buffer) }; /* 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 */ /* USER CODE END FunctionPrototypes */ void ReadpressureTask(void *argument); void SenddataTask(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_NODE_ID_From_Flash(); Read_parameter_From_Flash(); NODE_ID = 04; /* 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 */ /* Create the queue(s) */ /* creation of myQueue01 */ myQueue01Handle = osMessageQueueNew (16, sizeof(uint16_t), &myQueue01_attributes); /* creation of myQueue02 */ myQueue02Handle = osMessageQueueNew (16, sizeof(uint16_t), &myQueue02_attributes); /* USER CODE BEGIN RTOS_QUEUES */ /* add queues, ... */ /* USER CODE END RTOS_QUEUES */ /* Create the thread(s) */ /* creation of Readpressure */ ReadpressureHandle = osThreadNew(ReadpressureTask, NULL, &Readpressure_attributes); /* creation of Senddata */ SenddataHandle = osThreadNew(SenddataTask, NULL, &Senddata_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_ReadpressureTask */ /** * @brief Function implementing the Readpressure thread. * @param argument: Not used * @retval None */ /* USER CODE END Header_ReadpressureTask */ void ReadpressureTask(void *argument) { /* USER CODE BEGIN ReadpressureTask */ /* Infinite loop */ uint8_t sequence =0; uint8_t slice_num = 1; for(;;) { Read_PressureData(); memcpy(data_P02, data_P01, 3); printf("data_P02: "); for (int i = 0; i < 8; i++) { printf("%02X ", data_P02[i]); } printf("\n"); // control_MLX90640_power(false); CAN_Send_Msg(data_P02, 8, NODE_ID, sequence, slice_num, 0); sequence++; // printf("1\n"); Enter_LPStop2Mode(); osDelay(500); // if (osMutexAcquire(dataMutexHandle, pdMS_TO_TICKS(600)) == osOK)// 获取互斥量 // { // memcpy(data_P02, data_P01, 3); // osMutexRelease(dataMutexHandle);// 释放互斥量 // } } /* USER CODE END ReadpressureTask */ } /* USER CODE BEGIN Header_SenddataTask */ /** * @brief Function implementing the Senddata thread. * @param argument: Not used * @retval None */ /* USER CODE END Header_SenddataTask */ void SenddataTask(void *argument) { /* USER CODE BEGIN SenddataTask */ /* Infinite loop */ // TickType_t pxPreviousWakeTime = xTaskGetTickCount(); // uint8_t sequence =0; // uint8_t slice_num = 1; // uint32_t send_interval = 0; // Bus-Off 错误处理标志 // static uint32_t last_busoff_time = 0; // static uint8_t bus_off_flag = 0; for(;;) { // // 1. CAN 错误状态检测部分 // uint32_t can_esr = hcan1.Instance->ESR; // 读取 CAN 错误状态寄存器 // uint8_t lec = (can_esr >> 4) & 0x07; // 最近一次错误类型 // uint8_t tec = (can_esr >> 16) & 0xFF; // 发送错误计数 // uint8_t rec = (can_esr >> 24) & 0xFF; // 接收错误计数 // // // Bus-Off 状态检测与恢复 // if (can_esr & CAN_ESR_BOFF) // { // if (bus_off_flag == 0) // { // 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) // { // printf("[CAN] Try to recover CAN...\n"); // HAL_CAN_Stop(&hcan1); // HAL_CAN_Start(&hcan1); // HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING | CAN_IT_BUSOFF); // // 观察是否成功恢复,若未恢复再走 DeInit/Init // if (hcan1.Instance->ESR & CAN_ESR_BOFF) // { // printf("[CAN] Quick recovery failed. Doing full re-init...\n"); // HAL_CAN_DeInit(&hcan1); // MX_CAN1_Init(); // HAL_CAN_Start(&hcan1); // HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING | CAN_IT_BUSOFF); // } // printf("[CAN] CAN restarted successfully after Bus-Off!\n"); // bus_off_flag = 0; // } // // 跳过本次发送,等待 CAN 恢复 // vTaskDelayUntil(&pxPreviousWakeTime, pdMS_TO_TICKS(10)); // send_interval++; // continue; // } // // Error Passive 警告 // if (tec >= 128 || rec >= 128) // { // printf("[CAN WARNING] Error Passive! TEC=%d REC=%d\n", tec, rec); // } // // LEC(Last Error Code) // if (lec != 0) // { // switch (lec) // { // case 0x01: printf("[CAN LEC] Stuff Error\n"); break; // case 0x02: printf("[CAN LEC] Form Error\n"); break; // case 0x03: printf("[CAN LEC] Acknowledgment Error\n"); break; // case 0x04: printf("[CAN LEC] Bit recessive Error\n"); break; // case 0x05: printf("[CAN LEC] Bit dominant Error\n"); break; // case 0x06: printf("[CAN LEC] CRC Error\n"); break; // default: break; // } // } // // 2. 正常发送部分 // if ((send_interval >= 100 * flash_data.delay_receivedValue)) // { // if (osMutexAcquire(dataMutexHandle, pdMS_TO_TICKS(200)) == osOK)// 获取互斥量 // { // CAN_Send_Msg(data_P02, 8, NODE_ID, sequence, slice_num, 0); // sequence++; // osMutexRelease(dataMutexHandle);// 释放互斥量 // Enter_LPStop2Mode(); // } // send_interval=0; // } // 等待下一次发送 // vTaskDelayUntil(&pxPreviousWakeTime, pdMS_TO_TICKS(10)); osDelay (10); // send_interval++; } /* USER CODE END SenddataTask */ } /* 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; // 闪灯计数器 for(;;) { osDelay(10); // counter++; // if (counter >= 500) // { // HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_4); // 切换 LED 状态 // counter = 0; // 重置计数器 //// HAL_IWDG_Refresh(&hiwdg); // } } /* USER CODE END CommonTask */ } /* Private application code --------------------------------------------------*/ /* USER CODE BEGIN Application */ /** * @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); 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) { 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) { printf("CANID received: 0x%08X\n", RX_Header.ExtId); if ((rxData[4] == 0 && rxData[5] == 0) || rxData[6] == 0) { CAN_Send_Parameter(NODE_ID, 0, &flash_data, 0xFF, 0xFF, 0xFF); return; } flash_data.second_threshold = (rxData[4] << 8) | rxData[5]; flash_data.delay_receivedValue = rxData[6]; // 保存到 Flash Save_parameter_To_Flash(flash_data.second_threshold, flash_data.delay_receivedValue); // 应答 CAN_Send_Parameter(NODE_ID, 3, &flash_data, 0xFF, 0xFF, 0xFF); } else { printf("CANID mismatched!\n"); } } else { 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; // Tx_Header.StdId = id; Tx_Header.ExtId = (1<<28)|(node_id << 20)|(sequence << 12)|(slice_num << 8)|(slice_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){ printf("HAL_CAN_AddTxMessage failed , ret_status:0x%x \r\n", ret_status); 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) { 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]); } 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->second_threshold >> 8) & 0xFF; msg[1] = flash_data->second_threshold & 0xFF; msg[2] = flash_data->delay_receivedValue; msg[3] = 0; 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){ printf("HAL_CAN_AddTxMessage failed , ret_status:0x%x \r\n", ret_status); printf("hcan->ErrorCode: 0x%x \r\n", hcan1.ErrorCode); } } /** * @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 = 02; }else{ NODE_ID = NODE_ID; } 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_ptr[1] == 0xFF) { flash_data.second_threshold = 100; }else{ flash_data.second_threshold = (uint16_t)(flash_ptr[0] << 8) | flash_ptr[1]; } if (flash_ptr[2] == 0xFF) { flash_data.delay_receivedValue = 29; }else{ flash_data.delay_receivedValue = flash_ptr[2]; } printf("Loaded data: second_threshold=%u , delay_receivedValue=%u\n", flash_data.second_threshold, flash_data.delay_receivedValue); } 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) { printf("Failed to save NODE_ID to flash\n"); } else { printf("NODE_ID saved to flash: %u\n", nodeIDData[0]); } } void Save_parameter_To_Flash(uint16_t second_threshold, uint8_t delay_receivedValue) // 向 Flash 写入 parameter { uint8_t parameter[4] = {0}; parameter[0]= (uint8_t)(second_threshold >> 8); parameter[1]= (uint8_t)(second_threshold & 0xFF); parameter[2]= delay_receivedValue; parameter[3]= 0; uint8_t readparameterData[4]; if (Flash_WriteRead(FLASH_LAST_PAGE_ADDR, parameter, sizeof(parameter), readparameterData) != SUCCESS) { printf("Failed to save Parameter to flash\n"); } else { printf("Parameter saved to flash: [%u] [%u] [%u] [%u] \n", parameter[0], parameter[1], parameter[2], parameter[3]); } } /** * @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) { printf("Entering Stop2\n"); Configure_GPIOs_For_LowPower(); Enable_RTC_Wakeup(flash_data.delay_receivedValue); // 使能 RTC 唤醒 // HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE2); // 配置调压器为低功耗模式 HAL_PWREx_EnterSTOP2Mode(PWR_STOPENTRY_WFI);// 进入 STOP2 低功耗模式 } void Wakeup_LPStop2Mode(void) { // 重新初始化系统时钟 SystemClock_Config(); NVIC_SystemReset(); // 直接执行软件复位 } void Enable_RTC_Wakeup(uint16_t delay_time) { HAL_RTCEx_DeactivateWakeUpTimer(&hrtc); // 先关闭 RTC 唤醒,防止冲突 // 计算唤醒时间 uint32_t wakeup_counter = delay_time; // 设置 RTC 唤醒 HAL_RTCEx_SetWakeUpTimer_IT(&hrtc, wakeup_counter, RTC_WAKEUPCLOCK_CK_SPRE_16BITS); printf("RTC Wakeup Timer set for %d s\n", wakeup_counter); } void HAL_RTCEx_WakeUpTimerEventCallback(RTC_HandleTypeDef *hrtc) { printf("RTC callback\n"); // control_MLX90640_power(false); 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); } /* USER CODE END Application */