赞
踩
这是一个自我学习FreeRTOS的过程,目的是总结学习中所学到的操作和分享,最重要的是为自己DIY一个stm32平衡小车做铺垫。第一次写博客如果有错误求指出啊哈哈哈。
FreeRTOS是一个免费开源的实时操作系统,我们很容易的对其进行移植并且运用在我们项目之中。话不多说,我们一起先创建一个FreeRTOS的工程吧。
首先我们创建一个总FreeRTOS的文件夹在任意位置中(名字随便起哈哈哈别数字或者中文就可以了,因为keil识别不了中文或数字开头,否则后期会一直报错的哈哈哈,文件名切记要!!!)。
接下来我们在其内创建4个子文件夹分别如下:
Doc为说明文档,freertos中包含着include和protabel,project用来放置keil的工程,User为用户文件夹,主要用于放置main.c。
用哪个芯片就拷贝哪个芯片的RVDS进去即可(M3、M4),此处用ARM-CM3
这样我们的FreeRTOS的基本框架就创建好了。
新建工程并且保存在freertos的project中并且选着芯片M3
勾选上这两个选项哟!!!
然后我们在Keil上创建工程分组
然后打开文件夹在User中新建main.c文件夹(一定要把后缀改为.c!!!!!!)
并且把main.c添加到工程中,右键分组user,Add File to Group 。
并且先给 main函数写个空循环吧,防止后续检查问题时一直报错!!
keil需要配置芯片的时钟!!! 不同的芯片时钟的要求不一致,打开ARMCM3.c文件就可以看到其对时钟的要求!!!
系统时钟SYSTEM—CLOCK=XTAL/2=25MHZ(M3),顺便配置一下keil吧
然后我们需要添加一下头文件的路径
这样我们一个FreeRTOS的keil才算是设置好,接下来可以开始我们最重要的构建链表的操作啦!!
这就是单向链表的原理图,在此不多解释了,大伙们可以去看看数据结构这本书或者是网课!!(没有数据结构的基础是学不好操作系统的哟!!后续如果有时间我会再写一篇有关于这方面数据结构的文章)
FreeRTOS中与链表相关的操作均在list.h和list.c这两个文件中实现
首先我们要创建list.h和list.c。
新建list.c在freeRTOS中
同理创建list.h在include下并将其添加进去工程分组的FreeRTOS/Source中。
移植并且添加进去FreeRTOS/Source
具体的文件可以去野火官网或者是FreeRTOS官网下载哟!!FreeRTOS - Market leading RTOS (Real Time Operating System) for embedded systems with Internet of Things extensions
实现节点的初始化(原理)
链表节点的数据结构在list.h中定义
- struct xLIST_ITEM
- {
- TickType_t xItemValue;
- struct xLIST_ITEM * pxNext; /* 辅助值,用于帮助节点做顺序排列 */
- struct xLIST_ITEM * pxPrevious; /* 指向链表下一个节点 */
- void * pvOwner; /* 指向链表前一个节点 */
- void * pvContainer; /* 指向拥有该节点的内核对象,通常是TCB */
- };
- typedef struct xLIST_ITEM ListItem_t; /* 节点数据类型重定义 */
链表根节点的数据结构在list.h中定义。
- typedef struct xLIST
- {
- UBaseType_t uxNumberOfItems; /*链表节点计数器*/
- ListItem_t * pxIndex; /*链表节点索引指针*/
- MiniListItem_t xListEnd; /*链表最后一个索引*/
- }List_t
链表节点的初始化在list.c中实现:vListInitialiseItem()
-
- void vListInitialiseItem( ListItem_t * const pxItem )
- {
- /* 初始化该节点所在的链表为空,表示节点还没有插入任何链表 */
- pxItem->pvContainer = NULL ;
- }
链表根节点的初始化在list.c中实现:vListInitialise()。
-
- void vListInitialise( List_t *const pxList)
- {
- /* 将链表索引指针指向最后一个节点 */
- pxList->pxIndex = (ListItem_t *)&pxList->xListEnd;
- /* 将链表最后一个节点的辅助排序的值设置为最大,确保该节点就是链表的最后节点 */
- pxList ->xListEnd.xItemValue = portMAX_DELAY;
- /* 将最后一个节点的pxNext和pxPrevious指针均指向节点自身,表示链表为空 */
- pxList ->xListEnd.pxPrevious= (ListItem_t *)&( pxList ->xListEnd);
- pxList ->xListEnd.pxNext=(ListItem_t *)&( pxList ->xListEnd);
- /* 初始化链表节点计数器的值为0,表示链表为空 */
- pxList->uxNumberOfItems = ( UBaseType_t ) 0U;
-
- }
为了便于分别双向链表的结尾定义多一个结构体mini节点,作为双向链表的结尾。(双向链表是首尾相连的,头即是尾,尾即是头)
- struct xMINI_LIST_ITEM
- {
- TickType_t xItemValue; /* 辅助值,用于帮助节点做升序排列 */
- struct xLIST_ITEM * pxNext; /* 指向链表下一个节点 */
- struct xLIST_ITEM * pxPrevious; /* 指向链表前一个节点 */
- };
- typedef struct xMINI_LIST_ITEM MiniListItem_t; /* 最小节点数据类型重定义 */
然后我们需要有插入节点的操作均在list.c中实现:分别为:将节点插入到链表的尾部、将节点按照升序排列插入到链表、将节点从链表中删除 这三个操作。
将节点插入到链表的尾部:
- void vListInsertEnd( List_t * const pxList, ListItem_t * const pxNewListItem ) //两个参数(插入的链表,新的节点)
- {
- ListItem_t * const pxIndex = pxList->pxIndex; //定义一个索引指向链表的End
-
- pxNewListItem->pxNext = pxIndex; //第一步;将新节点的Next指向End
- pxNewListItem->pxPrevious = pxIndex->pxPrevious; //第二部;将新节点的Previous指向原来End的上一个
- pxIndex->pxPrevious->pxNext = pxNewListItem; //第三步;将原本End上一个的Next指向新节点
- pxIndex->pxPrevious = pxNewListItem; //第四步;将End的Previous指向新节点
-
- /* 记住该节点所在的链表 */
- pxNewListItem->pvContainer =( void * ) pxList;
-
- /* 链表节点计数器++ */
- ( pxList->uxNumberOfItems )++;
- }
将节点按照升序排列插入到链表:
- void vListInsert( List_t * const pxList, ListItem_t * const pxNewListItem ) //两个参数(插入的链表,新的节点)
- {
- ListItem_t *pxIterator;
-
- /* 获取节点的排序辅助值 */
- const TickType_t xValueOfInsertion = pxNewListItem->xItemValue;
-
- /* 寻找节点要插入的位置 */
- 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 )++;
- }
将节点从链表中删除:
- /* 将节点从链表中删除 */
- 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;
-
- /* Make sure the index is left pointing to a valid item. */
- if( pxList->pxIndex == pxItemToRemove )
- {
- pxList->pxIndex = pxItemToRemove->pxPrevious;
- }
-
- /* 初始化该节点所在的链表为空,表示节点还没有插入任何链表 */
- pxItemToRemove->pvContainer = NULL;
-
- /* 链表节点计数器-- */
- ( pxList->uxNumberOfItems )--;
-
- /* 返回链表中剩余节点的个数 */
- return pxList->uxNumberOfItems;
- }
这样我们就可以实现链表的创建和操作啦,注意list.c中需要引用头文件: "FreeRTOS.h"
和 <stdlib.h>和"list.h"!!!!!list.h需要引用头文件"FreeRTOS.h"。
那接下来我们就在main()创建一个有三个节点的链表吧。
首先先定义一个根节点、然后再定义三个节点。
再分别对根节点和三个节点进行初始化
最后再对其进行排序插入节点。
- #include "list.h"
- /*1.定义一个根节点*/
- struct xLIST List_Text;
-
- /*2.定义3个节点*/
- struct xLIST_ITEM List_Item1;
- struct xLIST_ITEM List_Item2;
- struct xLIST_ITEM List_Item3;
-
- int main(void)
- { /*3.根节点初始化*/
- vListInitialise(&List_Text);
-
- /*节点初始化*/
- vListInitialiseItem(&List_Item1);
- vListInitialiseItem(&List_Item2);
- vListInitialiseItem(&List_Item3);
-
- /*插入节点*/
- vListInsert(&List_Text,&List_Item1);
- vListInsert(&List_Text,&List_Item2);
- vListInsert(&List_Text,&List_Item3);
-
-
- for(;;)
- {
- //空
- }
- }
最后debug看看是否符合预期,要run一下!!!
最后结构正确,各节点指针指向符合双向链表预期!!本章就到这啦,如果有错请指出哟!!!如果我的学习过程可以帮到你就最好啦!!别忘记点赞哟!!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。