当前位置:   article > 正文

FreeRTOS的学习—新建FreeRTOS工程及创建简易链表_freertos 编译框架

freertos 编译框架

 

这是一个自我学习FreeRTOS的过程,目的是总结学习中所学到的操作和分享,最重要的是为自己DIY一个stm32平衡小车做铺垫。第一次写博客如果有错误求指出啊哈哈哈。

FreeRTOS是一个免费开源的实时操作系统,我们很容易的对其进行移植并且运用在我们项目之中。话不多说,我们一起先创建一个FreeRTOS的工程吧。

一、我们先要创建一个基本的FreeRTOS的框架—创建FreeRTOS的文件夹

首先我们创建一个总FreeRTOS的文件夹在任意位置中(名字随便起哈哈哈别数字或者中文就可以了,因为keil识别不了中文或数字开头,否则后期会一直报错的哈哈哈,文件名切记要!!!)。

04293d37d3e941de9128dee3d8dd2db7.png

接下来我们在其内创建4个子文件夹分别如下:

b78d900296b448e7afdb9bfcb20570fb.png

 Doc为说明文档,freertos中包含着include和protabel,project用来放置keil的工程,User为用户文件夹,主要用于放置main.c。 

f888401d01154910b8ea4ec403aa7726.png

6421424d9caa41ae97833224c69e1e93.png

 用哪个芯片就拷贝哪个芯片的RVDS进去即可(M3、M4),此处用ARM-CM3

b804b8f0d8ac43d883376d61a6725a6e.png

 这样我们的FreeRTOS的基本框架就创建好了。

二、打开keil,新建工程并且保存在freertos的project中并且选着芯片M3

新建工程并且保存在freertos的project中并且选着芯片M3

13e28843abf446839fd081fb2f7fe303.png

勾选上这两个选项哟!!!

然后我们在Keil上创建工程分组

3db6c0d7415d4cec874f82e8fa6d1f34.png

然后打开文件夹在User中新建main.c文件夹(一定要把后缀改为.c!!!!!!)

d1e2359c63d1463f90a71ceb27cfbd78.png

并且把main.c添加到工程中,右键分组user,Add File to Group 。

 86674e47a72741e39fd98922575eb53f.png

并且先给 main函数写个空循环吧,防止后续检查问题时一直报错!!

da4cbab2a5e5445e9bd453383f87973c.png

keil需要配置芯片的时钟!!! 不同的芯片时钟的要求不一致,打开ARMCM3.c文件就可以看到其对时钟的要求!!!

17a4d0a0c296413a9e99ea9b236c95bb.png

系统时钟SYSTEM—CLOCK=XTAL/2=25MHZ(M3),顺便配置一下keil吧

d1f9a5b8971843d791c92eda9437ae11.png

d63082a19eae4bde9676f3fa10d4a3d5.png

然后我们需要添加一下头文件的路径

680327c7e1004b5ca83447f3e2196ec7.png

7e3264ea30cb49c88bed6760cc75006b.png

这样我们一个FreeRTOS的keil才算是设置好,接下来可以开始我们最重要的构建链表的操作啦!!

三、链表的创建与实现

 7c82b1a2afa4464489142d87937fa6a4.png

 这就是单向链表的原理图,在此不多解释了,大伙们可以去看看数据结构这本书或者是网课!!(没有数据结构的基础是学不好操作系统的哟!!后续如果有时间我会再写一篇有关于这方面数据结构的文章)

 FreeRTOS中与链表相关的操作均在list.h和list.c这两个文件中实现

首先我们要创建list.h和list.c。

新建list.c在freeRTOS中

 

4df098b499114547ac6ec23c916b47e9.png

 

同理创建list.h在include下并将其添加进去工程分组的FreeRTOS/Source中。

8716b11d717b4d8c9b7e3181bfcb4942.png

移植并且添加进去FreeRTOS/Source

49ed29984828493db92269efc126caef.png

71fb023bb8e048df90767dd0cee8523a.png

具体的文件可以去野火官网或者是FreeRTOS官网下载哟!!FreeRTOS - Market leading RTOS (Real Time Operating System) for embedded systems with Internet of Things extensions

 实现节点的初始化(原理)

