当前位置:网站首页>【实战】STM32MP157开发教程之FreeRTOS系统篇6:FreeRTOS 列表和列表项
【实战】STM32MP157开发教程之FreeRTOS系统篇6:FreeRTOS 列表和列表项
2022-06-21 09:09:00 【华清远见IT开放实验室】
1.写在前面:
本文章为《STM32MP157开发教程之FreeRTOS操作系统篇》系列中的一篇,笔者使用的开发平台为华清远见FS-MP1A开发板(STM32MP157开发板)。stm32mp157是ARM双核,2个A7核,1个M4核,A7核上可以跑Linux操作系统,M4核上可以跑FreeRTOS、RT-Thread等实时操作系统,STM32MP157开发板所以既可以学嵌入式linux,也可以学stm32单片机。
针对FS-MP1A开发板,除了FreeRTOS操作系统篇外,还包括其他多系列教程,包括Cortex-A7开发篇、Cortex-M4开发篇、扩展板驱动移植篇、Linux应用开发篇、Linux系统移植篇、Linux驱动开发篇、硬件设计篇、人工智能机器视觉篇、Qt应用编程篇、Qt综合项目实战篇等。欢迎关注,更多stm32mp157开发教程及视频,可加技术交流Q群459754978,感谢关注。
FS-MP1A开发板详情介绍:淘宝网 - 淘!我喜欢
2.FreeRTOS列表和列表项
2.1列表和列表项简介
学习FreeRTOS,肯定少不了列表和列表项,列表和列表项是FreeRTOS的一个数据结构,它是FreeRTOS的基石。
列表被用来跟踪FreeRTOS中的任务,在list.h文件中定义了列表结构体List_t如下
typedef struct xLIST
{
listFIRST_LIST_INTEGRITY_CHECK_VALUE
configLIST_VOLATILE UBaseType_t uxNumberOfItems;
ListItem_t * configLIST_VOLATILE pxIndex;
MiniListItem_t xListEnd;
listSECOND_LIST_INTEGRITY_CHECK_VALUE
} List_t;
第一行和第五行都是用来检查列表完整性,需要将宏
configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES设置为1。
uxNumberOfItems用来记录列表中列表项的数量。
pxIndex用来记录当前列表项索引号,用于遍历列表。
xListEnd表示列表中最后一个列表项,用来表示列表结束。
列表项就是存放在列表中的项目,其定义如下
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;
void * configLIST_VOLATILE pvContainer;
listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE
};
typedef struct xLIST_ITEM ListItem_t;
第一行和第七行同列表一样,都是用来检查列表项完整性。
xItemValue为列表项值。
pxNext指向下一个列表项。
pxPrevious指向前一个列表项,与pxNext相配合。
pvOwner记录此列表项归谁拥有,通常是任务控制块。
pvContainer用来记录此列表项归哪个列表。
另外还有一种迷你列表项,其定义如下
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;
第一行同样用于检查迷你列表项的完整性。
xItemValue记录列表项值。
pxNext指向下一个列表项。
pxPrevious指向前一个列表项。
在这里之所以弄个迷你列表项,是因为有些情况下,我们不需要列表项那么全的功能,可能只需要其中的某几个成员变量,此时用列表项的话可能会造成内存浪费。
2.2列表与列表项函数
2.2.1列表与列表项初始化
新创建或者定义的列表都需要对其做初始化处理,对列表的初始化函数为vListInitialise(),其函数原型如下:
void vListInitialise ( List* const pxList)
参数:
pxList: 要进行初始化的列表。
返回值:无
对列表项的初始化函数为vListInitialiseItem(),其函数原型如下:
void vListInitialiseItem ( ListItem_t * const pxItem)
参数:
pxItem: 要进行初始化的列表。
返回值:无
在此不对初始化函数的具体代码做描述了,有兴趣的可以去list.c文件中查看。
2.2.2 列表项插入
列表项的插入函数为vListInsert(),其函数原型如下:
void vListInsert( List* const pxList, ListItem_t * const pxNewListItem)
参数:
pxList: 列表项要插入的列表。
pxNewListItem: 要插入的列表项。
返回值:无
2.2.3列表项末尾插入
列表在末尾插入列表项的函数为vListInsertEnd(),其函数原型如下:
void vListInsertEnd( List * const pxList, ListItem_t * const pxNewListItem)
参数:
pxList: 列表项要插入的列表。
pxNewListItem: 要插入的列表项。
返回值:无
2.2.4 列表项删除
有插入那么必然有删除,列表项的删除函数为uxListRemove(),其函数原型如下:
UBaseType_t uxListRemove( ListItem_t * const pxItemToRemove )
参数:
pxItemToRemove: 要删除的列表项。
返回值:
返回删除列表项以后的列表剩余列表项数目。
列表项的删除只是将指定的列表项从列表中删除掉,并不会将列表项的内存给释放掉。
2.3操作实验
2.3.1实验设计
本次设计中创建了一个列表以及三个列表项,通过中断采集按键状态,当KEY1按下时,依次将三个列表项添加到列表中,当KEY2按下时,删除第2条列表项,当KEY3按下时,再将第2条列表项从末尾插入。
可参考12.3.2章节进行导入已有工程,工程存放路径【华清远见-FS-MP1A开发资料\02-程序源码\ARM体系结构与接口技术\FreeRTOS\7_MP1A-FreeRTOS-List】
任务及其功能如下:
StartTask02(): 进行列表与列表项的初始化并打印,然后采集按键状态,根据不同的按键结果进行不同处理。
StartDefaultTask(): 让LED3循环闪烁,提示系统正常运行。
2.3.2实验过程与分析
首先,根据之前几章内容配置好CubeMX,按照上一节配置“FREERTOS”,完成后生成代码。 在StartDefaultTask() 与StartTask02()中添加代码如下。
void StartDefaultTask(void *argument)
{
/* USER CODE BEGIN 5 */
/* Infinite loop */
for(;;)
{
LED_3_TOG();
osDelay(1000);
}
/* USER CODE END 5 */
}
void StartTask02(void *argument)
{
/* USER CODE BEGIN StartTask02 */
/* Infinite loop */
//初始化列表和列表项
vListInitialise(&TestList);
vListInitialiseItem(&ListItem1);
vListInitialiseItem(&ListItem2);
vListInitialiseItem(&ListItem3);
ListItem1.xItemValue=40; //ListItem1列表项值为40
ListItem2.xItemValue=60; //ListItem2列表项值为60
ListItem3.xItemValue=50; //ListItem3列表项值为50
//打印列表和其他列表项的地址
printf("project address \r\n");
printf("TestList %#x \r\n",(int)&TestList);
printf("TestList->pxIndex %#x \r\n",(int)TestList.pxIndex);
printf("TestList->xListEnd %#x \r\n",(int)(&TestList.xListEnd));
printf("ListItem1 %#x \r\n",(int)&ListItem1);
printf("ListItem2 %#x \r\n",(int)&ListItem2);
printf("ListItem3 %#x \r\n",(int)&ListItem3);
for(;;)
{
if(key == EVENTBIT_1)
{
//向列表TestList添加列表项ListItem1,并通过串口打印所有
//列表项中成员变量pxNext和pxPrevious的值,通过这两个值观察列表
//项在列表中的连接情况。
vListInsert(&TestList,&ListItem1); //插入列表项ListItem1
printf("project address \r\n");
printf("TestList->xListEnd->pxNext %#x \r\n",(int)(TestList.xListEnd.pxNext));
printf("ListItem1->pxNext %#x \r\n",(int)(ListItem1.pxNext));
printf("/***********Connect the divider front and back 1************/\r\n");
printf("TestList->xListEnd->pxPrevious %#x
\r\n",(int)(TestList.xListEnd.pxPrevious));
printf("ListItem1->pxPrevious %#x \r\n",(int)(ListItem1.pxPrevious));
printf("/**************************end****************************/\r\n");
//向列表TestList添加列表项ListItem2,并通过串口打印所有
//列表项中成员变量pxNext和pxPrevious的值,通过这两个值观察列表
//项在列表中的连接情况。
vListInsert(&TestList,&ListItem2); //插入列表项ListItem2
printf("project address \r\n");
printf("TestList->xListEnd->pxNext %#x \r\n",(int)(TestList.xListEnd.pxNext));
printf("ListItem1->pxNext %#x \r\n",(int)(ListItem1.pxNext));
printf("ListItem2->pxNext %#x \r\n",(int)(ListItem2.pxNext));
printf("/***********Connect the divider front and back 2************/\r\n");
printf("TestList->xListEnd->pxPrevious %#x\r\n",
(int)(TestList.xListEnd.pxPrevious));
printf("ListItem1->pxPrevious %#x \r\n",(int)(ListItem1.pxPrevious));
printf("ListItem2->pxPrevious %#x \r\n",(int)(ListItem2.pxPrevious));
printf("/***************************end*****************************/\r\n");
//向列表TestList添加列表项ListItem3,并通过串口打印所有
//列表项中成员变量pxNext和pxPrevious的值,通过这两个值观察列表
//项在列表中的连接情况。
vListInsert(&TestList,&ListItem3); //插入列表项ListItem3
printf("project address \r\n");
printf("TestList->xListEnd->pxNext %#x \r\n",(int)(TestList.xListEnd.pxNext));
printf("ListItem1->pxNext %#x \r\n",(int)(ListItem1.pxNext));
printf("ListItem3->pxNext %#x \r\n",(int)(ListItem3.pxNext));
printf("ListItem2->pxNext %#x \r\n",(int)(ListItem2.pxNext));
printf("/************Connect the divider front and back 3************/\r\n");
printf("TestList->xListEnd->pxPrevious %#x
\r\n",(int)(TestList.xListEnd.pxPrevious));
printf("ListItem1->pxPrevious %#x \r\n",(int)(ListItem1.pxPrevious));
printf("ListItem3->pxPrevious %#x \r\n",(int)(ListItem3.pxPrevious));
printf("ListItem2->pxPrevious %#x \r\n",(int)(ListItem2.pxPrevious));
printf("/***************************end*****************************/\r\n");
}
if(key == EVENTBIT_2)
{
//删除ListItem2,并通过串口打印所有列表项中成员变量pxNext和Previous的值,通过这两个值观察列表项在列表中的连接情况。
uxListRemove(&ListItem2); //删除ListItem2
printf("/**************Delete list items ListItem2*************/\r\n");
printf("project address \r\n");
printf("TestList->xListEnd->pxNext %#x \r\n",(int)(TestList.xListEnd.pxNext));
printf("ListItem1->pxNext %#x \r\n",(int)(ListItem1.pxNext));
printf("ListItem3->pxNext %#x \r\n",(int)(ListItem3.pxNext));
printf("/***********Connect the divider front and back 2************/\r\n");
printf("TestList->xListEnd->pxPrevious %#x
\r\n",(int)(TestList.xListEnd.pxPrevious));
printf("ListItem1->pxPrevious %#x \r\n",(int)(ListItem1.pxPrevious));
printf("ListItem3->pxPrevious %#x \r\n",(int)(ListItem3.pxPrevious));
printf("/*************************end****************************/\r\n");
}
if(key == EVENTBIT_3)
{
//末尾添加ListItem2,并通过串口打印所有列表项中成员变量pxNext和Previous的值,
//通过这两个值观察列表项在列表中的连接情况。
TestList.pxIndex=TestList.pxIndex->pxNext; //Index向后移一项,这样pxIndex就会指向ListItem1。
vListInsertEnd(&TestList,&ListItem2); //列表末尾添加列表项ListItem2
printf("/***********Add the list at the end of ListItem2***********/\r\n");
printf("project address \r\n");
printf("TestList->pxIndex %#x \r\n",(int)TestList.pxIndex);
printf("TestList->xListEnd->pxNext %#x
\r\n",(int)(TestList.xListEnd.pxNext));
printf("ListItem2->pxNext %#x \r\n",(int)(ListItem2.pxNext));
printf("ListItem1->pxNext %#x \r\n",(int)(ListItem1.pxNext));
printf("ListItem3->pxNext %#x \r\n",(int)(ListItem3.pxNext));
printf("/************Connect the divider front and back 2*************/\r\n");
printf("TestList->xListEnd->pxPrevious %#x
\r\n",(int)(TestList.xListEnd.pxPrevious));
printf("ListItem2->pxPrevious %#x \r\n",(int)(ListItem2.pxPrevious));
printf("ListItem1->pxPrevious %#x \r\n",(int)(ListItem1.pxPrevious));
printf("ListItem3->pxPrevious %#x \r\n",(int)(ListItem3.pxPrevious));
printf("/***************************end*****************************/\r\n");
}
key = 0;
osDelay(100);
}
/* USER CODE END StartTask02 */
}
编写按键中断回调函数如下
void HAL_GPIO_EXTI_Rising_Callback(uint16_t GPIO_Pin)
{
switch(GPIO_Pin)
{
case GPIO_PIN_8:
if(HAL_GPIO_ReadPin(GPIOF,GPIO_PIN_8) == GPIO_PIN_SET) /* read KEY3 PF8 state */
key = EVENTBIT_3;
break;
case GPIO_PIN_7:
if(HAL_GPIO_ReadPin(GPIOF,GPIO_PIN_7) == GPIO_PIN_SET) /* read KEY2 PF7 state */
key = EVENTBIT_2;
break;
case GPIO_PIN_9:
if(HAL_GPIO_ReadPin(GPIOF,GPIO_PIN_9) == GPIO_PIN_SET) /* read KEY1 PF9 state */
key = EVENTBIT_1;
break;
}
}
烧录程序以后,打开串口,可以发现显示内容如下

当按下KEY1键时,将列表项添加到列表中,串口显示如下

当KEY2键按下时,删除第2条列表项,剩余结果如下

此时按下KEY3键,将第2条列表项从末尾插入,最终结果如下

硬件平台:华清远见FS-MP1A开发板(STM32MP157)
部分开发教程下载:加QQ群459754978,群文件里有。
部分视频课程收看:
https://space.bilibili.com/670826565/channel/detail?cid=145472
淘宝购买链接:
https://item.taobao.com/item.htm?id=622457259672
手机淘宝分享码:复制本行文字打开手淘₤T4FPXn3YYJ2₤
边栏推荐
- Understanding and use of advanced pointer
- Unity的网络请求_短连接
- 微信小程序
- [JUC series] completionservice of executor framework
- leetcode:19. Delete the penultimate node of the linked list
- 【活动早知道】LiveVideoStack近期活动一览
- The difference between tuples and lists
- Retrofit extended reading
- Can you implement these requirements with MySQL
- Ads Filter Design Wizard tool 2
猜你喜欢

Wechat applet

Unity 5 自带的Mono也可以支持C# 6

Abstractqueuedsynchronizer (AQS) source code detailed analysis - semaphore source code analysis

Zhihu wanzan: what kind of programmers are still wanted by the company after the age of 35? Breaking the "middle age crisis" of programmers

Alibaba P6 employees came to a small company for an interview and asked for an annual salary increase of 500000 yuan. How dare you speak

What should I do if a white page appears during MySQL installation

【VS】【使用问题】【解决方案】VS2010打开一直停留在启动界面

PingCAP 入选 2022 Gartner 云数据库“客户之声”,获评“卓越表现者”最高分

window10局域网共享文件夹流程

How to connect the Internet - FTTH
随机推荐
Talking about Festinger effect
R language ggplot2 visualization, draw two lines in the same ggplot2 graph in a graph, and use postscript function to save the visualization image to PS format file in the specified directory
Figure out how MySQL works
Summary of problems and errors encountered in tidb4.0.0 (tiup deployment)
Unity Detailed explanation of meta file function
apk 反编译 上的填坑之路
Is it safe to open a stock account at present? Can I open an account online directly?
南京理工大学MOOC慕课:程序设计基础(Ⅰ)第8章测试选择题答案及解析
Observation on the salary data of the post-90s: poor, counselled and serious
【MGT】代码解读之model-MGT
Character function and string function
MOOC course of Nanjing University of Technology: Fundamentals of program design (Ⅰ) Chapter 8 answer and analysis of multiple choice test questions
Dumping backup database
Binary search (non recursive, no repeating elements)
Abstractqueuedsynchronizer (AQS) source code detailed analysis - semaphore source code analysis
The next stop of Intelligent Manufacturing: cloud native + edge computing two wheel drive
Retrofit Extended reading
一条命令开启监控之旅!
\Processing method of ufeff
Quick sort_ sort