娇小w搡bbbb搡bbb,《第一次の人妻》,中国成熟妇女毛茸茸,边啃奶头边躁狠狠躁视频免费观看

深度解析鏈表在STM32中的應用

發(fā)布者:SereneSerenity最新更新時間:2024-09-26 來源: elecfans關鍵字:鏈表  STM32  數組 手機看文章 掃描二維碼
隨時隨地手機看文章

1、為何引入鏈表

程序中經常面臨一個問題,我們需要保存一定數量的對象,但是對象數目是不確定的,或者說是隨時增加或減少的。這時候最簡單的方法是創(chuàng)建一個足夠大的數組,用來存儲這些對象。我最近開發(fā)一個項目就遇到類似的問題,下面我把問題簡化一下。


需求:通過PC下發(fā)一些矩形的坐標和寬高信息,每個區(qū)域有個ID編號,并在這些矩形內填充一定的數據。

通常情況下,最簡單易懂的做法是,限制最多5個區(qū)域,每個區(qū)域存儲1K數據。因此設置了這樣的一個結構體(類似于面向對象語言里說的成員屬性)。

typedef struct Area_Inf{ uint8_t ID; uint8_t X; uint8_t Y; uint8_t Width; uint8_t Height; uint8_t data_len;}Area_Inf_Typedef;

然后定義結構體的實體。

#define Area_Num 5#define Area_cache 1024

Area_Inf_Typedef Area_Info[Area_Num];uint8_t Area_Data[Area_Num*Area_cache];//存儲區(qū)域的數據

/*找到ID為5的區(qū)域,并將數據拷貝出去*/void main(){ uint8_t i; uint8_t data[1024]; for(i = 0;i 《 Area_Num;i++) { if(Area_Info[i].ID == 5) { memcpy(data,&Area_Data[i*Area_cache ],Area_Info[i].data_len); } }}

上面這種做法是最簡單易懂的,但不靈活,比如有客戶要求10個區(qū)域,但是每個區(qū)域存儲的數據很少,根本用不到1K。雖然上面的程序已經使用了宏定義,只需要修改宏定義就能實現要求。但這意味著不同的客戶,需要編譯不同的固件

#define Area_Num 10#define Area_cache 512

這樣的程序存在的問題:

1、在內存資源很緊缺的單片機程序中,當區(qū)域數據很少時,這種程序的處理方法浪費了大量的內存空間。

2、數值固定,需要存儲更多區(qū)域,即使還有內存,還是需要修改宏定義,重新編譯固件,不靈活。

這時需要引入鏈表來解決這個問題。

2、鏈表實現

鏈表實際上是線性表的鏈式存儲結構,與數組不同的是,它是用一組任意的存儲單元來存儲線性表中的數據,存儲單元不一定是連續(xù)的,且鏈表的長度不是固定的,鏈表數據的這一特點使其可以非常的方便地實現節(jié)點的插入和刪除操作。鏈表的每個元素稱為一個節(jié)點,每個節(jié)點都可以存儲在內存中的不同的位置,為了表示每個元素與后繼元素的邏輯關系,以便構成“一個節(jié)點鏈著一個節(jié)點”的鏈式存儲結構,除了存儲元素本身的信息外,還要存儲其直接后繼信息,因此,每個節(jié)點都包含兩個部分,第一部分稱為鏈表的數據區(qū)域,用于存儲元素本身的數據信息。

6ee7ead4-9e2c-11eb-8b86-12bb97331649.png

對于上面的問題,我們使用鏈表解決,需要配合內存管理才能實現。內存管理這一塊,大家可以自己編寫內存管理驅動,也可以使用C庫的malloc和free函數。如何字節(jié)編寫內存管理驅動不是本文的重點,下文將使用C庫的malloc和free函數進行內存管理。

使用鏈表的方式,在原有的成員屬性結構體的前提上,還要再封裝多一層鏈表管理。以單向鏈表為例:

