使用了STM32F103的FreeRTOS庫(kù)來(lái)創(chuàng)建一個(gè)列表,其實(shí)FreeRTOS的list中鏈表是雙向的循環(huán)鏈表,為了簡(jiǎn)單介紹,我直接說(shuō)是列表了。
芯片使用的是GD32F103CBT6,該芯片兼容ST的庫(kù),不影響使用效果。
以下代碼不全,僅提供思路,如有不足,請(qǐng)給我留言。
第一步
先定義變量,初始化列表及列表項(xiàng)
nodeDevice node_t; //節(jié)點(diǎn)數(shù)據(jù)
nodeDevice * pNode; //節(jié)點(diǎn)指針
xList list_t; //列表
#define pList ((xList *) &list_t) //列表指針
xListItem item_t; //列表項(xiàng)
xListItem * pItem; //列表項(xiàng)指針
/*初始化列表、列表項(xiàng)*/
vListInitialise((xList *) &list_t);
vListInitialiseItem(pItem);
第二步
根據(jù)條件判斷是否需要增加列表項(xiàng)與節(jié)點(diǎn)(每一個(gè)節(jié)點(diǎn)指針掛載在對(duì)應(yīng)列表項(xiàng)的空指針上)。
我的節(jié)點(diǎn)數(shù)據(jù)是通過(guò)CAN數(shù)據(jù)來(lái)獲取的,其實(shí)通過(guò)其它總線也可以,但CAN總線可以掛載多個(gè)設(shè)備(收發(fā)器),就是現(xiàn)成的多個(gè)節(jié)點(diǎn)了。
這部分代碼是我是否創(chuàng)建新節(jié)點(diǎn)的邏輯代碼。
/*****************************************************************************
**Name: DealAddressReq
**Function: 處理設(shè)備地址
**Args:
**Return:
******************************************************************************/
void DealAddressReq(CanRxMsgTypeDef * const pCAN_RxData, void * const pBaseInfo)
{
uint32_t NodeAddress;
nodeDevice *goalCurrentNode = NULL;//當(dāng)前節(jié)點(diǎn)指針
/*獲取設(shè)備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);//加載第一項(xiàng),創(chuàng)建第一個(gè)節(jié)點(diǎn)
}
else/*如果列表不為空*/
{
goalCurrentNode = GetNodeByUidOrCHID(NodeAddress, 0);//根據(jù)UID獲取節(jié)點(diǎn)
/*如果不是地址池中的地址,則創(chuàng)建新的節(jié)點(diǎn)*/
if(goalCurrentNode == NULLNODE)
{
CreateNode(pCAN_RxData, pBaseInfo, NodeAddress);//創(chuàng)建新節(jié)點(diǎn)
}
else
{
return;
}
}
}
其中遍歷列表,查找當(dāng)前節(jié)點(diǎn)的函數(shù)
/*****************************************************************************
**Name: GetNodeByUid
**Function: 根據(jù)UID獲取節(jié)點(diǎn),或根據(jù)數(shù)據(jù)上下行通道獲取節(jié)點(diǎn)
**Args: NodeAddress != 0: 使用UID獲取節(jié)點(diǎn)
nodeChannelID != 0: 使用數(shù)據(jù)上下行通道獲取節(jié)點(diǎn)
**Return:
******************************************************************************/
nodeDevice * GetNodeByUidOrCHID(uint32_t NodeAddress, uint32_t nodeChannelID)
{
int index;
nodeDevice *getCurrentNode = NULL;//當(dāng)前節(jié)點(diǎn)指針
for(index = 0; index < LIST_LENGTH; index++)
{
/*遍歷列表,返回的是列表中列表項(xiàng)的pxOwner成員*/
listGET_OWNER_OF_NEXT_ENTRY(getCurrentNode, pList);
//根據(jù)MAC查找結(jié)點(diǎn)
if(NodeAddress == (getCurrentNode->nodeAddress))
{
return getCurrentNode;
}
//地址應(yīng)答幀ID是否與該節(jié)點(diǎn)的數(shù)據(jù)下行通道相配對(duì)
else if(nodeChannelID == (getCurrentNode->nodeChannelID_Low|0x01))
{
return getCurrentNode;
}
else
{
getCurrentNode = NULLNODE;
}
}
return getCurrentNode;
}
第三步
申請(qǐng)內(nèi)存,創(chuàng)建節(jié)點(diǎn)與列表項(xiàng),插入列表(鏈表)
這一部分為重點(diǎn),其實(shí)思路與網(wǎng)上大部分創(chuàng)建插入鏈表相同,只是更改了一些函數(shù)名與變量。
/*****************************************************************************
**Name: CreateNode
**Function: 創(chuàng)建列表項(xiàng)與節(jié)點(diǎn)
**Args:
**Return:
******************************************************************************/
void CreateNode(CanRxMsgTypeDef * const pCAN_RxData, void * const pBaseInfo, uint32_t UidAddress)
{
/*執(zhí)行一次,則創(chuàng)建一個(gè)列表項(xiàng)與節(jié)點(diǎn)結(jié)構(gòu)體*/
pItem = pvPortMalloc(sizeof(ListItem_t));//申請(qǐng)列表項(xiàng)內(nèi)存
pNode = pvPortMalloc(sizeof(nodeDevice));//申請(qǐng)結(jié)構(gòu)體內(nèi)存
memset(pNode, 0, sizeof(nodeDevice));
pItem->xItemValue = GetNodePosition();//獲取占位地址大小
vListInsert(pList, pItem);//插入列表項(xiàng)
pItem->pvOwner = pNode;//給列表項(xiàng)的空指針掛上我們的數(shù)據(jù)地址
/*發(fā)送通道ID(大端)*/
NodeDataInstall( pCAN_RxData, pBaseInfo, UidAddress, pNode);//數(shù)據(jù)加載
}
因?yàn)樾枰獎(jiǎng)討B(tài)增加節(jié)點(diǎn),所以pItem->xItemValue的值是需要在可控范圍內(nèi)獲取的,并不一定是0~0xFFFFFFFFU的值,需要根據(jù)節(jié)點(diǎn)索引的數(shù)據(jù)類(lèi)型來(lái)。
這里有一個(gè)問(wèn)題,比如定義了一個(gè)char型,就只能取0~255的數(shù),若是超過(guò)了255怎么辦吶?或者我是“整十”地定義索引,就只有25個(gè)數(shù)可取了.
之前說(shuō)過(guò)了是“動(dòng)態(tài)增加節(jié)點(diǎn)”,也就是說(shuō)不只是增加,我們也可以刪除,刪除數(shù)據(jù)之后我們需要還原一些數(shù)據(jù),并釋放內(nèi)存,當(dāng)我們下一次增加新節(jié)點(diǎn)時(shí)使用的就是之前釋放掉的內(nèi)存,那么問(wèn)題還是那個(gè)——我們的xItemValue值和節(jié)點(diǎn)定義的索引怎么辦?
先來(lái)說(shuō)一下列表項(xiàng)的xItemValue值,它是FreeRTOS中l(wèi)ist.h定義的一個(gè)列表項(xiàng)結(jié)構(gòu)體的一個(gè)變量,目地是為了插入列表項(xiàng)的時(shí)候,更據(jù)它的大小比較進(jìn)行排序后插入列表對(duì)應(yīng)的位置,所以它很重要。為了不要讓我們插入的位置沖突,最好初始化一個(gè)新的列表項(xiàng)的時(shí)候把它賦一個(gè)不同的值。
我們節(jié)點(diǎn)的索引應(yīng)該也一樣具有唯一性,就和總線上的設(shè)備地址一樣。所以值的設(shè)置我們使用占位法,思路與STM32的寄存器一樣—— 一個(gè)功能占一個(gè)BIT,使用時(shí)將該位“置1”,使用完后將該位“清0”,等待下一次使用。
當(dāng)使用到一位時(shí),將它“置1”后將它的實(shí)際大小返回,賦值給xItemValue。
例如:從小到大占位“0000 0000”,現(xiàn)在都是空的, 現(xiàn)在占用第1位后“0000 0001”,當(dāng)前列表項(xiàng)xItemValue = 1;
從小到大占位“0001 1111”,現(xiàn)在使用了5個(gè)位置,當(dāng)前列表項(xiàng)xItemValue = 5,現(xiàn)在還原第3位后“0001 1011”,下次可繼續(xù)使用第3位;
注:位的運(yùn)算方法推薦使用STM32庫(kù)中對(duì)寄存器的運(yùn)算!
第四步
自己設(shè)計(jì)刪除節(jié)點(diǎn)的條件
//......
//還原位置數(shù)據(jù)
RestoreNodePosition(bxCurrentNode->nodeChannelID_Low);
pxCurrentItem = pList->pxIndex;//當(dāng)前列表項(xiàng)
uxListRemove( pxCurrentItem); //刪除列表項(xiàng)
vPortFree(bxCurrentNode); //釋放內(nèi)存
vPortFree(pxCurrentItem);
//......
上一篇:FreeRTOS學(xué)習(xí)筆記——基礎(chǔ)知識(shí)與移植(STM32F103)
下一篇:幾張圖對(duì)比STM32各系列產(chǎn)品特性和外設(shè)兼容性
推薦閱讀最新更新時(shí)間:2025-06-28 06:14



