FreeRTOS列表和列表项

2023-05-16

本文是《ALIENTEK STM32F429 FreeRTOS 开发教程》第七章学习笔记
第一章笔记–FreeRTOS简介与源码下载
第二章笔记–FreeRTOS在STM32F4上移植
第三章笔记-FreeRTOS系统配置
第四章笔记-FreeRTOS中断分析
第四章笔记补充-FreeRTOS临界段代码
第五章笔记-FreeRTOS任务基础
第六章笔记-FreeRTOS任务API函数的使用

1. 列表和列表项的简介

1.1 列表

列表是FreeRTOS中的一个数据结构,概念与链表有些类似,列表被用来跟踪FreeRTOS中的任务。与列表相关的全部代码在文件list.c和list.h中。

list.h中定义了结构体List_t:

typedef struct xLIST
{
    listFIRST_LIST_INTEGRITY_CHECK_VALUE                /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
    configLIST_VOLATILE UBaseType_t uxNumberOfItems;
    ListItem_t * configLIST_VOLATILE pxIndex;           /*< Used to walk through the list.  Points to the last item returned by a call to listGET_OWNER_OF_NEXT_ENTRY (). */
    MiniListItem_t xListEnd;                            /*< List item that contains the maximum possible item value meaning it is always at the end of the list and is therefore used as a marker. */
    listSECOND_LIST_INTEGRITY_CHECK_VALUE               /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
} List_t;

listFIRST_LIST_INTEGRITY_CHECK_VALUE和listSECOND_LIST_INTEGRITY_CHECK_VALUE:用来检查列表的完整性,需要将宏configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES设置为1,默认不开启

#if( configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES == 0 )
    #define listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE


#else
    #define listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE               TickType_t xListItemIntegrityValue1;
    #define listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE              TickType_t xListItemIntegrityValue2;

    #define listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem )     ( pxItem )->xListItemIntegrityValue1 = pdINTEGRITY_CHECK_VALUE
    #define listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem )    ( pxItem )->xListItemIntegrityValue2 = pdINTEGRITY_CHECK_VALUE

uxNumberOfItems: 用来记录列表中的列表项的数量

pxIndex: 用于遍历链表,指向由listGET_OWNER_OF_NEXT_ENTRY()函数返回的列表项

xListEnd: 指向列表最后一个列表项,变量类型为MiniListItem_t

1.2 列表项

FreeRTOS提供了两种列表项:列表项和迷你列表项

1.2.1 列表项

struct xLIST_ITEM
{
    listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE           /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
    configLIST_VOLATILE TickType_t xItemValue;          /*< The value being listed.  In most cases this is used to sort the list in descending order. */
    struct xLIST_ITEM * configLIST_VOLATILE pxNext;     /*< Pointer to the next ListItem_t in the list. */
    struct xLIST_ITEM * configLIST_VOLATILE pxPrevious; /*< Pointer to the previous ListItem_t in the list. */
    void * pvOwner;                                     /*< Pointer to the object (normally a TCB) that contains the list item.  There is therefore a two way link between the object containing the list item and the list item itself. */
    void * configLIST_VOLATILE pvContainer;             /*< Pointer to the list in which this list item is placed (if any). */
    listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE          /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
};
typedef struct xLIST_ITEM ListItem_t;                   /* For some reason lint wants this as two separate definitions. */

listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE 和 listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE: 检查列表项完整性

xItemValue:列表项值

pxNext:指向下一个列表项

pxPrevious:指向前一列表项,与pxNext配合实现类似双向链表功能

pvOwner:记录此列表项归谁拥有,通常是任务控制块

pvContainer:用来记录此列表项归哪个列表

1.2.2 迷你列表项

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;
};
typedef struct xMINI_LIST_ITEM MiniListItem_t;

listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE:用来检查迷你列表项的完整性

xItemValue:记录列表列表项值

pxNext:指向下一个列表项

pxPrevious:指向前一列表项

有些情况下不需要列表项这么全的功能,用列表项会浪费内存,所以定义迷你列表项

2. 相关API函数

2.1 列表初始化

函数vListInitialise()完成新创建或定义的列表。列表初始化即初始化列表结构体List_t中各个成员变量。

