Files
FreeRTOS_LoRa_Environment_A…/STM32/Environment_Node/User/main.c

348 lines
12 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#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)
{
}
}