本笔记是正点原子的freertos的视频笔记结合freertos开发指南总结的各个部分的常用API。
1.创建函数(动态)
(1)xTaskCreate //创建函数 (创建一个开始函数)
(2)vTaskStartScheduler() //开启任务调度
(3)在开始函数中
vPortEnterCritical()//进入临界段
用xTaskCreate创建相关任务函数
vTaskDelete(NULL);//删除开始函数自身
vPortExitCritical();//退出临界段
(4)任务函数中处理相关任务
vTaskDelete(任务句柄);//删除任务函数
vTaskDelay(500);//进入500ms的阻塞
2.创建函数(静态)
(1)vApplicationGetIdleTaskMemory //为空闲任务分配堆栈和TCB空间
(2)vApplicationGetTimerTaskMemory//为软件定时器任务分配堆栈和TCB空间
(3)StackType_t start_task_stack[128];//用户开辟任务堆栈空间
StaticTask_t start_task_tcb;//用户开辟任务TCB空间
(4)StartTask_Handler(任务句柄)=xTaskCreateStatic//创建静态函数,函数返回值是任务句柄
(5) vTaskDelete(任务句柄);//删除任务函数,和动态删除一样(需要手动删除任务堆栈和TCB空间???)
3.挂起和恢复任务
(1)
vTaskSuspend()
挂起任务(暂停任务)
(2)
vTaskResume()
恢复被挂起的任 AA务
(恢复任务继续运行)
(3)
xTaskResumeFromISR()
在中断中恢复被挂起的任务
4.屏蔽中断任务
优先级低于我们设置的中断就是可以管理的中断
(1)portDISABLE_INTERRUPTS();//关闭可管理的中断
(2)
portENABLE_INTERRUPTS();//恢复中断
5.列表项的插入和删除
(1)(2)(3)是视频讲的,例程里是没有的
(1)这个方法很好可以看到各个地址的情况
![](https://img-blog.csdnimg.cn/530b04bf063a4cf5a07cbce479ea4928.png)
(2)这样可以控制成员的指向
![](https://img-blog.csdnimg.cn/2e5d149ec2ba4b38ac1390e5cb2d3c9f.png)
(3)这样可以控制列表项的值(升序排列插入有用)
![](https://img-blog.csdnimg.cn/5c7a02de57914efdb3b7ad3f61fa87c1.png)
(4)函数
vListInitialise()
初始化列表
(5)
vListInitialiseItem()
初始化列表项
(6)
vListInsert()
将列表项插入到列表中
(7)
uxListRemove()
将列表项从列表中移除
(8)
vListInsertEnd()
列表项插入到列表末尾
6.其他API函数
(1)uxTaskGetSystemState
获取所有任务的状态信息
2 原子的方法更省内存
3
任务编号带表任务创建的顺序
![](https://img-blog.csdnimg.cn/5366408d62a743dab15e3564aa8f753f.png)
4 显示任务状态
IDLE是空闲任务
Tmr Svc是软件定时器
![](https://img-blog.csdnimg.cn/f7e1d6df7a934f208e0a13110219e4fd.png)
(2)vTaskGetInfo
获取指定任务的任务信息
![](https://img-blog.csdnimg.cn/86ef28b5c0d4483399149a1b912480bb.png)
(3)xTaskGetHandle获取任务的句柄
![](https://img-blog.csdnimg.cn/823a84dce4f74ccb862ad1ca49fa6d19.png)
![](https://img-blog.csdnimg.cn/3c4489f8fef1465ab6e78620a2faf6de.png)
(4) uxTaskGetStackHighWaterMark
获取指定任务的任务栈的历史剩余最小值
![](https://img-blog.csdnimg.cn/4d206c0a00f2494fbc61555f11c76f8d.png)
![](https://img-blog.csdnimg.cn/40aa5e8beb7b4cbfafa764dd6a016b83.png)
![](https://img-blog.csdnimg.cn/38ee5c34f44b42f8817bd717639ad6bf.png)
发现很多空间都没有使用,可以改小任务堆栈大小,节省空间
(5)
vTaskList()
以“表格”的形式获取系统中任务的信息(看状态用这个最简单最方便)
该函数的参数直接放定义的一个cahr型的数组即可
(6)
vTaskGetRunTimeStats()
获取指定任务的运行时间、运行状态等信息(调试程序用这个很多)
使用方法:1.
configGENERATE_RUN_TIME_STATS,置1
configUSE_
STATS_FORMATTING
_FUNCTIONS,
置1
onfigSUPPORT_DYNAMIC_ALLOCATION
置1
2.实现该函数定义
portCONFIGURE_TIMER_FOR_RUN_TIME_STATS(),即创建时基 定时器,用于计数任务运行的时间。
3.定时器函数中定义变量
FreeRTOSRunTimeTicks,初始化定时器函数中清零该变量, 定时器中断中加加该变量
![](https://img-blog.csdnimg.cn/eec89975cef341f0969cbed6fee8664a.png)
注意,时间值表示
FreeRTOSRunTimeTicks的值,该值乘10us才是时间
![](https://img-blog.csdnimg.cn/08109b4b969d4b8487235300eaf17ef1.png)
7.延时函数讲解
在延时函数中
进入prvAddCurrentTaskToDelayedList函数
8.队列操作
这里不包括所有api函数,只记录常用的几个用法,其他的举一反三
1.xQueueCreate队列创建函数
(1)函数创建成功返回队列的句柄
(2)队列项有几个
(3)每个队列项的大小
2.xQueueSend向队列发送信息
(1)返回值表明队列是否写入成功
(2)要写入的队列
(3)要写入数据的地址
(4)等待队列项的时间
3.xQueueReceive从队列读取信息
(1)返回值表示读取是否成功
(2)要读取的队列
(3)将读取到的数据存在这里
(4)等待队列有数据的时间
9.队列API函数解析
1xQueueCreate动态队列创建函数
进xQueueCreate函数
进xQueueGenericCreate函数
10.二值信号量
1.xSemaphoreCreateBinary创建二值信号量
2.xSemaphoreGive释放二值信号量
3.xSemaphoreTake获取信号量
例子:(下面说的任务二阻塞可能是被挂到等待接收列表表现出阻塞状态)
有两个任务task1和task2,task2优先级高
如果不按按键,不会释放信号量,任务二的获取信号量函数会将任务二阻塞,任务二不运行了(portMAX_DELAY表示死等),灯不闪,串口不打印字符,任务一为就绪态正常运行,当我们按下按键,信号量被释放代表有资源了,在xSemaphoreGive函数中实现任务调度,任务二优先级大于正在运行的任务一,任务二将任务一抢占,任务二处于就绪态,运行任务二的任务灯闪和串口,然后再回任务一发送串口。
![](https://img-blog.csdnimg.cn/7fc9bccdf6bd4c05bf6d5c74e92a53f4.png)
若改成这样,不死等了,等2秒(阻塞)就不等了(退出阻塞)两秒之后,阻塞500ms继续获取信号量循环
![](https://img-blog.csdnimg.cn/bde75148b0254717995769d3cfd7b64d.png)
11.计数型信号量
需要加头文件 #include "semphr.h"
1.创建计数型信号量
(1)返回信号量句柄
(2)计数值最大值
(3)计数值初值
![](https://img-blog.csdnimg.cn/4ca90945cb244a1d8d5a744d971dacaf.png)
获取释放信号量和二值的获取释放一样
12.队列集
(1)xQueueCreateSet创建队列集
函数参数是队列集中可包含几个队列
![](https://img-blog.csdnimg.cn/6e5bcb14a8534223b598a0ddb0ff3c44.png)
(2)xQueueAddToSet添加队列进队列集
第一个参数是传入的要添加队列的句柄,第二个参数是添加进哪个队列集的句柄
![](https://img-blog.csdnimg.cn/367d507b169446c5ae7776ea55a349ae.png)
(3)xQueueSelectFromSet读消息队列集哪个队列来消息了
![](https://img-blog.csdnimg.cn/52f690eee5c24e51a67bc25626133124.png)
执行后面的操作
(4)其他api函数
![](https://img-blog.csdnimg.cn/207d9cd52cc141698fadacb1d89e320b.png)
13.事件标志组
(1)xEventGroupCreate创建队列集
(2)
xEventGroupSetBits向标志组地零位发送消息
![](https://img-blog.csdnimg.cn/f2b0f8ccbd414dc2a81923f015f0c557.png)
![](https://img-blog.csdnimg.cn/e78e1f69e50b47e49a2ca2aa15342458.png)
(3)xEventGroupWaitBits等待第一位和第二位消息都到来
![](https://img-blog.csdnimg.cn/18e3b4fe37c7426e9d027a6b40fbff6d.png)
14.任务通知
任务通知不用创建,在创建好任务的时候就已经创建好了
1.模拟二值信号量
(1)xTaskNotifyGive 向任务发送通知,执行一次函数,通知值+1,返回值为1表示发送成功,模拟二值信号量
![](https://img-blog.csdnimg.cn/7f044118b7384e479e525f63b3ecef27.png)
(2)ulTaskNotifyTake 接收通知信息,pdTRUE表示接收到通知值后将通知值清零(模拟二值信号量)
![](https://img-blog.csdnimg.cn/347d42227a034648bed7254a72a805b5.png)
2.模拟计数信号量
(1)xTaskNotifyGive 向任务发送通知,执行一次函数,通知值+1
(2)ulTaskNotifyTake 接收通知信息,pdFALSE表示接收到通知值后将通知值-1
![](https://img-blog.csdnimg.cn/c25219bc9a5643f1b5e76f6845cd4c0b.png)
发送通知函数延时小,接收通知函数延时大,就可以实现按键++通知值,但是--慢,就可以控制接收任务的执行时间,按键按住时间越长,接收函数执行多久,直到通知值-为0阻塞
(3)xTaskNotify 发送key的值,eSetValueWithOverwrite代表直接覆写不等待更新原先的数据。
![](https://img-blog.csdnimg.cn/a8ffa5d4503b4e5eb3e534f56d63fa47.png)
(4)xTaskNotifyWait 接收数据 存到vule里面,0xffffffff表示接收到数据后清零32位的数据
![](https://img-blog.csdnimg.cn/407b820b3f0f4e7da7c616578d8a89f0.png)
15.软件定时器
(1)xTimerCreate 创建定时器 (最后一个参数是 定时器超时回调函数)
(2)xTimerStart 开启定时器
xTimerStop关闭定时器
![](https://img-blog.csdnimg.cn/9be6b9c2126448a29a06915d90c05c1f.png)
(3)定时器超时回调函数
注意:软件定时器的超时回调函数是由软件定时器服务任务调用的,软件定时器的超时回调函数本身不是任务,因此不能在该回调函数中使用可能会导致任务阻塞的API函数。
![](https://img-blog.csdnimg.cn/bb977127435b4e59bfe756563aa9c4e7.png)
16.低功耗模式
在config.h中定义宏 PRE_SLEEP_PROCESSING和POST_SLEEP_PROCESSING是我们定义的函数
![](https://img-blog.csdnimg.cn/a6660c677556459ba0e82853914f8c28.png)
(1)和(2)是系统声明的一个宏,宏对应的函数我们要自己去实现
PRE_SLEEP_PROCESSING和POST_SLEEP_PROCESSING就是我们去实现的函数
![](https://img-blog.csdnimg.cn/eec06717fbc2448fa971437764e7e721.png)
在demo.c中我们去实现函数
![](https://img-blog.csdnimg.cn/86d0637a44104e17862311ef3c02d481.png)
在demo.h中我们去定义函数
![](https://img-blog.csdnimg.cn/48731a0fbb774e6f96f2121ac63dece0.png)
由于在config.h中我们宏了
![](https://img-blog.csdnimg.cn/8b3c386c25b74ca3a4b9309a2e1f7c3e.png)
所以在config.h最前面加上
![](https://img-blog.csdnimg.cn/b8fbddff3364435888797418751af537.png)
最后,将宏置一即可
![](https://img-blog.csdnimg.cn/40eb54e893d84cd1818f19310c4e74a1.png)
freertos会自动根据任务在空闲任务中开启低功耗,在下次要执行任务的时候关闭低功耗运行任务并且补偿系统节拍,睡眠模式的硬件为睡眠模式,睡眠前去执行我们实现的低功耗模式开启前函数,这里面可以去关时钟,关闭低功耗前去执行低功耗模式关闭后函数
注意:如果下次唤醒低功耗的时间小于下面这个宏,就不会再进入低功耗了,说明低功耗时间太短了,没必要进去了,这个宏默认值为2ms
configEXPECTED_IDLE_TIME_BEFORE_SLEEPconfigEXPECTED_IDLE_TIME_BEFORE_SLEEP
17.内存管理
(1)pvPortMalloc 申请30个字节的内存(其实在内存申请函数中申请30+内存块结构体的大小)
![](https://img-blog.csdnimg.cn/5873e2660de847f78e2fbbf0a9cc1cff.png)
(2)vPortFree 释放内存
![](https://img-blog.csdnimg.cn/0e420e733e5c409384d2ae22003518d8.png)
(3)xPortGetFreeHeapSize 剩余大小
![](https://img-blog.csdnimg.cn/3897a34c437e4431b2f5b9c5fe2098ef.png)
注意:config.h中这个宏决定freertos一共占用多大的mcu内存
系统就是申请一个这么大的一个数组
![](https://img-blog.csdnimg.cn/a4387ea0c6a04ef1b01d0c4f58d3379b.png)