void vListInitialise( List_t * const pxList )
{
    pxList->pxIndex = ( ListItem_t * ) &( pxList->xListEnd );           
    pxList->xListEnd.xItemValue = portMAX_DELAY;
    pxList->xListEnd.pxNext = ( ListItem_t * ) &( pxList->xListEnd );   
    pxList->xListEnd.pxPrevious = ( ListItem_t * ) &( pxList->xListEnd );
    pxList->uxNumberOfItems = ( UBaseType_t ) 0U;
    listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList );
    listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList );
}

pxList->pxIndex = ( ListItem_t * ) &( pxList->xListEnd ):pxIndex指向每遍历一下最后指向的列表项,当前列表只有一个列表项,是xListEnd,所以pxIndex指向xListEnd

pxList->xListEnd.xItemValue = portMAX_DELAY :xListEnd的列表项值初始化为portMAX_DELAY,通过相关代码可以看到portMAX_DELAY的值可以为0xffff或0xffffffffUL,在FreeRTOS.h中宏定义的configUSE_16_BIT_TICKS确定portMAX_DELAY的值

#define configUSE_16_BIT_TICKS                  0 
#if( configUSE_16_BIT_TICKS == 1 )
    typedef uint16_t TickType_t;
    #define portMAX_DELAY ( TickType_t ) 0xffff
#else
    typedef uint32_t TickType_t;
    #define portMAX_DELAY ( TickType_t ) 0xffffffffUL

pxList->xListEnd.pxNext = ( ListItem_t * ) &( pxList->xListEnd ):初始化列表项xListEnd的pxNext变量,因为只有一个列表项xListEnd,因此pxNext只能指向自身

pxList->xListEnd.pxPrevious = ( ListItem_t * ) &( pxList->xListEnd ):初始化列表项xListEnd的pxPrevious变量,因为只有一个列表项xListEnd,因此pxNext只能指向自身

pxList->uxNumberOfItems = ( UBaseType_t ) 0U:标记列表项个数为0,可以看出不算xListEnd

listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList )和listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList ):初始化列表项里用来检查完整性的变量,根据相关代码可以看到当宏configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES为1时有效,根据不同MCU配置相应的宏configUSE_16_BIT_TICKS值为0x5a5a(16位MCU)或0x5a5a5a5aUL(32位MCU)

#if( configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES == 0 )
    #define listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList )
    #define listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList )
#else
    #define listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList )  ( pxList )->xListIntegrityValue1 = pdINTEGRITY_CHECK_VALUE
    #define listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList )  ( pxList )->xListIntegrityValue2 = pdINTEGRITY_CHECK_VALUE

#if( configUSE_16_BIT_TICKS == 1 )
    #define pdINTEGRITY_CHECK_VALUE 0x5a5a
#else
    #define pdINTEGRITY_CHECK_VALUE 0x5a5a5a5aUL

列表初始化完成后:
这里写图片描述

2.2 列表项初始化

函数vListInitialiseItem()完成列表项初始化

void vListInitialiseItem( ListItem_t * const pxItem )
{
    pxItem->pvContainer = NULL;
    listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem );
    listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem );
}

列表项初始化,只将成员变量pvContainer初始化为NULL,并且给用于完整性检查的变量赋值。

列表项根据实际使用情况来初始化,所以其初始化函数很短。

2.3 列表项插入

通过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;
    }
    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->pvContainer = ( void * ) pxList;
    ( pxList->uxNumberOfItems )++;
}

参数: pxList:列表项要插入的列表;pxNewListItem:要插入的列表项

const TickType_t xValueOfInsertion=pxNewListItem->xItemValue:获取要插入列表项值(列表项成员变量xItemValue的值),根据这个值来确定列表项要插入的位置

listTEST_LIST_INTEGRITY( pxList )和listTEST_LIST_ITEM_INTEGRITY( pxNewListItem ):检查列表和列表项完整性,通过相关源代码可以看出实现检查完整性代码需要实现断言函数configASSERT()

#if( configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES == 0 )
    #define listTEST_LIST_ITEM_INTEGRITY( pxItem )
    #define listTEST_LIST_INTEGRITY( pxList )
