#include "stm32f10x.h" // Device header #include "FreeRTOS.h" #include "task.h" #include "queue.h" #include "semphr.h" #include "LED.h" #include "DHT11.h" #include "USART.h" #include "LoRa.h" #include "Relay.h" /* 在创建任务前,需要创建一个任务句柄,每个任务句柄与任务一一对应。 */ TaskHandle_t xTaskStateLedHdlr; TaskHandle_t xTaskLedCtrlHdlr; TaskHandle_t xTaskFanCtrlHdlr; TaskHandle_t xTaskDht11Hdlr; TaskHandle_t xTaskLoRaToGateHdlr; TaskHandle_t xTaskLoRaMsgRecHdlr; /* 创建队列句柄 */ QueueHandle_t xQueueTempHdlr; QueueHandle_t xQueueHumiHdlr; QueueHandle_t xQueueUsart1IrqHdlr; QueueHandle_t xQueueUsart2IrqHdlr; QueueHandle_t xQueueUsart3IrqHdlr; /* 创建二值信号量句柄 */ SemaphoreHandle_t xSemLedOnHdlr; SemaphoreHandle_t xSemLedOffHdlr; SemaphoreHandle_t xSemFanOnHdlr; SemaphoreHandle_t xSemFanOffHdlr; /** * @brief LED状态指示任务函数 * @note 通过LED的闪烁状态指示系统运行状态。 * @param *pvParameters 任务参数,未使用,传入NULL。 * @retval None */ void vTaskStateLed(void *pvParameters) { while(1) { vPc13LedOn(); vTaskDelay(1000); vPc13LedOff(); vTaskDelay(1000); } } /** * @brief LED控制任务函数 * @note 根据信号量控制LED的开关状态。 * @param *pvParameters 任务参数,未使用,传入NULL。 * @retval None */ void vTaskLedControl(void *pvParameters) { while (1) { /* code */ if (xSemaphoreTake(xSemLedOnHdlr, pdMS_TO_TICKS(10)) == pdTRUE) { vPc13LedOn(); xSemaphoreGive(xSemLedOnHdlr); } else if (xSemaphoreTake(xSemLedOffHdlr, pdMS_TO_TICKS(10)) == pdTRUE) { /* code */ vPc13LedOff(); xSemaphoreGive(xSemLedOffHdlr); } } } /** * @brief 风扇控制任务函数 * @note 根据信号量控制风扇的开关状态。 * @param *pvParameters 任务参数,未使用,传入NULL。 * @retval None */ void vTaskFanControl(void *pvParameters) { while (1) { /* code */ if (xSemaphoreTake(xSemFanOnHdlr, pdMS_TO_TICKS(10)) == pdTRUE) { vFanOn(); } else if (xSemaphoreTake(xSemFanOffHdlr, pdMS_TO_TICKS(10)) == pdTRUE) { /* code */ vFanOff(); } } } /** * @brief DHT11数据读取任务函数 * @note 定期读取DHT11传感器的数据,并将温度和湿度数据发送到相应的队列。 * @param *pvParameters 任务参数,未使用,传入NULL。 * @retval None */ void vTaskDht11(void *pvParameters) { DHT11Data_t xDHT11Data; /* 数据存储数组。要求与队列参数设置大小一一对应。 */ uint8_t ucSendTempData = 0, ucSendHumiData = 0; if (vDht11Init() != 0) { /* 初始化失败,进行错误处理 */ ucSendTempData = ucSendHumiData = 0xAA; xQueueSend(xQueueTempHdlr, &ucSendTempData, pdMS_TO_TICKS(10)); xQueueSend(xQueueHumiHdlr, &ucSendHumiData, pdMS_TO_TICKS(10)); } while (1) { /* code */ if (vDht11ReadData(&xDHT11Data.ucTemp,&xDHT11Data.ucHumi) == 0) { /* code */ ucSendTempData = xDHT11Data.ucTemp; ucSendHumiData = xDHT11Data.ucHumi; /* 写队列。第一个参数是队列句柄,第二个是写入队列的地址(如数组),第三个是因队列满造成阻塞时的等待时长,也就是无法写入数据时的等待时长,以操作系统默认时钟节拍为准。 */ xQueueSend(xQueueTempHdlr, &ucSendTempData, pdMS_TO_TICKS(10)); xQueueSend(xQueueHumiHdlr, &ucSendHumiData, pdMS_TO_TICKS(10)); } else { ucSendTempData = ucSendHumiData = 0xAB; } } } /** * @brief LoRa数据发送任务函数 * @note 从温湿度队列接收数据,并通过LoRa模块发送到网关。同时处理执行器的控制信号。 * @param *pvParameters 任务参数,未使用,传入NULL。 * @retval None */ void vTaskLoRaToGatePkt(void *pvParameters) { uint8_t ucRecTempData = 0, ucRecHumiData = 0; /* 定义一个返回值判断是否接收成功 */ BaseType_t xRetvalQueueTemp, xRetvalQueueHumi; while (1) { /* code */ /* 接收队列:队列句柄、传输转存的目标变量或数组和未接收到数据的等待时长,分3种情况,分别为0、0~portMAX_DELAY和portMAX_DELAY三种,分别对应 * 一点不等、等一点时间和等最大时间。在等待队列数据的情况下,该接收队列所在的任务会一直处于阻塞态。 */ xRetvalQueueTemp = xQueueReceive(xQueueTempHdlr, &ucRecTempData, pdMS_TO_TICKS(10)); xRetvalQueueHumi = xQueueReceive(xQueueHumiHdlr, &ucRecHumiData, pdMS_TO_TICKS(10)); /* 发送 */ vLoRaConnectionPkt(xLoRaGateConfig.ucLoRaGateChannel); vLoRaToGateIdPkt(xLoRaNode1Config.ucLoRaNode1Identifier); vLoRaToGateSenIdPkt(xLoRaSensorID.ucIdDht11); /* 检测接收队列是否成功 */ if (xRetvalQueueTemp == pdTRUE && xRetvalQueueHumi == pdTRUE) { /* code */ vUsartSendArray(USART3, &ucRecTempData, 1); vUsartSendArray(USART3, &ucRecHumiData, 1); } if (xSemaphoreTake(xSemLedOnHdlr, pdMS_TO_TICKS(10)) == pdTRUE) { /* code */ vUsartSendArray(USART3, &xLoRaExecutorID.ucIdLed, 1); vUsartSendArray(USART3, &xLoRaExecutorCommand.ucCommandOn, 1); } else if (xSemaphoreTake(xSemLedOffHdlr, pdMS_TO_TICKS(10)) == pdTRUE) { /* code */ vUsartSendArray(USART3, &xLoRaExecutorID.ucIdLed, 1); vUsartSendArray(USART3, &xLoRaExecutorCommand.ucCommandOff, 1); } vTaskDelay(500); } } /** * @brief LoRa消息接收任务函数 * @note 从USART3接收LoRa模块传输的执行器控制消息,并根据信号量控制相应的执行器状态。 * @param *pvParameters 任务参数,未使用,传入NULL。 * @retval None */ void vTaskLoRaMsgRec(void *pvParameters) { uint8_t ucDataRecNodeId = 0, ucDataRecExeId = 0, ucDataRecExeSta = 0; uint8_t ucRetvalQueueNodeId = 0, ucRetvalQueueExeId = 0, ucRetvalQueueExeSta = 0; while (1) { ucRetvalQueueNodeId = xQueueReceive(xQueueUsart3IrqHdlr, &ucDataRecNodeId, portMAX_DELAY); ucRetvalQueueExeId = xQueueReceive(xQueueUsart3IrqHdlr, &ucDataRecExeId, portMAX_DELAY); ucRetvalQueueExeSta = xQueueReceive(xQueueUsart3IrqHdlr, &ucDataRecExeSta, portMAX_DELAY); while (ucRetvalQueueNodeId == pdTRUE && ucRetvalQueueExeId == pdTRUE && ucRetvalQueueExeSta == pdTRUE) { /* code */ if (xLoRaMsgProcess(ucDataRecNodeId, ucDataRecExeId, ucDataRecExeSta) == statusLedOn) { /* code */ xSemaphoreGive(xSemLedOnHdlr); } else if (xLoRaMsgProcess(ucDataRecNodeId, ucDataRecExeId, ucDataRecExeSta) == statusLedOff) { /* code */ xSemaphoreGive(xSemLedOffHdlr); } else if (xLoRaMsgProcess(ucDataRecNodeId, ucDataRecExeId, ucDataRecExeSta) == statusFanOn) { /* code */ xSemaphoreGive(xSemFanOnHdlr); } else if (xLoRaMsgProcess(ucDataRecNodeId, ucDataRecExeId, ucDataRecExeSta) == statusFanOn) { /* code */ xSemaphoreGive(xSemFanOffHdlr); } break; } } } /** * @brief 创建任务列表函数 * @note 创建所有需要的FreeRTOS任务。 * @param None * @retval None */ void vCreateTasksList(void) { // #if defined __LED_H__ #if LED_PC13_WORK_MODE == STM32_STATE_MODE /* 创建任务,参数分别为任务函数名称、任务名字、栈大小、返回参数值、优先级、任务句柄。 */ xTaskCreate( (TaskFunction_t ) vTaskStateLed, (char * ) "TaskName_StateLed", (configSTACK_DEPTH_TYPE) 256, (void * ) NULL, (UBaseType_t ) 2, (TaskHandle_t * ) &xTaskStateLedHdlr); #else xTaskCreate( (TaskFunction_t ) vTaskLedControl, (char * ) "TaskName_LedControl", (configSTACK_DEPTH_TYPE) 256, (void * ) NULL, (UBaseType_t ) 2, (TaskHandle_t * ) &xTaskLedCtrlHdlr); #endif // #endif // #if defined __RELAY_H__ xTaskCreate( (TaskFunction_t ) vTaskFanControl, (char * ) "TaskName_FanControl", (configSTACK_DEPTH_TYPE) 256, (void * ) NULL, (UBaseType_t ) 2, (TaskHandle_t * ) &xTaskFanCtrlHdlr); // #endif // #if defined __DHT11_H__ xTaskCreate( (TaskFunction_t ) vTaskDht11, (char * ) "TaskName_DHT11", (configSTACK_DEPTH_TYPE) 512, (void * ) NULL, (UBaseType_t ) 2, (TaskHandle_t * ) &xTaskDht11Hdlr); // #endif // #if defined __LORA_H__ xTaskCreate( (TaskFunction_t ) vTaskLoRaToGatePkt, (char * ) "TaskName_LoRaSendToGateway", (configSTACK_DEPTH_TYPE) 512, (void * ) NULL, (UBaseType_t ) 2, (TaskHandle_t * ) &xTaskLoRaToGateHdlr); xTaskCreate( (TaskFunction_t ) vTaskLoRaMsgRec, (char * ) "TaskName_LoRaReceivedMessage", (configSTACK_DEPTH_TYPE) 512, (void * ) NULL, (UBaseType_t ) 2, (TaskHandle_t * ) &xTaskLoRaMsgRecHdlr); // #endif } /** * @brief 创建队列列表函数 * @note 创建所有需要的FreeRTOS队列。 * @param None * @retval None */ void vCreateQueuesList(void) { /* 创建队列有两个参数,第一个是队列的长度,也就是这个队列能存放多少个数据; * 第二个参数就是每个数据的大小,单位为字节,在stm32中uint8_t指针的长度一般是4字节。 * 原函数的返回值就是队列句柄的结构体,所以需要在上面定义一个变量接收队列句柄。 */ xQueueTempHdlr = xQueueCreate( (UBaseType_t) 5, (UBaseType_t) sizeof(uint8_t)); xQueueHumiHdlr = xQueueCreate( (UBaseType_t) 5, (UBaseType_t) sizeof(uint8_t)); xQueueUsart3IrqHdlr = xQueueCreate( (UBaseType_t) 64, (UBaseType_t) sizeof(uint8_t *)); if (xQueueTempHdlr == NULL || xQueueHumiHdlr == NULL || xQueueUsart3IrqHdlr == NULL) { /* code */ vUsartPrintf(USART3, "Queue Init Failed.\r\n"); } } /** * @brief 创建信号量列表函数 * @note 创建所有需要的FreeRTOS信号量。 * @param None * @retval None */ void vCreateSemaphoresList(void) { xSemLedOnHdlr = xSemaphoreCreateBinary(); xSemLedOffHdlr = xSemaphoreCreateBinary(); xSemFanOnHdlr = xSemaphoreCreateBinary(); xSemFanOffHdlr = xSemaphoreCreateBinary(); } /** * @brief 主函数 * @note 初始化系统各模块,创建队列、信号量和任务,并启动调度器。 * @param None * @retval None */ int main(void) { vFanRelayInit(); vDelayInit(); vPc13LedInit(); vUsartInit(USART3, 115200); vCreateQueuesList(); vCreateSemaphoresList(); vCreateTasksList(); vTaskStartScheduler(); while(1) { } }