🔴🟡🟢其他文章链接,独家吐血整理
【吐血总结】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、一个弹幕的小问题