(第34-36讲)FreeRTOS消息队列知识汇总【B站UP、硬件家园、普中科技、正点原子】【视频笔记】【原创】


🔴🟡🟢其他文章链接,独家吐血整理

【吐血总结】FreeRTOS难点、Systick中断-滴答定时器、PendSV中断-任务切换、SVC中断-系统底层、时间片调度-时钟节拍【已完结】
(第1-8讲)STM32F4单片机,FreeRTOS基础知识总结【视频笔记、代码讲解】【正点原子】【原创】
(第9-10讲)STM32F4单片机,FreeRTOS任务创建和删除(动态方法)【视频笔记、代码讲解】【正点原子】【原创】
(第12讲)STM32F4单片机,FreeRTOS任务创建和删除(静态方法)【视频笔记、代码讲解】【正点原子】【原创】
(第13-14讲)STM32F4单片机,FreeRTOS任务挂起和恢复【视频笔记、代码讲解】【正点原子】【原创】
(第16-17讲)STM32F4单片机,FreeRTOS中断管理简介【视频笔记、代码讲解】【正点原子】【原创】
(第18-19讲)32单片机,FreeRTOS临界段代码保护、任务调度器的挂起和恢复【视频笔记、代码讲解】【原创】
(第20-22讲)STM32F4单片机,FreeRTOS列表和列表项API函数讲解【视频笔记、代码讲解、正点原子】【原创】
(第34-36讲)FreeRTOS消息队列知识汇总【B站UP、硬件家园、普中科技、正点原子】【视频笔记】【原创】
(第40-44讲)STM32F4单片机,FreeRTOS信号量【二值、计数、翻转、互斥】【代码讲解】【正点原子】【原创】

1、消息队列的概念

在这里插入图片描述
在这里插入图片描述
1、超时机制是指,可以设置最大读取的等待时间,假如任务超过时间仍旧没有读取到消息(队列为空,或者任务还没发过来),则任务不再等待读取了
2、是指一个任务在读取的时候会禁止其它的任务去读取队列消息
3、如果是裸机开发的话,一个全局标志变量flag,cpu需要永远去判断监视它(浪费算力),而队列的话,你没发过来消息我不会傻乎乎去读取,你发过来的瞬间我才会读取(一发即中多好啊哈哈)
4、fifo是先进先出,lifo则相反
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
复制就是拷贝副本,中断中不允许放入太多数据

2、消息队列常用API函数

在这里插入图片描述
在这里插入图片描述
ISR就是中断

3、普中科技&&正点原子

1、2024温故知新(纯文字)

队列=栈=数组=仓库=存储一些标志变量
信号=消息=全局数组=任务之间通信使用的标志变量
前面笔记写了只有三种列表,就绪、阻塞、挂起、没有运行
写队列时正常是要进入运行态,发现满了写不进去就从就绪移到阻塞态
读队列时是相同的方式,如果空了读不出来也是从就绪移到阻塞态
如果多个任务同时写队列或者读队列,但是队列又满了或者空了,则按照各种的等待时间来决定谁先写谁先读,任务之间的等待时间不可能相同,因为同一时间只能运行一个任务
!!!实际上这里的阻塞好像和任务切换之间的阻塞态不同,我猜测是把任务task任务阻塞了肯定是这样,待补充
全局变量适用于裸机系统(时间片轮询),不适用于OS系统,因为会存在多个任务重复交叉读写某个全局变量,导致结果出错(一任务在写变量的过程中,被另一个任务打断重复写这个变量,最终的结果对于两个任务来说都不是期望的结果)
队列可以理解为受临界区保护的全局数组,创建队列时要指定队列长度和队列项目大小
队列先进先出,也可以配置成后进后出(不常用)
队列可以穿进去实际值,也可以传入指针(大数据)
任何任务和中断都可以读写队列

/*
char g_i = 0;

task//1ms的时间片
{	
	if (读队列)
	{
		//code
	}
	
	vTaskDelay(10); //10ms
	g_i++;
	
	if (g_i > 200) //2s
	{
		g_i = 0;
	}
}//如果读队列发现为空,则task被阻塞(从运行态变阻塞态),则g_i变量如何变化要等实测
*/

队列有个结构体,里面有很多成员参数(这些参数实现了读写队列,并且具有上面那么多机制)
创建队列(我喜欢动态创建)->写队列->读队列

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
任务A向队列发送15之后,虽然这个值又变成了20,但是15和20都进入到了消息队列中(这就是拷贝的好处,能记录历史值)
在这里插入图片描述
在这里插入图片描述
假如队列是空的,任务A没有读到数据,此时它有三种做法,1不等,2等一会(设置阻塞时间),3死等;任务B是入队,它也有三种做法,同上一样
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
创,写数据,读数据,删
在这里插入图片描述
动态创建队列,要手动定义空间
在这里插入图片描述
在这里插入图片描述
中断中不能使用这个函数,会引起中断阻塞
在这里插入图片描述
在这里插入图片描述
也是不能在中断中使用这个函数,绿色框框表示消息之后不会删除消息,另外一个函数读完之后会删除消息
在这里插入图片描述
数据过大的话就采取地址发送了,而不是拷贝

