目录
前言:
一、列表与列表项
二、列表相关API函数
①初始化列表vListInitialise()
②初始化列表项vListInitialise()
③列表插入列表项(升序)函数vListInsert()
④列表插入列表项(无序)函数vListInsertEnd()
⑤移除列表项uxListRemove()函数
总结:
前言:
博客笔记根据B站视频教程编辑,仅供学习交流使用!
一、列表与列表项
列表:FreeRTOS 中的一个数据结构,概念上和链表类似,列表被用来跟踪 FreeRTOS中的任务。
列表项:存放在列表中的项目。
列表相当于链表,列表项相当于节点,FreeRTOS 中的列表是一个双向环形链表。
列表特点:列表项间的地址非连续的,是人为的连接到一起的。列表项:数目是由后期添加的个数决定的,随时可变。可随时删除和插入新的列表项。
数组的特点:数组成员地址是连续的,数组在最初确定了成员数量后期无法改变。
OS中任务的数量是不确定的,并且任务状态是会发生改变的,所以非常适用列表(链表)这种数据结构!
①FreeRTOS的源码中的list.h和list.c中存了有关列表的内容,list.h中列表的相关结构体:
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;
//首位两个校验值是两个宏,已知常量,通过它们判断列表数据运行过程是否遭到破坏,一般用于调试,默认不开启
//uxNumberOfItems,用于记录列表中列表项的个数(不包含 xListEnd)
//pxIndex用于指向列表中的某个列表项,一般用于遍历列表中所有列表项
//xListEnd是一个迷你列表项,排在最末尾
② list.h中列表项的相关结构体:
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 /* 列表项的拥有者 */
struct xLIST * configLIST_VOLATILE pxContainer; /* 列表项所在列表 */
listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE /* 用于检测列表项的数据完整性 */
};
typedef struct xLIST_ITEM ListItem_t;
//xItemValue多用于按升序对列表中的列表项进行排序(比如把阻塞时间小的任务排在前面)
//pxNext和pxPrevious分别指向列表项的下一个和上一个列表项(“双向环链”)
//pxOwner指向包含列表项的对象(通常是任务块)
//pxContainer指向列表项所在列表(就绪、阻塞、挂起)
③迷你列表项
也是列表项,但仅用于标记列表的末尾和挂载其他插入列表中的列表项:
struct xMINI_LIST_ITEM
{
listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE /* 用于检测数据完整性 */
configLIST_VOLATILE TickType_t xItemValue; /* 列表项的值 */
struct xLIST_ITEM * configLIST_VOLATILE pxNext; /* 上一个列表项 */
struct xLIST_ITEM * configLIST_VOLATILE pxPrevious; /* 下一个列表项 */
};
//xItemValue,pxNext,pxPrevious与普通列表项相同
//由于其功能特点,不需要pxOwner和pxContainer,节省了内存开销
列表与列表项关系(列表初始状态和即将插入的两个列表项):
二、列表相关API函数
①初始化列表vListInitialise()
void vListInitialise(List_t * const pxList){
pxList->pxIndex = ( ListItem_t * ) &( pxList->xListEnd );
//初始化时,列表中只有xListEnd项,因此pxIndex指向它
pxList->xListEnd.xItemValue = portMAX_DELAY;
//xListEnd初始化为最大值,以便列表项按升序排序,排在最后
pxList->xListEnd.pxNext = ( ListItem_t * ) &( pxList->xListEnd );
pxList->xListEnd.pxPrevious = ( ListItem_t * ) &( pxList->xListEnd );
//初始化时只有xListEnd项,因此上一个和下一个列表项都为自己本身
pxList->uxNumberOfItems = ( UBaseType_t ) 0U;
//初始化时,列表中列表项数量为0(不包含xListEnd)
listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList );
listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList );
//初始化时,用于检测列表数据完整性的校验值
}
//注意:->和.都可用于访问结构体的成员,但.操作结构体变量本身(跟在变量本身后面),
//而->操作的是结构体变量的指针(地址)
②初始化列表项vListInitialise()
void vListInitialiseItem( ListItem_t * const pxItem ){
pxItem->pxContainer = NULL;
//初始化时,列表项所在列表设为空
listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem );
listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem );
//数据完整性校验值
}
③列表插入列表项(升序)函数vListInsert()
用于将待插入列表的列表项按照列表项值升序进行排序,有序地插入到列表中
void vListInsert( List_t * const pxList, ListItem_t * const pxNewListItem )
{
ListItem_t * pxIterator;
const TickType_t xValueOfInsertion = pxNewListItem->xItemValue; /* 获取列表项的数值依据数值升序排列 */
listTEST_LIST_INTEGRITY( pxList ); /* 检查参数是否正确 */
listTEST_LIST_ITEM_INTEGRITY( pxNewListItem ); /* 如果待插入列表项的值为最大值 */
if( xValueOfInsertion == portMAX_DELAY )
{
pxIterator = pxList->xListEnd.pxPrevious; /* 插入的位置为列表 xListEnd 前面 */
} else
{
for( pxIterator = ( ListItem_t * ) &( pxList->xListEnd ); /*遍历列表中的列表项,找到插入的位置*/
pxIterator->pxNext->xItemValue <= xValueOfInsertion;
pxIterator = pxIterator->pxNext ) { }
}
pxNewListItem->pxNext = pxIterator->pxNext; /* 将待插入的列表项插入指定位置 */
pxNewListItem->pxNext->pxPrevious = pxNewListItem;
pxNewListItem->pxPrevious = pxIterator;
pxIterator->pxNext = pxNewListItem;
pxNewListItem->pxContainer = pxList; /* 更新待插入列表项所在列表 */
( pxList->uxNumberOfItems )++; /* 更新列表中列表项的数量 */
}
如下示例:一次插入列表项值为40,60,50的列表项:
④列表插入列表项(无序)函数vListInsertEnd()
用于将待插入列表的列表项插入到列表 pxIndex 指针指向的列表项前面,是一种无序的插入方法
void vListInsertEnd ( List_t * const pxList , ListItem_t * const pxNewListItem )
{
//省略部分非关键代码 … …
/* 获取列表 pxIndex 指向的列表项 */
ListItem_t * const pxIndex = pxList->pxIndex;
/* 更新待插入列表项的指针成员变量 */
pxNewListItem->pxNext = pxIndex;
pxNewListItem->pxPrevious = pxIndex->pxPrevious;
/* 更新列表中原本列表项的指针成员变量 */
pxIndex->pxPrevious->pxNext = pxNewListItem;
pxIndex->pxPrevious = pxNewListItem;
/* 更新待插入列表项的所在列表成员变量 */
pxNewListItem->pxContainer = pxList;
/* 更新列表中列表项的数量 */
( pxList->uxNumberOfItems )++;
}
假设初始列表pxIndex指向末尾列表,此时插入列表项值为30的列表项:
假设初始列表pxIndex指向值为40的列表项,此时插入列表项为30的列表项:
⑤移除列表项uxListRemove()函数
UBaseType_t uxListRemove( ListItem_t * const pxItemToRemove )
{
List_t * const pxList = pxItemToRemove->pxContainer;
//从列表中移除列表项(即更换被移除项前后两项的指针指向):
pxItemToRemove->pxNext->pxPrevious = pxItemToRemove->pxPrevious;
pxItemToRemove->pxPrevious->pxNext = pxItemToRemove->pxNext;
//如果pxIndex正指向待移除的列表项,需要将pxIndex指向待移除项的上一个列表项
if( pxList->pxIndex == pxItemToRemove )
{
pxList->pxIndex = pxItemToRemove->pxPrevious;
} else
{
mtCOVERAGE_TEST_MARKER();
}
//将待移除项所在的列表指针清空
pxItemToRemove->pxContainer = NULL;
//更新列表中列表项的数量
( pxList->uxNumberOfItems )--;
//返回移除后列表中列表项的数量
return pxList->uxNumberOfItems;
}
如下示例移除列表项2:
总结:
FreeRTOS是一个开源的实时操作系统,适用于低成本、低功耗的嵌入式系统。它具有高度可移植性和可扩展性,并支持多种处理器架构和编程语言! 广泛用于汽车电子中的实时控制系统,如发动机管理、制动系统、转向系统等。控制和监视工业自动化过程中的各个部分,如机器人和生产线。开发路由器、交换机、调制解调器和其他网络设备等通信设备。医疗设备需要快速响应并保持高度可靠性,因此FreeRTOS也在这个领域得到了广泛应用,如心脏起博器、血压计、呼吸机等。
往期精彩:
电机应用控制——直流无刷电机
OpenCV机器视觉系列专栏
C语言进阶