STM32使用FreeRTOS中的链表创建节点与列表项


关于FreeRTOS的list函数,可参考另一篇的链接:

网上的freeRTOS链表教程 - yintianlan的博客 - CSDN博客
https://blog.csdn.net/yintianlan/article/details/84530622

 

使用了STM32F103的FreeRTOS库来创建一个列表,其实FreeRTOS的list中链表是双向的循环链表,为了简单介绍,我直接说是列表了。 
芯片使用的是GD32F103CBT6,该芯片兼容ST的库,不影响使用效果。 
以下代码不全,仅提供思路,如有不足,请给我留言。

第一步

先定义变量,初始化列表及列表项

nodeDevice node_t;	//节点数据
nodeDevice * pNode;	//节点指针

xList list_t;		//列表
#define pList		((xList *) &list_t) //列表指针

xListItem item_t;	//列表项
xListItem * pItem;  //列表项指针

	/*初始化列表、列表项*/
	vListInitialise((xList *) &list_t);
	vListInitialiseItem(pItem);

第二步

根据条件判断是否需要增加列表项与节点(每一个节点指针挂载在对应列表项的空指针上)。 
我的节点数据是通过CAN数据来获取的,其实通过其它总线也可以,但CAN总线可以挂载多个设备(收发器),就是现成的多个节点了。 
这部分代码是我是否创建新节点的逻辑代码。

/*****************************************************************************
**Name:		 	DealAddressReq
**Function:	处理设备地址
**Args:
**Return:
******************************************************************************/
void DealAddressReq(CanRxMsgTypeDef * const pCAN_RxData, void * const pBaseInfo)
{
	uint32_t NodeAddress;
	nodeDevice *goalCurrentNode = NULL;//当前节点指针

	/*获取设备ID*/
	NodeAddress = (pCAN_RxData->Data[0]<<24)|(pCAN_RxData->Data[1]<<16)|(pCAN_RxData->Data[2]<<8)|(pCAN_RxData->Data[3]);

	if(NodeAddress == NULLDEVICE)return;//地址为空则退出

	/*如果列表为空*/
	if(listLIST_IS_EMPTY(pList))
	{
		CreateNode(pCAN_RxData, pBaseInfo, NodeAddress);//加载第一项,创建第一个节点
	}
	else/*如果列表不为空*/
	{
		goalCurrentNode = GetNodeByUidOrCHID(NodeAddress, 0);//根据UID获取节点

		/*如果不是地址池中的地址,则创建新的节点*/
		if(goalCurrentNode == NULLNODE)
		{
			CreateNode(pCAN_RxData, pBaseInfo, NodeAddress);//创建新节点
		}
		else
		{
			return;
		}
	}
}

其中遍历列表,查找当前节点的函数

/*****************************************************************************
**Name:		 	GetNodeByUid
**Function:	根据UID获取节点,或根据数据上下行通道获取节点
**Args: NodeAddress != 0:	使用UID获取节点
				nodeChannelID != 0:	使用数据上下行通道获取节点
**Return:
******************************************************************************/
nodeDevice * GetNodeByUidOrCHID(uint32_t NodeAddress, uint32_t nodeChannelID)
{
	int index;
	nodeDevice *getCurrentNode = NULL;//当前节点指针

	for(index = 0; index < LIST_LENGTH; index++)
	{
		/*遍历列表,返回的是列表中列表项的pxOwner成员*/
		listGET_OWNER_OF_NEXT_ENTRY(getCurrentNode, pList);

		//根据MAC查找结点
		if(NodeAddress == (getCurrentNode->nodeAddress))
		{
			return getCurrentNode;
		}
		//地址应答帧ID是否与该节点的数据下行通道相配对
		else if(nodeChannelID == (getCurrentNode->nodeChannelID_Low|0x01))
		{
			return getCurrentNode;
		}
		else
		{
			getCurrentNode = NULLNODE;
		}
	}

	return getCurrentNode;
}

第三步

申请内存,创建节点与列表项,插入列表(链表) 
这一部分为重点,其实思路与网上大部分创建插入链表相同,只是更改了一些函数名与变量。

/*****************************************************************************
**Name:		 	CreateNode
**Function:	创建列表项与节点
**Args:
**Return:
******************************************************************************/
void CreateNode(CanRxMsgTypeDef * const pCAN_RxData, void * const pBaseInfo, uint32_t UidAddress)
{
	/*执行一次,则创建一个列表项与节点结构体*/
	pItem = pvPortMalloc(sizeof(ListItem_t));//申请列表项内存
	pNode = pvPortMalloc(sizeof(nodeDevice));//申请结构体内存
	memset(pNode, 0, sizeof(nodeDevice));

	pItem->xItemValue = GetNodePosition();//获取占位地址大小
	vListInsert(pList, pItem);//插入列表项

	pItem->pvOwner = pNode;//给列表项的空指针挂上我们的数据地址

	/*发送通道ID(大端)*/
	NodeDataInstall( pCAN_RxData, pBaseInfo, UidAddress, pNode);//数据加载
}
  • 因为需要动态增加节点,所以pItem->xItemValue的值是需要在可控范围内获取的,并不一定是0~0xFFFFFFFFU的值,需要根据节点索引的数据类型来。 
    这里有一个问题,比如定义了一个char型,就只能取0~255的数,若是超过了255怎么办呐?或者我是“整十”地定义索引,就只有25个数可取了.
  • 之前说过了是“动态增加节点”,也就是说不只是增加,我们也可以删除,删除数据之后我们需要还原一些数据,并释放内存,当我们下一次增加新节点时使用的就是之前释放掉的内存,那么问题还是那个——我们的xItemValue值和节点定义的索引怎么办?
  • 先来说一下列表项的xItemValue值,它是FreeRTOS中list.h定义的一个列表项结构体的一个变量,目地是为了插入列表项的时候,更据它的大小比较进行排序后插入列表对应的位置,所以它很重要。为了不要让我们插入的位置冲突,最好初始化一个新的列表项的时候把它赋一个不同的值。 
    我们节点的索引应该也一样具有唯一性,就和总线上的设备地址一样。所以值的设置我们使用占位法,思路与STM32的寄存器一样—— 一个功能占一个BIT,使用时将该位“置1”,使用完后将该位“清0”,等待下一次使用。 
    当使用到一位时,将它“置1”后将它的实际大小返回,赋值给xItemValue。
  • 例如:从小到大占位“0000 0000”,现在都是空的, 现在占用第1位后“0000 0001”,当前列表项xItemValue = 1; 
    从小到大占位“0001 1111”,现在使用了5个位置,当前列表项xItemValue = 5,现在还原第3位后“0001 1011”,下次可继续使用第3位; 
    注:位的运算方法推荐使用STM32库中对寄存器的运算!

第四步

自己设计删除节点的条件

    //......
    
	//还原位置数据
	RestoreNodePosition(bxCurrentNode->nodeChannelID_Low);

	pxCurrentItem = pList->pxIndex;//当前列表项
	uxListRemove( pxCurrentItem); //删除列表项
	vPortFree(bxCurrentNode); //释放内存
	vPortFree(pxCurrentItem);
	
    //......
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值