348 lines
12 KiB
C
348 lines
12 KiB
C
#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)
|
||
{
|
||
char cBuffer[50];
|
||
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);
|
||
snprintf(cBuffer, sizeof(cBuffer), "Temp=%d, Humi=%d\r\n", ucRecTempData, ucRecHumiData);
|
||
vUsartSendString(USART1, cBuffer);
|
||
vTaskDelay(1000);
|
||
}
|
||
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(USART1, "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(USART1, 115200);
|
||
vUsartInit(USART3, 115200);
|
||
vCreateQueuesList();
|
||
vCreateSemaphoresList();
|
||
vCreateTasksList();
|
||
vTaskStartScheduler();
|
||
while(1)
|
||
{
|
||
|
||
}
|
||
}
|