a8e524d9e0514a3cafefc149f1c59977.png

链表节点的数据结构在list.h中定义

 

  1. struct xLIST_ITEM
  2. {
  3. TickType_t xItemValue;
  4. struct xLIST_ITEM * pxNext; /* 辅助值,用于帮助节点做顺序排列 */
  5. struct xLIST_ITEM * pxPrevious; /* 指向链表下一个节点 */
  6. void * pvOwner; /* 指向链表前一个节点 */
  7. void * pvContainer; /* 指向拥有该节点的内核对象,通常是TCB */
  8. };
  9. typedef struct xLIST_ITEM ListItem_t; /* 节点数据类型重定义 */

链表根节点的数据结构在list.h中定义。

  1. typedef struct xLIST
  2. {
  3. UBaseType_t uxNumberOfItems; /*链表节点计数器*/
  4. ListItem_t * pxIndex; /*链表节点索引指针*/
  5. MiniListItem_t xListEnd; /*链表最后一个索引*/
  6. }List_t

链表节点的初始化在list.c中实现:vListInitialiseItem()

  1. void vListInitialiseItem( ListItem_t * const pxItem )
  2. {
  3. /* 初始化该节点所在的链表为空,表示节点还没有插入任何链表 */
  4. pxItem->pvContainer = NULL ;
  5. }

链表根节点的初始化在list.c中实现:vListInitialise()。

  1. void vListInitialise( List_t *const pxList)
  2. {
  3. /* 将链表索引指针指向最后一个节点 */
  4. pxList->pxIndex = (ListItem_t *)&pxList->xListEnd;
  5. /* 将链表最后一个节点的辅助排序的值设置为最大,确保该节点就是链表的最后节点 */
  6. pxList ->xListEnd.xItemValue = portMAX_DELAY;
  7. /* 将最后一个节点的pxNext和pxPrevious指针均指向节点自身,表示链表为空 */
  8. pxList ->xListEnd.pxPrevious= (ListItem_t *)&( pxList ->xListEnd);
  9. pxList ->xListEnd.pxNext=(ListItem_t *)&( pxList ->xListEnd);
  10. /* 初始化链表节点计数器的值为0,表示链表为空 */
  11. pxList->uxNumberOfItems = ( UBaseType_t ) 0U;
  12. }

 为了便于分别双向链表的结尾定义多一个结构体mini节点,作为双向链表的结尾。(双向链表是首尾相连的,头即是尾,尾即是头)

  1. struct xMINI_LIST_ITEM
  2. {
  3. TickType_t xItemValue; /* 辅助值,用于帮助节点做升序排列 */
  4. struct xLIST_ITEM * pxNext; /* 指向链表下一个节点 */
  5. struct xLIST_ITEM * pxPrevious; /* 指向链表前一个节点 */
  6. };
  7. typedef struct xMINI_LIST_ITEM MiniListItem_t; /* 最小节点数据类型重定义 */

然后我们需要有插入节点的操作均在list.c中实现:分别为:将节点插入到链表的尾部、将节点按照升序排列插入到链表、将节点从链表中删除 这三个操作。

