定义:任务与任务,任务与中断数据交流的一种机制(用于传递信息)
特点:先进先出,也可以设置为先进后出,出队入队可能遇到阻塞,所以设置阻塞时间,自带临界区不能被打断,与全局变量相比更安全
动态创建 xQueueCreate( uxQueueLength,uxItemSize )
参数:队列长度,队列子项的大小 返回值:NULL失败,非NULL成功
静态创建 xQueueCreateStatic(uxQueueLength,uxItemSize,pucQueueStorage,pxQueueBuffer)
参数:队列长度,队列子项大小,队列存储区域起始地址,静态队列结构体 返回值 :同上
portBASE_TYPE xQueueSend( xQueueHandle xQueue,
const void * pvItemToQueue,
portTickType xTicksToWait );
参数:目标队列的句柄,指向发送数据 的指针,阻塞超时时间(目标队列已满,就等待)
返回值:pdPASS表示写入成功 errQUEUE_FULL表示写入不成功
xTicksToWait如果设为portMAX_DELAY,并且在FreeRTOSConig.h 中设定 INCLUDE_vTaskSuspend为
1,那么阻塞等待将没有超时限制。
上面俩API不能在中断服务例程中调用
xQueueSendToFrontFromISR()与xQueueSendToBackFromISR()用于在中断服务中实现相同的功能。
xQueueReceive()与 xQueuePeek()API函数
xQueueReceive()用于从队列中接收(读取)数据单元,接收到的单元同时会从队列中删除。
xQueuePeek()也是从队列中接收数据单元,但不会在队列中删除接收到的单元。
portBASE_TYPE xQueueReceive( xQueueHandle xQueue,
const void * pvBuffer,
portTickType xTicksToWait );
portBASE_TYPE xQueuePeek( xQueueHandle xQueue,
const void * pvBuffer,
portTickType xTicksToWait );
参数:被读队列的句柄,指向接收数据缓存区的指针,阻塞超时时间
返回值:pdPASS表示读取成功 errQUEUE_FULL表示读取不成功
xTicksToWait如果设为portMAX_DELAY,并且在FreeRTOSConig.h 中设定 INCLUDE_vTaskSuspend为 1,那么阻塞等待将没有超时限制。
上面俩API不能在中断服务例程中调用
xQueueReceiveFromISR()用于在中断服务中实现相同的功能
uxQueueMessagesWaiting()API函数
unsigned portBASE_TYPE uxQueueMessagesWaiting(xQueueHandle xQueue);
参数:被查询队列的句柄 返回值:保存有数据的单元个数,0则队列为空
临界区保护
taskENATER_CRITICAL(); 进入临界区
taskEXIT_CRITICAL(); 退出临界区
作用:保护那些不想被打断的程序段
队列实验
//freertos_demo.c
#include "freertos_demo.h"
#include "./SYSTEM/usart/usart.h"
#include "./BSP/LED/led.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/KEY/key.h"
#include "./SYSTEM/delay/delay.h"
#include "./MALLOC/malloc.h"
/*FreeRTOS*********************************************************************************************/
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
/******************************************************************************************************/
/*FreeRTOS配置*/
/* START_TASK 任务 配置
* 包括: 任务句柄 任务优先级 堆栈大小 创建任务
*/
#define START_TASK_PRIO 1
#define START_TASK_STACK_SIZE 128
TaskHandle_t start_task_handler;
void start_task(void * pvParameters);
/* TASK1 任务 配置
* 包括: 任务句柄 任务优先级 堆栈大小 创建任务
*/
#define TASK1_PRIO 2
#define TASK1_STACK_SIZE 128
TaskHandle_t task1_handler;
void task1(void* pv);
/* TASK2 任务 配置
* 包括: 任务句柄 任务优先级 堆栈大小 创建任务
*/
#define TASK2_PRIO 2
#define TASK2_STACK_SIZE 128
TaskHandle_t task2_handler;
void task2(void* pv);
/* TASK3 任务 配置
* 包括: 任务句柄 任务优先级 堆栈大小 创建任务
*/
#define TASK3_PRIO 4
#define TASK3_STACK_SIZE 128
TaskHandle_t task3_handler;
void task3(void* pv);
/******************************************************************************************************/
QueueHandle_t key_queue; //小数据句柄
QueueHandle_t big_data_queue; //大数据句柄
char buff[200] = {"世界终结前,抓住那最后的闪电,心灵在颤抖,又一次轮回十万年,再来是千年的千年"};
/**
* @brief FreeRTOS例程入口函数
* @param 无
* @retval 无
*/
void freertos_demo(void)
{
key_queue = xQueueCreate( 2, sizeof(uint8_t) ); //创建小数据队列
if(key_queue != NULL)
{
printf("key_queue创建成功!!!\r\n");
}else printf("key_queue创建失败!!!\r\n");
big_data_queue = xQueueCreate( 1, sizeof(char *) ); //创建大数据队列
if(big_data_queue != NULL)
{
printf("big_data_queue创建成功!!!\r\n");
}else printf("big_data_queue创建失败!!!\r\n");
xTaskCreate((TaskFunction_t ) start_task, //创建开始任务
(char* ) "start_task",
(unsigned portSHORT) START_TASK_STACK_SIZE,
(void * ) NULL,
(portBASE_TYPE ) START_TASK_PRIO,
(TaskHandle_t* ) &start_task_handler );
vTaskStartScheduler();
}
void start_task(void* pvPara)
{
taskENTER_CRITICAL(); //进入临界区
xTaskCreate((TaskFunction_t ) task1, //创建任务一
(char* ) "task1",
(unsigned portSHORT) TASK1_STACK_SIZE,
(void * ) NULL,
(portBASE_TYPE ) TASK1_PRIO,
(TaskHandle_t* ) &task1_handler );
xTaskCreate((TaskFunction_t ) task2, //创建任务二
(char* ) "task2",
(unsigned portSHORT) TASK2_STACK_SIZE,
(void * ) NULL,
(portBASE_TYPE ) TASK2_PRIO,
(TaskHandle_t* ) &task2_handler );
xTaskCreate((TaskFunction_t ) task3, //创建任务二
(char* ) "task3",
(unsigned portSHORT) TASK3_STACK_SIZE,
(void * ) NULL,
(portBASE_TYPE ) TASK3_PRIO,
(TaskHandle_t* ) &task3_handler );
vTaskDelete(NULL); //删除start_task任务
taskEXIT_CRITICAL(); //退出临界区
}
//任务一 实现入队
void task1(void* pv)
{
uint8_t key = 0;
char* buf;
BaseType_t err = 0;
buf = buff; //buf等于buff[200]的首地址
while(1)
{
key = key_scan(0);
if(key == KEY0_PRES || key == KEY1_PRES) //key1还是key0按下
{
err = xQueueSend(key_queue,&key,portMAX_DELAY); //发送key值到小数据队列中
if(err != pdTRUE) //判断是否发送成功
{
printf("key_queue队列发送失败!!!\r\n");
}
}else if(key == WKUP_PRES) //key_up按键按下
{
err = xQueueSend(big_data_queue,&buf,portMAX_DELAY); //发送buff[200]的首地址到大数据队列中
if(err != pdTRUE)
{
printf("big_data_queue队列发送失败!!!\r\n");
}
}
vTaskDelay(500);
}
}
//任务二 小数据出队
void task2(void* pv)
{
uint8_t key = 0;
BaseType_t err = 0;
while(1)
{
err = xQueueReceive(key_queue,&key,portMAX_DELAY); //队列读取小数据
if(err != pdTRUE)
{
printf("key_queue队列读取失败\r\n");
}else
{
printf("key_queue队列读取成功,数据:%d\r\n",key);
}
}
}
//任务三 大数据出队
void task3(void* pv)
{
char * buf;
BaseType_t err = 0;
while(1)
{
err = xQueueReceive(big_data_queue,&buf,portMAX_DELAY); //队列读取大数据
if(err != pdTRUE)
{
printf("big_data_queue队列读取失败\r\n");
}else
{
printf("big_data_queue队列读取成功,数据:%s\r\n",buf);
}
}
}
//freertos_demo.h
#ifndef __FREERTOS_DEMO_H
#define __FREERTOS_DEMO_H
void freertos_demo(void);
#endif
#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/LED/led.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/KEY/key.h"
#include "./BSP/SRAM/sram.h"
#include "./MALLOC/malloc.h"
#include "freertos_demo.h"
#include "./BSP/TIMER/btim.h"
int main(void)
{
HAL_Init(); /* 初始化HAL库 */
sys_stm32_clock_init(336, 8, 2, 7); /* 设置时钟,168Mhz */
delay_init(168); /* 延时初始化 */
usart_init(115200); /* 串口初始化为115200 */
led_init(); /* 初始化LED */
lcd_init(); /* 初始化LCD */
key_init(); /* 初始化按键 */
sram_init(); /* SRAM初始化 */
my_mem_init(SRAMIN); /* 初始化内部SRAM内存池 */
my_mem_init(SRAMEX); /* 初始化外部SRAM内存池 */
my_mem_init(SRAMCCM); /* 初始化内部CCM内存池 */
delay_ms(10000); //串口反应迟钝,延时一段时间再发送信息,方便观察结果
freertos_demo();
}