#else
    #define listTEST_LIST_ITEM_INTEGRITY( pxItem )  configASSERT( ( ( pxItem )->xListItemIntegrityValue1 == pdINTEGRITY_CHECK_VALUE ) && ( ( pxItem )->xListItemIntegrityValue2 == pdINTEGRITY_CHECK_VALUE ) )
    #define listTEST_LIST_INTEGRITY( pxList )       configASSERT( ( ( pxList )->xListIntegrityValue1 == pdINTEGRITY_CHECK_VALUE ) && ( ( pxList )->xListIntegrityValue2 == pdINTEGRITY_CHECK_VALUE ) )

#define vAssertCalled(char,int) printf("Error:%s,%d\r\n",char,int)
#define configASSERT(x) if((x)==0) vAssertCalled(__FILE__,__LINE__)

if( xValueOfInsertion == portMAX_DELAY ):获取列表项插入到什么位置,如果插入列表项的值等于portMAX_DELAY,即列表项值为最大值,此时插入的位置为列表最末尾

pxIterator = pxList->xListEnd.pxPrevious:获取要插入点,列表中xListEnd表示列表末尾,初始化列表时xListEnd的列表值也是portMAX_DELAY,尽管两个值一样,但是要把插入的列表项放在xListEnd前面

for( pxIterator = ( ListItem_t * ) &( pxList->xListEnd ); pxIterator->pxNext->xItemValue <= xValueOfInsertion; pxIterator = pxIterator->pxNext ) :如果列表项的值不等于portMAX_DELAY那么就需要在列表中遍历,寻找插入位置,用for循环遍历列表寻找插入点

插入代码:

pxNewListItem->pxNext = pxIterator->pxNext;
pxNewListItem->pxNext->pxPrevious = pxNewListItem;
pxNewListItem->pxPrevious = pxIterator;
pxIterator->pxNext = pxNewListItem;

插入代码用来把要插入的列表项插入到列表当中(找到升序中的比他大的列表项的前一列表项的后面)

pxNewListItem->pvContainer = ( void * ) pxList:插入后,列表项成员变量pvContainer记录此列表项属于哪个列表

pxList->uxNumberOfItems:列表成员数量加1

2.4 列表项末尾插入

通过vListInsertEnd()函数完成列表项末尾的插入

void vListInsertEnd( List_t * const pxList, ListItem_t * const pxNewListItem )
{
    ListItem_t * const pxIndex = pxList->pxIndex;
    listTEST_LIST_INTEGRITY( pxList );
    listTEST_LIST_ITEM_INTEGRITY( pxNewListItem );
    pxNewListItem->pxNext = pxIndex;
    pxNewListItem->pxPrevious = pxIndex->pxPrevious;
    mtCOVERAGE_TEST_DELAY();
    pxIndex->pxPrevious->pxNext = pxNewListItem;
    pxIndex->pxPrevious = pxNewListItem;
    pxNewListItem->pvContainer = ( void * ) pxList;
    ( pxList->uxNumberOfItems )++;
}

参数:pxList:列表项要插入的列表;pxNewListItem:要插入的列表项

listTEST_LIST_INTEGRITY( pxList )和listTEST_LIST_ITEM_INTEGRITY( pxNewListItem ):先进行列表和列表项的完整性检查

pxNewListItem->pxNext = pxIndex;
pxNewListItem->pxPrevious = pxIndex->pxPrevious;
mtCOVERAGE_TEST_DELAY();
pxIndex->pxPrevious->pxNext = pxNewListItem;
pxIndex->pxPrevious = pxNewListItem;

将要插入的列表项插入到列表末尾,列表末尾指的是pxIndex所指向的列表项的前面(列表中pxIndex成员变量用来遍历列表,pxIndex所指向的列表项就是要遍历的开始列表项)

pxNewListItem->pvContainer = ( void * ) pxList:标记新列表项pxNewListItem属于列表pxList

( pxList->uxNumberOfItems )++:列表中的列表项数目加一

2.5 列表项的删除

通过uxListRemove()函数完成列表项插入

UBaseType_t uxListRemove( ListItem_t * const pxItemToRemove )
{
    List_t * const pxList = ( List_t * ) pxItemToRemove->pvContainer;
    pxItemToRemove->pxNext->pxPrevious = pxItemToRemove->pxPrevious;
    pxItemToRemove->pxPrevious->pxNext = pxItemToRemove->pxNext;
    mtCOVERAGE_TEST_DELAY();
    if( pxList->pxIndex == pxItemToRemove )
    {
        pxList->pxIndex = pxItemToRemove->pxPrevious;
    }
    else
    {
        mtCOVERAGE_TEST_MARKER();
    }
    pxItemToRemove->pvContainer = NULL;
    ( pxList->uxNumberOfItems )--;
    return pxList->uxNumberOfItems;
}

