FreeRTOS之消息队列
声明:本人按照正点原子的FreeRTOS例程进行学习的,欢迎各位大佬指责和批评,谢谢!
消息队列的定义
- 消息队列其实是两个任务之间的数据传递的过程,在没有操作系统之前,使用的是全局变量;使用了FreeRTOS操作系统,就要使用“队列”的机制来完成任务与任务之间、任务与中断之间的数据传递。
- 下面是实验举例:Task1任务获取到键值,使用消息队列发送函数;KeyProcess任务中接收到消息队列,使用消息队列接收函数:
- 创建消息队列
//按键消息队列的数量
#define KEYMSG_Q_NUM 1 //按键消息队列的数量
#define MESSAGE_Q_NUM 4 //发送数据的消息队列的数量
QueueHandle_t Key_Queue; //按键值消息队列句柄
QueueHandle_t Message_Queue; //信息队列句柄
void start_task(void *pvParameters)
{
taskENTER_CRITICAL(); //进入临界区
//创建消息队列
Key_Queue=xQueueCreate(KEYMSG_Q_NUM,sizeof(u8)); //创建消息Key_Queue
Message_Queue=xQueueCreate(MESSAGE_Q_NUM,USART_REC_LEN); //创建消息Message_Queue,队列项长度是串口接收缓冲区长度
//创建TASK1任务 注意:在主函数中需要初始化内部内存池
xTaskCreate((TaskFunction_t )task1_task, my_mem_init(SRAMIN) 此函数在#include"malloc.h"
(const char* )"task1_task", 队列中需要申请内存
(uint16_t )TASK1_STK_SIZE,
(void* )NULL,
(UBaseType_t )TASK1_TASK_PRIO,
(TaskHandle_t* )&Task1Task_Handler);
//创建TASK2任务
xTaskCreate((TaskFunction_t )Keyprocess_task,
(const char* )"keyprocess_task",
(uint16_t )KEYPROCESS_STK_SIZE,
(void* )NULL,
(UBaseType_t )KEYPROCESS_TASK_PRIO,
(TaskHandle_t* )&Keyprocess_Handler);
vTaskDelete(StartTask_Handler); //删除开始任务
taskEXIT_CRITICAL(); //退出临界区
}
- 发送消息----队列
void task1_task(void *pvParameters)
{
u8 key,i;
BaseType_t err;
while(1)
{
key = KEY_Scan(0);
if((Key_Queue != NULL)&&(key))
{
err=xQueueSend(Key_Queue,&key,10);
if(err==errQUEUE_FULL) //发送按键值
{
printf("队列Key_Queue已满,数据发送失败!\r\n");
}
}
i++;
if(i==100)
{
i=0;
LED1=!LED1;
}
vTaskDelay(10);
}
}
- 接收消息----队列
void keyprocess_task(void *pvParameters)
{
u8 key;
while(1)
{
if(Key_Queue != NULL)
{
if(xQueueReceive(Key_Queue,&key,portMAX_DELAY))
{
switch(key)
{
case WKUP_PRES:LED0=!LED0;break;
case KEY2_PRES:BEEP=!BEEP;break;
case KEY0_PRES:printf("已经接收到\r\n");break;
}
}
}
vTaskDelay(10);
}
}
- 下面是主函数
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "timer.h"
#include "lcd.h"
#include "FreeRTOS.h"
#include "task.h"
#include "key.h"
#include "beep.h"
#include "queue.h"
#include "malloc.h"
#define START_TASK_PRIO 1 //任务优先级
#define START_STK_SIZE 256 //任务堆栈大小
TaskHandle_t StartTask_Handler; //任务句柄
void start_task(void *pvParameters); //任务函数
#define LED_TASK_PRIO 2 //任务优先级
#define LED_STK_SIZE 128 //任务堆栈大小
TaskHandle_t LedTask_Handler; //任务句柄
void led_task(void *pvParameters); //任务函数
#define TASK1_TASK_PRIO 3 //任务优先级
#define TASK1_STK_SIZE 256 //任务堆栈大小
TaskHandle_t Task1Task_Handler; //任务句柄
void task1_task(void *pvParameters); //任务函数
#define TASK2_TASK_PRIO 4 //任务优先级
#define TASK2_STK_SIZE 128 //任务堆栈大小
TaskHandle_t Task2Task_Handler; //任务句柄
void task2_task(void *pvParameters); //任务函数
//将字符串中的字母,小写转换为大写
//str:字符串
//len:字符串长度
void LowerToCap(u8 *str,u8 len)
{
u8 i;
for(i=0;i<len;i++)
{
if((96<str[i]) && (str[i]<123))
{
str[i] = str[i] - 32;
}
}
}
//LCD显示接收到的队列消息
void disp_str(u8* str)
{
LCD_Fill(5,230,110,245,WHITE);
LCD_ShowString(5,230,100,16,16,str);
}
#define KEYMSG_Q_NUM 1 //按键消息队列的数量
#define MESSAGE_Q_NUM 4 //发送数据的消息队列的数量
QueueHandle_t Key_Queue; //按键值消息队列句柄
QueueHandle_t Message_Queue; //信息队列句柄
u8 test;
//LCD刷屏时使用的颜色
int lcd_discolor[14]={ WHITE, BLACK, BLUE, BRED,
GRED, GBLUE, RED, MAGENTA,
GREEN, CYAN, YELLOW,BROWN,
BRRED, GRAY };
char InfoBuffer[1000]; //保存信息的数组
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组4
delay_init(168); //初始化延时函数
uart_init(115200); //初始化串口
LED_Init(); //初始化LED端口
KEY_Init();
BEEP_Init();
LCD_Init(); //初始化LCD
my_mem_init(SRAMIN); //初始化内存池
POINT_COLOR = RED;
LCD_ShowString(30,10,200,16,16,"ATK STM32F407");
LCD_ShowString(30,30,200,16,16,"FreeRTOS 测试");
LCD_ShowString(30,50,200,16,16,"任务状态查询");
//创建开始任务
xTaskCreate((TaskFunction_t )start_task, //任务函数
(const char* )"start_task", //任务名称
(uint16_t )START_STK_SIZE, //任务堆栈大小
(void* )NULL, //传递给任务函数的参数
(UBaseType_t )START_TASK_PRIO, //任务优先级
(TaskHandle_t* )&StartTask_Handler); //任务句柄
vTaskStartScheduler(); //开启任务调度
}
//开始任务任务函数
void start_task(void *pvParameters)
{
taskENTER_CRITICAL(); //进入临界区
Key_Queue=xQueueCreate(KEYMSG_Q_NUM,sizeof(u8)); //创建消息Key_Queue
Message_Queue=xQueueCreate(MESSAGE_Q_NUM,USART_REC_LEN); //创建消息Message_Queue,队列项长度是串口接收缓冲区长度
//创建LED任务
xTaskCreate((TaskFunction_t )led_task,
(const char* )"keyprocess_task",
(uint16_t )LED_STK_SIZE,
(void* )NULL,
(UBaseType_t )LED_TASK_PRIO,
(TaskHandle_t* )&LedTask_Handler);
//创建TASK1任务
xTaskCreate((TaskFunction_t )task1_task,
(const char* )"task1_task",
(uint16_t )TASK1_STK_SIZE,
(void* )NULL,
(UBaseType_t )TASK1_TASK_PRIO,
(TaskHandle_t* )&Task1Task_Handler);
//创建TASK2任务
xTaskCreate((TaskFunction_t )task2_task,
(const char* )"task2_task",
(uint16_t )TASK2_STK_SIZE,
(void* )NULL,
(UBaseType_t )TASK2_TASK_PRIO,
(TaskHandle_t* )&Task2Task_Handler);
vTaskDelete(StartTask_Handler); //删除开始任务
taskEXIT_CRITICAL(); //退出临界区
}
//task1任务函数
void task1_task(void *pvParameters)
{
u8 key,i;
BaseType_t err;
while(1)
{
key = KEY_Scan(1); //key0返回为1
if((Key_Queue != NULL)&&(key))
{
vTaskDelay(100);
if(key == KEY0_PRES)
{
test ++;
}
err=xQueueSend(Key_Queue,&test,10);
if(err==errQUEUE_FULL) //发送按键值
{
printf("队列Key_Queue已满,数据发送失败!\r\n");
}
}
i++;
if(i==100)
{
i=0;
LED1=!LED1;
}
vTaskDelay(10);
}
}
//led0任务函数
void led_task(void *pvParameters)
{
while(1)
{
if(Key_Queue != NULL)
{
if(xQueueReceive(Key_Queue,&test,portMAX_DELAY))
{
printf("key0 : %d\r\n",test);
}
}
vTaskDelay(10);
}
}
void task2_task(void *pvParameters)
{
u8 i;
while(1)
{
i++;
if(i==100)
{
i=0;
LED0=!LED0;
}
vTaskDelay(10);
}
}
结束