一.利用 vTaskList()以及 vTaskGetRunTimeStats()来获取任务的信息
1.现象与开启启用宏
![](https://i-blog.csdnimg.cn/direct/1707e96104fe4a878e429539e241a9b8.png)
freeRTOSConfig.h
![](https://i-blog.csdnimg.cn/direct/c6a7edb6cc004e8da165c8504a81b1f1.png)
//必须启用
#define configUSE_TRACE_FACILITY 1
#define configGENERATE_RUN_TIME_STATS 1
#define configUSE_STATS_FORMATTING_FUNCTIONS 1
#define configSUPPORT_DYNAMIC_ALLOCATION 1
//定义
#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() (CPU_RunTime = 0ul)//为0的原因是下面的 CPU_RunTime已经满足 ,高出10~20倍的条件了。
#define portGET_RUN_TIME_COUNTER_VALUE() CPU_RunTime
2. vTaskList()函数与 vTaskGetRunTimeStats()函数基础信息
vTaskList()函数是FreeRTOS中自带的一个用来获取任务信息的函数,该函数会创建一个列表,列表中包含任务名称,任务状态信息,任务优先级,剩余堆栈以及任务编号的信息。
vTaskGetRunTimeStats()函数是FreeRTOS中自带的一个用来统计各个Task占用CPU时间的函数,使用这个功能我们可以清晰地看到每个任务所占用时间、百分比以及CPU整体的占用率,任务的运行时间信息提供了每个任务获取到的CPU使用权总的时间。
#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() (CPU_RunTime = 0ul)
初始化一个外设来提供统计功能所需的时基。这个时基的分辨率一定要比FreeRTOS的系统时钟高,一般高出10~20倍。
#define portGET_RUN_TIME_COUNTER_VALUE()
CPU_RunTime用于系统时间计数
![](https://i-blog.csdnimg.cn/direct/2c1da2601cbe4bf594eb20261be6030c.png)
//1.在上该语句所在的.c文件种定义 CPU_RunTime2.在 freeRTOSConfig.h调用外部声明的全局变量3.在中断的回调函数中调用4.在开启调度器前 打开中断计时器
![](https://i-blog.csdnimg.cn/direct/0675405fa0ab4d74bb48ac5ebdcd433a.png)
因为使用的是tim7中断计数注意要在调度器使用前打开中断计时器并且在配置时不要忘记打开
![](https://i-blog.csdnimg.cn/direct/2b2a5f2db2d34a2e83a5fc21039f9ee8.png)
任务函数例子:
void task_uart(void *para)
{
uint8_t CPU_RunINfo[400];
while(1)
{
memset(CPU_RunINfo,0,400);
vTaskList((char*)CPU_RunINfo );
printf("任务名\t任务状态\t优先级\t剩余栈\t任务序号\r\n");
printf("%s",CPU_RunINfo);
printf("\r\n");
memset(CPU_RunINfo,0,400);
vTaskGetRunTimeStats((char*)CPU_RunINfo);
printf("任务名\t运行时间\t使用率\r\n");
printf("%s",CPU_RunINfo);
printf("\r\n");
vTaskDelay(1000);
}
}
//补充: 利用tim进行记录时间其实就是在使用其中断的回调函数在进行时间的记录, 每次使用中断计时器时都要注意打开中断计时器
中断是有共同的回调函数但是可以使用判断不同的htim来进行不同的操作
#include "string.h"
uint8_t CPU_RunINfo[400];
memset(CPU_RunINfo,0, 400 ); 从那个地址 CPU_RunINfo,开始赋值0,赋值400 字节
如果 uint16_t CPU_RunINfo[400];
则 memset(CPU_RunINfo,0,800); 从那个地址 CPU_RunINfo,开始赋值0,赋值800 字节
状态:x运行态s挂起态r就绪b阻塞态
二.队列
1.队列的基础信息: 队列其实就是任务与任务之间进行交流与通信,在实际的应用中,常常会遇到一个任务或者中断服务需要和另一个任务进行“沟通交流,这个沟通交流的过程其实就是消息传递的过程,在没有 操作系统的时候两个应用程序进行消息传递一般使用全局变量的方式,但是如果在使用操作系统的应用中,用全局变量来传递消息就会涉及到”资源管理“的问题;
队列的功能就是提供任务到任务,任务到中断和中断到任务的通讯机制;
队列是为了任务与任务,任务与中断之间的通信而准备的,可以在任务与任务、任务与中断之间传递消息,队列中可以储存有限的大小固定的数据项目;
//补充:
为什么不使用全局变量来进行数据传递?
中断里设置i=1;
i=0;就是说中断控制i=1但是没有写在实际的地址上时又来了一次中断使i=1这样就吞了一次中断
LDR r0,[r1,#0] //从r1指向地址读取i的值,及读i在内存内的值
ADDS r0,# //计算5+1 ,并把结果放在r0中
STR r0,[r1,#0] //把r0内的值存储到r1指向的内存中
2.队列的特性:队列数据结构实现任务 异步通信工作
消息支持先进先出方式排队,支持异步读写工作方式,消息支持后进先出方式排队,往队首发送消息
读写队列均支持超时机制
FreeRTOS中采用实际值传递,即将数据拷贝到队列中进行传递,FreeRTOS采用拷 贝数据传递,也可以传递指针(指针也是数值),所以在传递较大的数据的时候采用指针传递
一个任务能够从 任意一个消息队列接受和发送信息;
多个任务能够从 同一个消息队列接受和发送消息;
当队列使用结束后,可以通过删除队列函数进行删除;
队列项:在队列中可以存储数量有限,大小固定的数据,队列中每一个数据叫做队列项,队列能够存储队列项的最大数量成为 队列的长度,创建队列的时候会指定项目的大小和队列的长度;
消息队列的运行方式:
![](https://i-blog.csdnimg.cn/direct/085162b43aef4a15bb81636a951bfd83.png)
队列读写操作
![](https://i-blog.csdnimg.cn/direct/1d7a53a556cf49ab87273ad727c9de2a.png)
队列的出队入队
![](https://i-blog.csdnimg.cn/direct/ec9052359e88402abbd904604686260a.png)
核心
![](https://i-blog.csdnimg.cn/direct/870587446e064fc0ae2a392c7091d19f.png)
3.创建队列函数
静态相比动态要更加安全
queue. h
动态创建队列:
configSUPPORT_DYNAMIC_ALLOCATION 必须在 FreeRTOSConfig.h 中设置为 1
QueueHandle_t xQueueCreate(
UBaseType_t uxQueueLength, // 队列一次可存储的最大项目数
UBaseType_t uxItemSize ); // 存储队列中每个项目所需的大小
如果队列创建成功,则返回所创建队列的句柄。如果创建队列所需的内存 无法分配,则返回 NULL。
静态创建队列:
configSUPPORT_STATIC_ALLOCATION 必须设置为1
QueueHandle_t xQueueCreateStatic(
UBaseType_t uxQueueLength, // 队列一次可存储的最大项目数
UBaseType_t uxItemSize, // 存储队列中每个项目所需的大小
uint8_t *pucQueueStorageBuffer, // 如果 uxItemSize 不为零,则 pucQueueStorageBuffer 必须指向一个 uint8_t 数组,该数组的大小 至少要能容纳队列中最多可能存在的项目的总字节数, 即 ( uxQueueLength * uxItemSize ) 字节。如果 uxItemSize 为零,则 pucQueueStorageBuffer 可以为 NULL
StaticQueue_t *pxQueueBuffer ); // 必须指向 StaticQueue_t 类型的变量,该变量将用于保存队列的数据结构体。队列的任务控制块