参数:pxItemToRemove:要删除的列表项

List_t * const pxList = ( List_t * ) pxItemToRemove->pvContainer:读出要删除列表项的成员变量pvContainer得到此列表项处于哪个列表

pxItemToRemove->pxNext->pxPrevious = pxItemToRemove->pxPrevious 和 pxItemToRemove->pxPrevious->pxNext = pxItemToRemove->pxNext:将要删除列表项的前后列表项”连接”起来

if( pxList->pxIndex == pxItemToRemove ){pxList->pxIndex = pxItemToRemove->pxPrevious;}:如果列表的pxIndex正好指向要删除的列表项,则pxIndex指向被删除列表项前一列表项

pxItemToRemove->pvContainer = NULL:删除的成员变量pvContainer清零

( pxList->uxNumberOfItems )–:列表中列表项数目减一

2.6 列表的遍历

列表的遍历使用listGET_OWNER_OF_NEXT_ENTRY()函数,本质上是一个宏

#define listGET_OWNER_OF_NEXT_ENTRY( pxTCB, pxList )                                        
{                                       
    List_t * const pxConstList = ( pxList );
    ( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext;                            
    if( ( void * ) ( pxConstList )->pxIndex == ( void * ) &( ( pxConstList )->xListEnd ) )  
    {                                           
        ( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext;                        
    }                                           
    ( pxTCB ) = ( pxConstList )->pxIndex->pvOwner;                                          
}

参数:pxTCB:保存pxIndex所指向的列表项的pvOwner变量值,通常是一个任务的任务控制块;pxList:表示要遍历的列表

( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext:列表的pxIndex变量指向下一个列表项

if( ( void * ) ( pxConstList )->pxIndex == ( void * ) &( ( pxConstList)->xListEnd){(pxConstList)->pxIndex = (pxConstList)->pxIndex->pxNext;}:如果成员变量pxIndex指向了列表的xListEnd成员变量,则跳过xListEnd,重新指向处于列表头的列表项即完成了对列表的遍历

( pxTCB ) = ( pxConstList )->pxIndex->pvOwner:将pxIndex所指向新列表项的pvOwner赋值给pxTCB

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

FreeRTOS列表和列表项 的相关文章

随机推荐

  • windows10家庭版安装docker踩坑

    目录 前提条件 排错1 xff1a 下载并运行安装程序 排错2 xff1a 排错3 xff1a 注意点 xff1a 运行docker 配置镜像加速 xff1a 测试下吧 成功安装 前提条件 需要Windows功能 xff1a Hyper V
  • XML文件解析

    void DomXml parseXml QDomDocument document 声明QDomDocument document setContent amp xml 初始化QDomDocument 文档结构 QDomElement r
  • ROS安装指令集合(快速安装+简易原理教程)

    很多刚装了Ubuntu的工控机上ROS官网很慢 xff0c 而且mirror不好找 xff0c 所以我把安装ROS的指令都放了进来 xff0c 一条一条复制即可 加载中科大镜像 xff1a sudo sh c 39 etc lsb rele
  • 蓝桥杯 嵌入式设计与开发项目 历届 客观题

    蓝桥杯嵌入式各届客观题 xff0c 包含省赛第八至十三届 xff0c 决赛第十 十一届 第十三届 部分题目为本人自己做的 xff0c 非标准答案 xff0c 仅供参考 注 xff1a 大学组客观题为10道 xff0c 研究生组客观题为15道
  • 输入rostopic echo /scan 报错:Segmentation fault (core dumped)[gazebo-2] process has died

    问题背景 xff1a 在gazebo中用rplidar实现gampping算法时 xff0c 一旦输入rostopic echo scan xff0c 就会报错 xff0c 错误 xff1a Segmentation fault core
  • C# 注释详解

    一 二 三 是智能注释也称xml注释 xff0c 会在被编译 xff0c 并生成xml文件在可执行文件中 会影响编译速度 xff0c 但不会影响代码执行速度 一级注释 xff1a 1 lt remarks gt 对类型进行描述 xff0c
  • STM32控制HC-05蓝牙模块进行通信

    一 HC 05蓝牙模块 1 简介 HC 05主从一体蓝牙串口模块采用英国CSR公司BlueCore4系列的芯片 xff0c 符合符合蓝牙2 0 43 EDR规范 xff0c 可以同带同种蓝牙功能的电脑 蓝牙主机和手机等智能终端配对 2 主要
  • 51单片机PWM的控制(呼吸灯)

    一 PWM Pulse Width Modulation脉冲宽度调制 xff0c 简称PWM PWM 脉冲宽度调制 对模拟信号电平进行数字编码的方法 xff0c 计算机只能输出0或5V的数字电压值而不能输出模拟电压 xff0c 而我们如果想
  • STM32用SPI方式控制OLED模块

    一 OLED 1 OLED模块的外观 2 OLED模块的电路图 3 OLED模块参数 项目说明接口特性3 3V 串电阻后 xff0c 可与 5V 系统连接 通信接口4 线 SPI屏幕分辨率128 64屏幕尺寸0 96 寸工作温度 40 70
  • STM32上使用UCOSII--消息队列和信号量集

    有关UCOS任务的介绍 xff1a STM32上使用UCOSII 任务 有关UCOS信号量和邮箱的介绍 xff1a STM32上使用UCOSII 信号量和邮箱 一 消息队列 使用消息队列可以在任务之间传递多条消息 消息队列由三个部分组成 x
  • PID控制算法+倒立摆控制应用

    一 位式控制算法 传统的控制算法采用位式控制算法 特点 位式控制算法输出信号只有H L两种状态算法输出信号OUT的依据 xff1a span class hljs comment 二位式 span span class hljs comme
  • 调整 mysql policy requirements

    Error xff1a mysql gt CREATE USER 39 tester 39 64 39 39 IDENTIFIED BY 39 password 39 ERROR 1819 HY000 Your password does
  • FreeRTOS简介与源码下载

    RTOS系统 实时操作系统 RTOS全称 Real Time OS 实时操作系统 xff0c 强调实时性 实时操作系统分为硬实时和软实时 硬实时要求在规定的时间内必须完成操作 xff0c 不允许超时 xff1b 软实时则没有那么严格 xff
  • FreeRTOS在STM32F4上移植

    本文是 ALIENTEK STM32F429 FreeRTOS 开发教程 第二章学习笔记 第一章笔记 FreeRTOS简介与源码下载 一 移植 1 准备工程文件 MCU用的是STM32F429的CORE xff0c 用keli创建一个基础工
  • FreeRTOS系统配置

    本文是 ALIENTEK STM32F429 FreeRTOS 开发教程 第三章学习笔记 第一章笔记 FreeRTOS简介与源码下载 第二章笔记 FreeRTOS在STM32F4上移植 FreeRTOSConfig h FreeRTOS的配
  • FreeRTOS中断分析

    本文是 ALIENTEK STM32F429 FreeRTOS 开发教程 第四章学习笔记 第一章笔记 FreeRTOS简介与源码下载 第二章笔记 FreeRTOS在STM32F4上移植 第三章笔记 FreeRTOS系统配置 一 Cortex
  • FreeRTOS临界段代码

    本文是 ALIENTEK STM32F429 FreeRTOS 开发教程 第四章学习笔记的补充 第一章笔记 FreeRTOS简介与源码下载 第二章笔记 FreeRTOS在STM32F4上移植 第三章笔记 FreeRTOS系统配置 第四章笔记
  • FreeRTOS任务基础

    本文是 ALIENTEK STM32F429 FreeRTOS 开发教程 第五章学习笔记 第一章笔记 FreeRTOS简介与源码下载 第二章笔记 FreeRTOS在STM32F4上移植 第三章笔记 FreeRTOS系统配置 第四章笔记 Fr
  • FreeRTOS任务API函数的使用

    这篇文章最后的demo工程可以在网盘中自行下载 xff1a 链接 xff1a https pan baidu com s 1o1U niMKu0RuDAFio1nKMA 密码 xff1a ysev 本文是 ALIENTEK STM32F42
  • FreeRTOS列表和列表项

    本文是 ALIENTEK STM32F429 FreeRTOS 开发教程 第七章学习笔记 第一章笔记 FreeRTOS简介与源码下载 第二章笔记 FreeRTOS在STM32F4上移植 第三章笔记 FreeRTOS系统配置 第四章笔记 Fr