将节点插入到链表的尾部:

  1. void vListInsertEnd( List_t * const pxList, ListItem_t * const pxNewListItem ) //两个参数(插入的链表,新的节点)
  2. {
  3. ListItem_t * const pxIndex = pxList->pxIndex; //定义一个索引指向链表的End
  4. pxNewListItem->pxNext = pxIndex; //第一步;将新节点的Next指向End
  5. pxNewListItem->pxPrevious = pxIndex->pxPrevious; //第二部;将新节点的Previous指向原来End的上一个
  6. pxIndex->pxPrevious->pxNext = pxNewListItem; //第三步;将原本End上一个的Next指向新节点
  7. pxIndex->pxPrevious = pxNewListItem; //第四步;将End的Previous指向新节点
  8. /* 记住该节点所在的链表 */
  9. pxNewListItem->pvContainer =( void * ) pxList;
  10. /* 链表节点计数器++ */
  11. ( pxList->uxNumberOfItems )++;
  12. }

 将节点按照升序排列插入到链表:

  1. void vListInsert( List_t * const pxList, ListItem_t * const pxNewListItem ) //两个参数(插入的链表,新的节点)
  2. {
  3. ListItem_t *pxIterator;
  4. /* 获取节点的排序辅助值 */
  5. const TickType_t xValueOfInsertion = pxNewListItem->xItemValue;
  6. /* 寻找节点要插入的位置 */
  7. if( xValueOfInsertion == portMAX_DELAY )
  8. {
  9. pxIterator = pxList->xListEnd.pxPrevious;
  10. }
  11. else
  12. {
  13. for( pxIterator = ( ListItem_t * ) &( pxList->xListEnd ); //通过获取函将这个值找出来
  14. pxIterator->pxNext->xItemValue <= xValueOfInsertion;
  15. pxIterator = pxIterator->pxNext )
  16. {
  17. /* 没有事情可做,不断迭代只为了找到节点要插入的位置 */
  18. }
  19. }
  20. pxNewListItem->pxNext = pxIterator->pxNext;
  21. pxNewListItem->pxNext->pxPrevious = pxNewListItem;
  22. pxNewListItem->pxPrevious = pxIterator;
  23. pxIterator->pxNext = pxNewListItem;
  24. /* 记住该节点所在的链表 */
  25. pxNewListItem->pvContainer = (void*) pxList;
  26. /* 链表节点计数器++ */
  27. ( pxList->uxNumberOfItems )++;
  28. }

将节点从链表中删除:

  1. /* 将节点从链表中删除 */
  2. UBaseType_t uxListRemove( ListItem_t * const pxItemToRemove )
  3. {
  4. /* 获取节点所在的链表 */
  5. List_t * const pxList = ( List_t * ) pxItemToRemove->pvContainer;
  6. pxItemToRemove->pxNext->pxPrevious = pxItemToRemove->pxPrevious;
  7. pxItemToRemove->pxPrevious->pxNext = pxItemToRemove->pxNext;
  8. /* Make sure the index is left pointing to a valid item. */
  9. if( pxList->pxIndex == pxItemToRemove )
  10. {
  11. pxList->pxIndex = pxItemToRemove->pxPrevious;
  12. }
  13. /* 初始化该节点所在的链表为空,表示节点还没有插入任何链表 */
  14. pxItemToRemove->pvContainer = NULL;
  15. /* 链表节点计数器-- */
  16. ( pxList->uxNumberOfItems )--;
  17. /* 返回链表中剩余节点的个数 */
  18. return pxList->uxNumberOfItems;
  19. }

这样我们就可以实现链表的创建和操作啦,注意list.c中需要引用头文件: "FreeRTOS.h"
和 <stdlib.h>和"list.h"!!!!!list.h需要引用头文件"FreeRTOS.h"。

那接下来我们就在main()创建一个有三个节点的链表吧。

首先先定义一个根节点、然后再定义三个节点。

再分别对根节点和三个节点进行初始化

最后再对其进行排序插入节点。

  1. #include "list.h"
  2. /*1.定义一个根节点*/
  3. struct xLIST List_Text;
  4. /*2.定义3个节点*/
  5. struct xLIST_ITEM List_Item1;
  6. struct xLIST_ITEM List_Item2;
  7. struct xLIST_ITEM List_Item3;
  8. int main(void)
  9. { /*3.根节点初始化*/
  10. vListInitialise(&List_Text);
  11. /*节点初始化*/
  12. vListInitialiseItem(&List_Item1);
  13. vListInitialiseItem(&List_Item2);
  14. vListInitialiseItem(&List_Item3);
  15. /*插入节点*/
  16. vListInsert(&List_Text,&List_Item1);
  17. vListInsert(&List_Text,&List_Item2);
  18. vListInsert(&List_Text,&List_Item3);
  19. for(;;)
  20. {
  21. //空
  22. }
  23. }

最后debug看看是否符合预期,要run一下!!!

1512701f269246219fcb9a4d6231c213.png

 

最后结构正确,各节点指针指向符合双向链表预期!!本章就到这啦,如果有错请指出哟!!!如果我的学习过程可以帮到你就最好啦!!别忘记点赞哟!! 

 

 

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/运维做开发/article/detail/825847
推荐阅读
相关标签
  

闽ICP备14008679号