typedef struct Area_Inf{ uint8_t ID; uint8_t X; uint8_t Y; uint8_t Width; uint8_t Height; uint8_t data_len; uint8_t* Area_Data;}Area_Inf_Typedef;

typedef struct Area_List_Inf{ Area_Inf_Typedef *Area_Inf; struct Area_List_Inf *next_Area_Inf; //用于指向下一個}Area_List_Inf_Typedef;

Area_List_Inf_Typedef *Head_Area_List; //鏈表的頭指針

由于在定義的時候,只定義了一個頭指針,那么它也只是個指向了Area_List_Inf_Typedef也就是鏈表結構體的指針,同樣沒有內存空間,在沒有創(chuàng)建新增鏈表之前,它是一個野指針。

所以,在具體應用之前,需要先執(zhí)行一個初始化操作,也就是申請空間給鏈表管理結構體,然后頭指針指向這個空間。

/*** @brief 動態(tài)區(qū)鏈表初始化* @return int */int Area_List_Init(void){ //申請鏈表類型大小的空間,并讓頭指針指向它 Head_Area_List = (Area_List_Inf_Typedef*)malloc(sizeof(Area_List_Inf_Typedef)); if(Head_Area_List == NULL) return false; //同時要標記下一個信息為空 Head_Area_List-》next_Area_Inf = NULL; return true;}

通過PC下發(fā)一個新的區(qū)域信息后,增加新區(qū)域到鏈表末尾。

/*** @brief 在鏈表末尾增加一個區(qū)域參數* @param Area_Inf 增加的區(qū)域區(qū)參數指針* @return int */int Add_Area_ToList(Area_Inf_Typedef *Area_Inf){ Area_List_Inf_Typedef *p = Head_Area_List; while(p-》next_Area_Inf!=NULL) { p = p-》next_Area_Inf; } //先申請鏈表結構體的空間,因為后續(xù)還要繼續(xù)增加 p-》next_Area_Inf = (Area_List_Inf_Typedef*)malloc(sizeof(Area_List_Inf_Typedef)); if(p-》next_Area_Inf == NULL) return false;//申請不到內存,返回失敗 //指向剛剛申請的空間,并為需要存放的動態(tài)區(qū)信息申請對應的內存 p = p-》next_Area_Inf; p-》Area_Inf = (Area_Inf_Typedef*)malloc(sizeof(Area_Inf_Typedef)); if(p-》Area_Inf == NULL) { free(p);//由于申請失敗,先前申請的鏈表空間也要釋放 return false; } memcpy(p-》Area_Inf,Area_Inf,sizeof(Area_Inf_Typedef)); /*拷貝數據*/ p-》Area_Inf-》Area_Data = (uint8_t*)malloc(Area_Inf-》data_len); if(p-》Area_Inf-》Area_Data == NULL) { free(p-》Area_Inf); free(p); return false; } memcpy(p-》Area_Inf-》Area_Data,Area_Inf-》Area_Data,Area_Inf-》data_len); //標記這個鏈表的尾部 p-》next_Area_Inf=NULL; //添加成功 return true;}

通過PC下發(fā)一個刪除指定ID的區(qū)域命令。

/*** @brief 根據區(qū)域ID刪除動態(tài)區(qū)* @param num 區(qū)域ID* @return int */int Delete_Area_Accordingn_ID(int num){ int res = false; Area_List_Inf_Typedef *p = Head_Area_List; while(p-》next_Area_Inf!=NULL) { Area_List_Inf_Typedef *temp = p; p = p-》next_Area_Inf; if(p-》Area_Inf-》ID == num)//匹配到對應的值 { temp-》next_Area_Inf = p-》next_Area_Inf; //釋放內存空間 free(p-》Area_Inf-》Area_Data); free(p-》Area_Inf); free(p); p=temp; res = true; } } return res;}

看了上面的驅動函數,相信大家已經明白,大家可以自行編寫一些驅動,下面我實現的三個簡單函數。

/*** @brief 根據區(qū)域ID找到鏈表* @param data_p 鏈表指針* @param num 區(qū)域ID編號* @return int */int Find_Area_According_ID(Area_Inf_Typedef **data_p,int num){ Area_List_Inf_Typedef *p = Head_Area_List; while(p-》next_Area_Inf!=NULL) { p = p-》next_Area_Inf; if(p-》Area_Inf-》ID == num)//匹配到對應的值 { *data_p = p-》Area_Inf; return true; } } return false;}/*** @brief 刪除所有區(qū)域* */int Delete_All_Area(void){ int res = false; Area_List_Inf_Typedef *p = Head_Area_List; while(p-》next_Area_Inf!=NULL) { Area_List_Inf_Typedef *temp = p; p = p-》next_Area_Inf; temp-》next_Area_Inf = p-》next_Area_Inf; //釋放內存空間 free(p-》Area_Inf-》Area_Data); free(p-》Area_Inf); free(p); p=temp; res = true; } return res;}/*** @brief 打印鏈表信息* */void Printf_Area_Inf(void){ int i=0; Area_List_Inf_Typedef *p = Head_Area_List; printf(“l(fā)ist ID X Y Width Height Area_Data

”); while(p-》next_Area_Inf!=NULL) { p = p-》next_Area_Inf; printf(“ %d %d %d %d %d %d %s

”,i,p-》Area_Inf-》ID,p-》Area_Inf-》X,p-》Area_Inf-》Y,p-》Area_Inf-》Width,p-》Area_Inf-》Height,p-》Area_Inf-》Area_Data); i++; } printf(“----------------------end-----------------------

”);}

3、測試函數

下面編寫一個測試函數,可以測試,鏈表的初始化,增加一個區(qū)域,刪除指定區(qū)域,根據ID返回區(qū)域信息,刪除所有區(qū)域接口。

/*** @brief 鏈表測試函數* */void list_main(){ int i,j; Area_Inf_Typedef temp; Area_Inf_Typedef **data_p; data_p = NULL; printf(“------------------List test---------------------

”); if(!Area_List_Init( )) { printf(“Memory fail.。

”); } for(i=0;i《5;i++) { temp.ID = i; temp.X = 5+i; temp.Y = i; temp.Width = 10+i; temp.Height = 10+i; temp.data_len = i+1; temp.Area_Data = (uint8_t*)malloc(temp.data_len+1); for(j=0;j《temp.data_len;j++) { temp.Area_Data[j] = j+0x30; } temp.Area_Data[j] = 0; if(!Add_Area_ToList(&temp)) { printf(“Add Area %d Area_Info fail

”,i); } } Printf_Area_Inf(); printf(“

-------------Delete ID of Area is 3-------------

”); Delete_Area_Accordingn_ID(3); Printf_Area_Inf(); temp.ID = 9; temp.data_len = 10; temp.Area_Data = (uint8_t*)malloc(temp.data_len+1); for(j=0;j《temp.data_len;j++) { temp.Area_Data[j] = j+0x30; } temp.Area_Data[j] = 0; if(!Add_Area_ToList(&temp)) { printf(“Add Area %d info fail

”,temp.ID); } printf(“

--------------Add ID of Area is 9---------------

”); Printf_Area_Inf(); Find_Area_According_ID(data_p,2); temp.ID = (*data_p)-》ID; Delete_All_Area(); printf(“

--------------Delete All Area-------------------

”); Printf_Area_Inf(); while(1);}

測試結果

6ef62022-9e2c-11eb-8b86-12bb97331649.png

如果大家手中有板子可以調試,可以看《一文了解串口打印》文章,使用串口打印。如果臨時沒有板子可以debug,可以模擬測試,IAR設置如下:

選擇Simulator調試

6eff06a6-9e2c-11eb-8b86-12bb97331649.png

打開View-》TerminalI/O,就可以看到打印信息

6f0adc92-9e2c-11eb-8b86-12bb97331649.png


關鍵字:鏈表  STM32  數組 引用地址:深度解析鏈表在STM32中的應用

上一篇:stm32 can不穩(wěn)定的解決方法
下一篇:在學習STM32時為什么要學習匯編?

推薦閱讀最新更新時間:2025-06-17 17:12

c51數組指針使用
#include reg52.h #define uchar unsigned char uchar tab ={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f}; void delay(void); main() { uchar i=0,*p; p=tab; while(1) { for(i=0,p=tab;i 8;i++,p++) { P1=*p; delay(); } } } void delay(void) { unsigned int i; for(i=0;i 5000;i++) {;} }
[單片機]
LabVIEW——數組
數組 數組是由同一類型數據元素組成的大小可變的集合。同其他語言一樣,Labview也提供了數組結構,數組是相同數據類型的集合,這些數據類型可以是數組型,布爾型,字符串型等。當需要頻繁地對一批數據進行繪圖時,使用數組將獲益匪淺。下面將詳細介紹數組及數組函數的各種用法。 創(chuàng)建數組 1.從前面板上創(chuàng)建數組:打開前面板,在控件 新式 數組,矩陣與簇 數組,如圖: 再在里面放置一個數值輸入控件即可,如圖: 如果要顯示更多的數組成員,在工具選項板上選擇定位工具,在數組的邊框停滯,當出現網狀拐角后就可以拖動增加或減少顯示區(qū)域。如圖: 如果要增加或減少數組的維度,既可以在索引框的快捷菜單上執(zhí)行,如圖: 增加后如圖
[測試測量]
LabVIEW——<font color='red'>數組</font>
STM32 USART與USB接收不定數據方法,標準庫、HAL庫都適用
很多時候,我們使用串口或USB接收數據時,往往不知道PC端會發(fā)多長的數據下來, 為了解決這個不定數據接收問題,在此各提供一個解決思路。 串口數據不定接收: 由于STM32單片機帶IDLE中斷,所以利用這個中斷,可以接收不定長字節(jié)的數據, 由于STM32屬于ARM單片機,所以這篇文章的方法也適合其他的ARM單片機。 IDLE就是串口收到一幀數據后,發(fā)生的中斷。什么是一幀數據呢?比如說給單片機一 次發(fā)來1個字節(jié),或者一次發(fā)來8個字節(jié),這些一次發(fā)來的數據,就稱為一幀數據,也可以 叫做一包數據。 還有一個RXNE中斷,當接收到1個字節(jié),就會產生RXNE中斷,當接收到一幀數據,就 會產生IDLE中斷。比如給單片機一次性發(fā)送8個字
[單片機]
<font color='red'>STM32</font> USART與USB接收不定數據方法,標準庫、HAL庫都適用
STM32匯編程序閃爍LED燈1
在main函數中添加如下代碼: AREA |.text|, CODE, READONLY GPIOB_CRL EQU 0X40010C00 GPIOB_CRL_OUT EQU 1 21 ;1 21 GPIOB_ODR EQU 0X40010C0C GPIOB_ODR_OUT EQU 1 5 ;1 5 GPIOB_BSRR EQU 0X40010C10 GPIOB_BSRR_OFF EQU 1 5 ;1 5 GPIOB_BSRR_ON EQU 1 21 ;1 21 RCC_APB2ENR EQU 0x4002
[單片機]
STM32一文通(9) DMA
一. DMA簡介 DMA(Direct Memory Access,直接存儲器訪問) 傳輸將數據從一個地址空間復制到另外一個地址空間。而且不占用CPU 數據傳輸支持從外設到存儲器或者存儲器到存儲器,這里的存儲器可以是 SRAM 或者是 FLASH。 我們把外設簡稱為: P, 把寄存器簡稱為: M DMA 控制器包含了 DMA1 和 DMA2,其中 DMA1 有 7 個通道,DMA2 有 5 個通道,這里的通道可以理解為傳輸數據的一種管道。要注意的是 DMA2 只存在于大容量的單片機中。 1. DMA功能框圖 關鍵角色: DMA請求 : 發(fā)送方向MCU請求使用DMA通道發(fā)送數據 通道 : 傳輸數據的管道 具體通
[單片機]
STM32燒錄方法
STM32的學習 1:STM32F103的最小系統(tǒng)板的燒錄程序。 需要 USB TO TTL 模塊 stm32f103的最小系統(tǒng)板 以及杜邦線若干 USB TO TTL 模塊,與stm32f103最小系統(tǒng)板的連接 3.3v接3.3v gnd接gnd RX接stm32f103的A9引腳 TX接stm32f103的A10引腳 并且stm32f103的最小系統(tǒng)板的BOOT0置0,BOOT1置1,用燒錄工具把程序燒進去 程序燒錄完畢后,需要把T0和T1都置1才能正常執(zhí)行程序
[單片機]
【嵌入式】STM32開發(fā)板燒寫后程序無法正常運行
STM32在使用過程中經常會出現蜜汁卡死的情況,所以我準備專門寫篇文章來記錄下曾經遇到過的情況,小伙伴們看到可以少走些彎路。(持續(xù)更新) 情景一(已解決) 外設配置不完整,例如GPIO需要Speed、Mode、Pin這三個參數,如果少其中之一,編譯時不會報錯,但燒錄后無法正常運行,打開調試后則一直循環(huán)在某一段匯編指令下。 情景二(已解決) 硬件平臺是stm32F103RCT6開發(fā)板,通過下載器供3.3V電。燒寫程序后,開發(fā)板無任何反應,代碼無問題。打開調試模式后,反匯編界面顯示在這段無限循環(huán) //寄存器的值一直僅有R1會變。 0x1FFFF3B2 F8D01808 LDR r1, 0x1FFFF3B6 0549 L
[單片機]
單片機stm32零基礎入門之--初識STM32 標準庫
  CMSIS 標準及庫層次關系   因為基于Cortex 系列芯片采用的內核都是相同的,區(qū)別主要為核外的片上外設的差異,這些差異卻導致軟件在同內核,不同外設的芯片上移植困難。為了解決不同的芯片廠商生產的Cortex 微控制器軟件 的兼容性問題,ARM 與芯片廠商建立了CMSIS 標準(CortexMicroController Software Interface Standard)。   所謂CMSIS 標準,實際是新建了一個軟件抽象層。   CMSIS 標準中最主要的為CMSIS 核心層,它包括了:   內核函數層:其中包含用于訪問內核寄存器的名稱、地址定義,主要由ARM 公司提供。   設備外設訪問層:提供了片上的核
[單片機]
小廣播
設計資源 培訓 開發(fā)板 精華推薦

最新單片機文章
何立民專欄 單片機及嵌入式寶典

北京航空航天大學教授,20余年來致力于單片機與嵌入式系統(tǒng)推廣工作。

 
EEWorld訂閱號

 
EEWorld服務號

 
汽車開發(fā)圈

 
機器人開發(fā)圈

電子工程世界版權所有 京ICP證060456號 京ICP備10001474號-1 電信業(yè)務審批[2006]字第258號函 京公網安備 11010802033920號 Copyright ? 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
主站蜘蛛池模板: 来凤县| 金昌市| 靖江市| 望都县| 潢川县| 广东省| 长武县| 仲巴县| 八宿县| 岑巩县| 比如县| 塔城市| 衡山县| 巫山县| 汉源县| 巴楚县| 新安县| 芮城县| 义马市| 廉江市| 东山县| 肃宁县| 杂多县| 凤冈县| 商丘市| 斗六市| 福鼎市| 凯里市| 巴塘县| 韶关市| 阳春市| 连平县| 泾阳县| 阳城县| 宜章县| 维西| 广宗县| 响水县| 万盛区| 长寿区| 新龙县|