目录
一.任务的创建与删除
1.任务创建
xTaskCreate:
动态创建,任务控制块,任务栈空间由FreeRTOS从堆中进行分配。任务创建之后,会自动进去就绪态
原型:
BaseType_t xTaskCreate
(
TaskFunction_t pxTaskCode, //指向任务函数的指针
const char * const pcName, //任务名字
const configSTACK_DEPTH_TYPE usStackDepth, //任务堆栈大小,以字为单位
void * const pvParameters, //传递给函数的参数
UBaseType_t uxPriority, //任务优先级
TaskHandle_t * const pxCreatedTask //任务句柄,任务控制块
)
xTaskCreateStatic
静态创建,任务控制块,任务栈空间由用户自己定义。任务创建之后,会自动进去就绪态
原型:
TaskHandle_t xTaskCreateStatic
(
TaskFunction_t pxTaskCode, //任务函数指针
const char * const pcName, //函数名
const uint32_t ulStackDepth, //任务堆栈大小,以字为单位
void * const pvParameters, //传递给函数的参数
UBaseType_t uxPriority, //函数优先级
StackType_t * const puxStackBuffer, //任务堆栈,一般为数组,由用户分配
StaticTask_t * const pxTaskBuffer //任务控制块指针
)
2.任务删除
vTaskDelete
任务删除。当param传入NULL时,代表删除任务本身。
原型:
void vTaskDelete
(
TaskHandle_t xTaskToDelete //任务句柄
)
二.临界区保护接口
void vTaskEnterCritical( void ) //进入临界区
void vTaskExitCritical( void ) //退出临界区
简单而言:临界区保护,就是保护那些不想被打断的程序段。当某程序调用进去临界区,则会关闭程序调度中断。这两个函数需要成对调用,不然进入临界区后,如果不及时退出,程序会一直保留在当前任务,其他任务将得不到调度!
三.任务挂起以及恢复
1.vTaskSuspend
任务挂起,当param传入NULL时,代表挂起任务本身。
原型:
void vTaskSuspend
(
TaskHandle_t xTaskToSuspend //任务句柄
)
2.vTaskResume
任务恢复!
原型:
void vTaskResume
(
TaskHandle_t xTaskToResume //任务句柄
)
3.xTaskResumeFromISR
任务恢复。当想在中断函数中恢复某任务是,需要调用此接口
返回值:
pdTRUE:任务恢复之后需要进行任务切换
pdFALSE:任务恢复之后无需进行任务切换
原型:
BaseType_t xTaskResumeFromISR
(
TaskHandle_t xTaskToResume //任务句柄
)
四.中断管理
中断优先级:
中断也分优先级,高优先级中断可以打断低优先级中断。ARM Cortex-M使用了8位宽的寄存器来配置中断的优先级,称为中断优先级配置寄存器。最大为2^8=256个优先级。但是厂商一般用不到这么大,比如STM32,只用了高四位[7:4],2^4=16个,且还分为抢占优先级与子优先级。
抢占优先级:抢占高优先级可以打断低优先级的中断
子优先级:当同时发生两个抢占优先级的中断时,子优先级越小的优先执行
注:中断优先级值越小,优先级越高
中断优先级分组设置
一共5组设置:
NVIC_PriorityGroup_0:0bit用于抢占优先级(0级别),4bit用于子优先级(16级别)
NVIC_PriorityGroup_1:1bit用于抢占优先级(2级别),3bit用于子优先级(8级别)
NVIC_PriorityGroup_2:2bit用于抢占优先级(3级别),2bit用于子优先级(3级别)
NVIC_PriorityGroup_3:3bit用于抢占优先级(8级别),1bit用于子优先级(2级别)
NVIC_PriorityGroup_4:4bit用于抢占优先级(16级别),0bit用于子优先级(0级别)
FreeRTOS 一般都是使用Group_4,方便管理中断。
NVIC_PriorityGroupConfig()接口可以配置相关优先级分组
特点:
1.低于configMAX_SYSCALL_INTERRUPT_PRIORITY优先级的中断里才允许调用FreeRTOS的API函数
2.建议使用Group_4设置,方便管理
3.中断优先级数值越小,中断优先级越先。任务优先级数值越大,任务优先级越先
4.中断服务函数的优先级需在FreeRTOS所管理的范围内
5.在中断服务函数里调用FreeRTOS的API函数时,需使用带“FromISR”后缀的函数
6.打断当前程序运行的方式:中断,任务调度
五.FreeRTOS临界段代码保护及调度器挂起与恢复
临界段代码保护:
临界段:指必须完整运行,不能被打断的代码段
临界段使用场合:①需严格按照时序初始化的外设:iic,spi等
②系统自身需要
③用户需求
保护方式:关闭中断,当临界段代码运行完后,打开中断
接口:
taskENTER_CRITICAL(); //任务级
taskEXIT_CRITICAL();
taskENTER_CRITICAL_FROM_ISR(); //中断级
taskEXIT_CRITICAL_FROM_ISR();
任务调度器的挂起与恢复
挂起任务调度器:挂起后,任务不能进行调度,停留在当前任务,但是中断正常响应
接口:
void vTaskSuspendAll( void );
void vTaskResume( TaskHandle_t xTaskToResume );
六.FreeRTOS的列表与列表项
列表是FreeRTOS中的一个数据结构,与链表类似。用于跟踪FreeRTOS中的任务.
FreeRTOS中的三大列表项为就绪,阻塞,挂起列表
列表项就是存放在列表中的项目
列表是一个双向环形列表:
支持插入,删除等结点操作。
列表头节点:
typedef struct xLIST
{
listFIRST_LIST_INTEGRITY_CHECK_VALUE //校验值
volatile UBaseType_t uxNumberOfItems; //列表中的列表项数量
ListItem_t * configLIST_VOLATILE pxIndex; //遍历列表的指针,一般指向末尾列表项
MiniListItem_t xListEnd; //末尾列表项
listSECOND_LIST_INTEGRITY_CHECK_VALUE //校验值
} List_t;
列表项:
struct xLIST_ITEM
{
listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE //校验值
configLIST_VOLATILE TickType_t xItemValue; //列表项的值,用于升序排列
struct xLIST_ITEM * configLIST_VOLATILE pxNext; //上一个列表
struct xLIST_ITEM * configLIST_VOLATILE pxPrevious; //下一个列表
void * pvOwner; //列表项的拥有者,一般指向TCB
struct xLIST * configLIST_VOLATILE pxContainer; //列表项所在列表
listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE //校验值
};
迷你列表项(用于标记列表的末尾和挂载其他插入列表中的列表项,相等于列表头的左右手):
struct xMINI_LIST_ITEM
{
listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE
configLIST_VOLATILE TickType_t xItemValue; //一般值为0xffffffff
struct xLIST_ITEM * configLIST_VOLATILE pxNext;
struct xLIST_ITEM * configLIST_VOLATILE pxPrevious;
};
关系图如下:
相关接口:
void vListInitialise( List_t * const pxList ) PRIVILEGED_FUNCTION;
void vListInitialiseItem( ListItem_t * const pxItem ) PRIVILEGED_FUNCTION;
void vListInsert( List_t * const pxList, ListItem_t * const pxNewListItem ) PRIVILEGED_FUNCTION;
void vListInsertEnd( List_t * const pxList, ListItem_t * const pxNewListItem ) PRIVILEGED_FUNCTION;
UBaseType_t uxListRemove( ListItem_t * const pxItemToRemove ) PRIVILEGED_FUNCTION;
需要注意的就是vListInsert是升序插入,其他接口都比较简单
七.任务调度
①void ICACHE_ATTR vTaskStartScheduler( void ) //开始任务调度
主要做一下事情:
1.创建空闲任务
2.创建软件定时器任务
3.初始化xNextTaskUnblockTime 阻塞超时时间,xSchedulerRunning调度器运行标记位,xTickCount系统节拍
4.调用xPortStartScheduler(),完成启动任务调度器中与硬件相关的配置,以及启动第一个任务。此时不进行return,直接跳到第一个任务中执行代码
八.任务相关api函数
uxTaskPriorityGet //获取任务优先级
vTaskPrioritySet //设置任务优先级
uxTaskGetNumberOfTasks //获取系统中任务的数量
uxTaskGetSystemState //获取所有任务状态信息
vTaskGetInfo //获取指定单个的任务信息
xTaskGetCurrentTaskHandle //获取当前任务的任务句柄
xTaskGetHandle //根据任务名获取该任务的任务句柄
uxTaskGetStackHighWaterMark //获取任务的任务栈历史剩余最小值
eTaskGetState //获取任务状态
vTaskList //以“表格”形式获取所有任务的信息
vTaskGetRunTimeStats //获取任务的运行时间
。
。
。
。
。等等
延时函数:
vTaskDelay
相对延时。从执行函数vTaskDelay()开始计时,直到时间结束。以ms为单位,把当前任务移除到等待任务列表中
vTaskDelayUntil
绝对延时。将整个任务的运行周期看出一个整体,适用于按照一定频率运行的任务。也就是在任务中如果调用了该函数,则该任务整体运行需要100ms时间