4、正点原子demo.c函数【讲解】

/**
 ****************************************************************************************************
 * @file        freertos.c
 * @author      正点原子团队(ALIENTEK)
 * @version     V1.4
 * @date        2022-01-04
 * @brief       FreeRTOS 移植实验
 * @license     Copyright (c) 2020-2032, 广州市星翼电子科技有限公司
 ****************************************************************************************************
 * @attention
 *
 * 实验平台:正点原子 F407电机开发板
 * 在线视频:www.yuanzige.com
 * 技术论坛:www.openedv.com
 * 公司网址:www.alientek.com
 * 购买地址:openedv.taobao.com
 *
 ****************************************************************************************************
 */

#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 * pvParameters );


/* TASK2 任务 配置
 * 包括: 任务句柄 任务优先级 堆栈大小 创建任务
 */
#define TASK2_PRIO         3
#define TASK2_STACK_SIZE   128
TaskHandle_t    task2_handler;
void task2( void * pvParameters );

/* TASK3 任务 配置
 * 包括: 任务句柄 任务优先级 堆栈大小 创建任务
 */
#define TASK3_PRIO         4
#define TASK3_STACK_SIZE   128
TaskHandle_t    task3_handler;
void task3( void * pvParameters );
/******************************************************************************************************/
QueueHandle_t key_queue;        /* 小数据句柄 */
QueueHandle_t big_date_queue;   /* 大数据句柄 */
char buff[100] = {"我是一个大数组,大大的数组 124214 uhsidhaksjhdklsadhsaklj"};
/**
 * @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_date_queue = xQueueCreate( 1, sizeof(char *) );
    if(big_date_queue != NULL)
    {
        printf("big_date_queue队列创建成功!!\r\n");
    }else printf("big_date_queue队列创建失败!!\r\n");
    
    xTaskCreate((TaskFunction_t         )   start_task,
                (char *                 )   "start_task",
                (configSTACK_DEPTH_TYPE )   START_TASK_STACK_SIZE,
                (void *                 )   NULL,
                (UBaseType_t            )   START_TASK_PRIO,
                (TaskHandle_t *         )   &start_task_handler );
    vTaskStartScheduler();
}


void start_task( void * pvParameters )
{
    taskENTER_CRITICAL();               /* 进入临界区 */
    xTaskCreate((TaskFunction_t         )   task1,
                (char *                 )   "task1",
                (configSTACK_DEPTH_TYPE )   TASK1_STACK_SIZE,
                (void *                 )   NULL,
                (UBaseType_t            )   TASK1_PRIO,
                (TaskHandle_t *         )   &task1_handler );
                
    xTaskCreate((TaskFunction_t         )   task2,
                (char *                 )   "task2",
                (configSTACK_DEPTH_TYPE )   TASK2_STACK_SIZE,
                (void *                 )   NULL,
                (UBaseType_t            )   TASK2_PRIO,
                (TaskHandle_t *         )   &task2_handler );
               
    xTaskCreate((TaskFunction_t         )   task3,
                (char *                 )   "task3",
                (configSTACK_DEPTH_TYPE )   TASK3_STACK_SIZE,
                (void *                 )   NULL,
                (UBaseType_t            )   TASK3_PRIO,
                (TaskHandle_t *         )   &task3_handler );                
    vTaskDelete(NULL);
    taskEXIT_CRITICAL();                /* 退出临界区 */
}

/* 任务一,实现入队 */
void task1( void * pvParameters )
{
    uint8_t key = 0;
    char * buf;
    BaseType_t   err = 0;
    buf = &buff[0]; /* buf = &buff[0] */
    while(1) 
    {
        key = key_scan(0);
        if(key == KEY0_PRES || key == KEY1_PRES)
        {
            err = xQueueSend( key_queue, &key, portMAX_DELAY );
            if(err != pdTRUE)
            {
                printf("key_queue队列发送失败\r\n");
            }
        }else if(key == WKUP_PRES)
        {
            err = xQueueSend( big_date_queue, &buf, portMAX_DELAY );
            if(err != pdTRUE)
            {
                printf("key_queue队列发送失败\r\n");
            }
        }
        vTaskDelay(10);
    }
}

/* 任务二,小数据出队 */
void task2( void * pvParameters )
{
    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 * pvParameters )
{
    char * buf;
    BaseType_t err = 0;
    while(1)
    {
        err = xQueueReceive( big_date_queue,&buf,portMAX_DELAY);
        if(err != pdTRUE)
        {
            printf("big_date_queue队列读取失败\r\n");
        }else 
        {
            printf("数据:%s\r\n",buf);
        }
    }
}


这个函数很简单,结合前面学习过的知识,注意传输单个数据和长字符串数组的方法即可。

1、一个弹幕的小问题

在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值