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中定义

 

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一下!!!

1512701f269246219fcb9a4d6231c213.png

 

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

 

 

 

 

  • 7
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值