- 熱門(mén)資源推薦
- 熱門(mén)放大器推薦
-
【Follow me第三季第1期】任務(wù)三:Arduino環(huán)境運(yùn)動(dòng)傳感器數(shù)據(jù)讀取
-
【Follow me 第三季第1期】任務(wù)二——Arduino控制板載LED燈,并實(shí)現(xiàn)呼吸燈效果
-
【Follow me 第三季第1期】任務(wù)一 源碼-——Arduino環(huán)境Hello EEWorld
-
Follow me第三季第1期STM32F429作品代碼
-
開(kāi)關(guān)電源外圍元器件選擇與檢測(cè)
-
運(yùn)算放大器的設(shè)計(jì)與應(yīng)用
-
智能鋰電池充電器
-
實(shí)時(shí)控制系統(tǒng)軟件設(shè)計(jì)原理及應(yīng)用
設(shè)計(jì)資源 培訓(xùn) 開(kāi)發(fā)板 精華推薦
- 基于51系列單片機(jī)的智能照明控制系統(tǒng)設(shè)計(jì)方案
- 基于STM32的四旋翼飛行器控制系統(tǒng)
- 單片機(jī)應(yīng)用編程技巧解析
- 基于89C52的教室智能節(jié)能照明系統(tǒng)設(shè)計(jì)
- 一種新型的雨量光照傳感器的設(shè)計(jì)
- 智能護(hù)眼臺(tái)燈設(shè)計(jì)
- 蓄電池高能脈沖充電系統(tǒng)設(shè)計(jì)
- 基于51單片機(jī)定時(shí)器的電子時(shí)鐘設(shè)計(jì)方案
- 瑞薩電子推出面向單電機(jī)應(yīng)用優(yōu)化的卓越MCU, 涵蓋電動(dòng)工具、家用電器等廣泛應(yīng)用場(chǎng)景
- LTC3809-1 的典型應(yīng)用 - 無(wú)檢測(cè)、低輸入電壓、具有輸出跟蹤功能的同步 DC/DC 控制器
- NCV8189CMTW180TAGEVB:NCV8189 WDFNW6 2x2 1V8 評(píng)估板
- LTC3615HFE-1 雙路 3A 同步降壓型 DC/DC 轉(zhuǎn)換器在主機(jī)和從機(jī)中的典型應(yīng)用,用于使用 2MHz 外部時(shí)鐘實(shí)現(xiàn)一致跟蹤輸出
- ADK-8470,HI-8470 16 傳感器陣列評(píng)估板 + ARINC 429 輸出、接地/開(kāi)路或電源/開(kāi)路傳感器
- AM1G-1209DH30Z ±9V 1 瓦 DC/DC 轉(zhuǎn)換器的典型應(yīng)用
- L7808A 固定輸出穩(wěn)壓器的典型應(yīng)用
- DC274A-A,用于 LT1576CS8、200kHz 降壓轉(zhuǎn)換器的演示板,具有關(guān)斷、5.5 至 25Vin、3.3V 或 5Vout,1.25A
- TCR5SB24U、200mA、2.4V輸出電壓CMOS低壓降穩(wěn)壓器的典型應(yīng)用
- STEVAL-ISA101V1,使用 L5973D 的演示板,具有 4 V/36 V 輸入電壓范圍的 2 A 直流降壓開(kāi)關(guān)穩(wěn)壓器
- 使用 Semtech 的 ACS8527 的參考設(shè)計(jì)
- 粉塵防爆電機(jī)選擇誤區(qū)_如何選擇粉塵防爆電機(jī)型號(hào)
- 美國(guó)低速自動(dòng)駕駛車(chē)輛在公共交通應(yīng)用詳解
- 垂直燃燒測(cè)試儀簡(jiǎn)介
- 國(guó)內(nèi)首條!基本半導(dǎo)體汽車(chē)級(jí)SiC功率模塊專(zhuān)用產(chǎn)線正式運(yùn)行
- 面向制造和工業(yè)環(huán)境監(jiān)控應(yīng)用的人工智能機(jī)器視覺(jué)
- 不得不說(shuō)的USART中的重定向問(wèn)題
- 基于光氫儲(chǔ)的多能互補(bǔ)系統(tǒng)研究
- 基于LPC2292控制器和CAN現(xiàn)場(chǎng)總線實(shí)現(xiàn)電力電纜溝道監(jiān)測(cè)系統(tǒng)的設(shè)計(jì)
- 奇瑞人形機(jī)器人9月開(kāi)售并將面向個(gè)人用戶(hù),機(jī)器人時(shí)代該來(lái)了嗎?
- 華為李文廣:華為智能駕駛規(guī)劃曝光,加速追趕特斯拉
- 功能迭代和功能安全的矛盾及車(chē)端應(yīng)用層-下
- 功能迭代和功能安全的矛盾及車(chē)端應(yīng)用層-中
- 功能迭代和功能安全的矛盾及車(chē)端應(yīng)用層-上
- 車(chē)云一體其他層面的架構(gòu)設(shè)計(jì)借鑒-下
- 輔助駕駛域控發(fā)展背景
- 輔助駕駛域控核心方法論是什么-下
- 輔助駕駛域控核心方法論是什么-上
- 規(guī)?;慨a(chǎn)時(shí)代來(lái)臨?智元、宇樹(shù)科技中標(biāo)1.24億人形機(jī)器人大單!
- 我國(guó)機(jī)器人產(chǎn)業(yè)發(fā)展已迎來(lái)了重要轉(zhuǎn)折點(diǎn)
- MPC5668G系列:Qorivva 雙核32位MCU,主要應(yīng)用在汽車(chē)網(wǎng)關(guān)
- 電動(dòng)渦輪:汽車(chē)技術(shù)最新的發(fā)展
- 比亞迪+華為,能不能打得過(guò)特斯拉?
- Waymo Honeycomb,激光雷達(dá)領(lǐng)域的另類(lèi)!
- 2019年首季度TCL電子電視機(jī)銷(xiāo)售量再創(chuàng)單季歷史新高達(dá)844萬(wàn)臺(tái)
- 創(chuàng)維數(shù)字可轉(zhuǎn)債現(xiàn)已啟動(dòng)發(fā)行 助推未來(lái)業(yè)績(jī)?cè)鲩L(zhǎng)
- 富士官方影像定制店現(xiàn)已登陸淘寶 開(kāi)業(yè)限時(shí)福利進(jìn)行中
- 智能音箱成竊聽(tīng)器?亞馬遜被曝雇傭數(shù)千名員工“偷聽(tīng)
- “新物種”還是“雜交種”,“腕機(jī)”到底算啥玩意兒?