0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

掌握HAL API中面向?qū)ο笤O(shè)計的思想

冬至子 ? 來源:Researcher LC ? 作者:licedu ? 2023-06-26 17:25 ? 次閱讀

1. 初識HAL

ST 為開發(fā)者提供了三種的開發(fā)庫:

  1. 標(biāo)準(zhǔn)外設(shè)庫(Standard Peripheral Library, SPL庫)
  2. 硬件抽象層庫(Hardware Abstraction Layer,HAL庫)
  3. 底層庫(Low-Layer,底層庫)

其中,ST CubeMX軟件支持STM32全線產(chǎn)品的HAL和LL庫;SPL已經(jīng)停更,部分芯片如STM32F7xx沒有推出SPL庫。

相比標(biāo)準(zhǔn)外設(shè)庫,STM32 HAL庫擁有更好的抽象整合水平,HAL API(HAL Application Programming Interface,HAL應(yīng)用程序接口)集中關(guān)注各個外設(shè)(Peripheral)的公共函數(shù)功能,通過定義一套通用的、用戶友好的API函數(shù)接口,支持不同STM32系列產(chǎn)品之間的輕松移植。

以點(diǎn)亮LED的工程舉例。

1.首先配置MDK的代碼補(bǔ)全

Edit Configuration Text Completion Symbols after 3 Characters。

圖片

2.代碼補(bǔ)全效果。

HAL庫函數(shù)都以HAL作為開頭。打開代碼自動補(bǔ)全后,輸入HAL_GPIO即可彈出一系列支持的函數(shù),如下圖的Init(初始化)、LockPin(鎖引腳)、ReadPin(讀引腳)、TogglePin(翻轉(zhuǎn)引腳)等。

圖片

3.HAL支持哪些函數(shù)?

如下圖所示,點(diǎn)擊MDK左側(cè)工程欄下方的Functions,點(diǎn)開對應(yīng)的hal_xx.c文件,即可顯示出所有的HAL庫函數(shù)。

圖片

ST的HAL庫通過高度抽象化,使用統(tǒng)一的HAL API對硬件進(jìn)行操作。無論是使用STM32F1系列、L4系列、F7系列、H7系列等,對GPIO的初始化、讀、寫、翻轉(zhuǎn)操作都是如下的統(tǒng)一接口,極大地方便了開發(fā)者將相同的代碼移植到不同的ST系列芯片中。

  • void HAL_GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_Init)
  • GPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
  • void HAL_GPIO_WritePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState)
  • void HAL_GPIO_TogglePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)

CubeMX通過圖形化界面操作,配置各個引腳、外設(shè)的工作狀態(tài),自動生成驅(qū)動初始化代碼,方便用戶快速進(jìn)行底層功能部署,開發(fā)者只關(guān)注CubeMX圖形化界面的配置,可以不關(guān)注寫底層硬件寄存器,通過調(diào)用統(tǒng)一的HAL API實現(xiàn)外設(shè)各種功能,這是HAL的一個典型特點(diǎn)。

2. STM32 Manual

關(guān)于STM32L4系列的手冊,可以在https://www.st.com/zh/microcontrollers-microprocessors/stm32l4-series.html下載相關(guān)手冊。

圖片

ST系列常見文檔的命名規(guī)則如下:

1.AN, Application Note ,應(yīng)用手冊。一般是一些相對復(fù)雜、精細(xì)、精巧的應(yīng)用原理與結(jié)果介紹,閱讀門檻較高,建議熟悉芯片、熟悉嵌入式系統(tǒng)后,再根據(jù)具體開發(fā)工作需求進(jìn)行查找與閱讀。
2.DS, Data Sheet規(guī)格書。芯片手冊,說明芯片容量、芯片時序、芯片封裝等情況的文檔,一般用于硬件選型階段。
3.UM, User Manual ,用戶手冊,為開發(fā)者提供HAL庫使用說明、硬件使用說明等情況的文檔,開發(fā)階段可以作為參考書。瀏覽https://www.st.com/zh/embedded-software/stm32cubel4.html可以找到STM32L4系列的HAL庫UM手冊。本課程要求下載UM1884 Description of STM32L4/L4+ HAL and low-layer drivers.pdf手冊。建議將該手冊作為參考書,有需要時再查閱,不要通讀,以后該文件簡稱為UM1884.pdf文件。
RM, Reference Manual ,參考手冊。說明芯片內(nèi)部寄存器如何配置的手冊,本課程要求下載RM0394_STM32L41xxx/42xxx/43xxx/44xxx/45xxx/46xxx advanced Arm?-based 32-bit MCUs.pdf文件,對應(yīng)例程逐步深入了解。以后該文件簡稱為RM0394.pdf
4.PM, Programming Manual ,編程手冊,針對具體芯片,一般是RISC匯編指令的解讀,不推薦給初學(xué)者。
5.TN, Technical Note ,技術(shù)手冊,一般是一些芯片規(guī)格、封裝、PCB制版、Toolchains等軟硬件方面的雜項技術(shù)要點(diǎn)和進(jìn)一步解讀,不推薦給初學(xué)者。

3. 熟悉GPIO HAL Driver

STM32L431RCT6芯片有GPIOA~GPIOE、GPIOH等6個IO口,其中,每個IO口都有16個引腳,從GPIOx的PIN0 ~ PIN15。

在第一個EVB MX+的GPIO例程中,我們翻轉(zhuǎn)GPIOC的引腳13,實現(xiàn)LED的點(diǎn)亮和熄滅。

HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);

/* 其函數(shù)原型為 */
/**
  * @brief  Toggle the specified GPIO pin.
  * @param  GPIOx where x can be (A..H) to select the GPIO peripheral for STM32L4 family
  * @param  GPIO_Pin specifies the pin to be toggled.
  * @retval None
  */
void HAL_GPIO_TogglePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)

我們依次認(rèn)識GPIOCGPIO_PIN_13,從HAL庫的數(shù)據(jù)結(jié)構(gòu)、操作原理、STM32的GPIO結(jié)構(gòu)的角度,來逐步深入了解。GPIO是最基礎(chǔ)的內(nèi)容,掌握了GPIO的HAL操作原理,也就理解了USART、SPI、ADC、IIC等更復(fù)雜外設(shè)的HAL庫工作原理

3.1 回顧指針

3.1.1 內(nèi)存中的數(shù)據(jù)與數(shù)據(jù)類型

圖片

計算機(jī)的內(nèi)存,可以簡單看作一條長街上的一行房子,每一個房子內(nèi)能容納數(shù)據(jù),并且每一個房子具有獨(dú)一無二的編號。

圖片

  • 上圖中,每一個格子表示1個字節(jié),一個字節(jié)的無符號數(shù)的表示范圍是
  • 為了存儲更大的數(shù),我們也可以將4個字節(jié)看作一個單元,在32位計算機(jī)中,4個字節(jié)即一個字word

圖片

計算機(jī)中所有的數(shù)據(jù)都必須放在內(nèi)存中,不同類型的數(shù)據(jù)占用的字節(jié)數(shù)不一樣。如 int 占用 4 個字節(jié),char 占用 1 個字節(jié)。為了正確地訪問這些數(shù)據(jù),必須為每個字節(jié)都編上號碼,就像門牌號、身份證號一樣,每個字節(jié)的編號是唯一的,根據(jù)編號可以準(zhǔn)確地找到某個字節(jié)。

我們將內(nèi)存中字節(jié)的編號稱為地址(Address)。地址從 0 開始依次增加。對于32位環(huán)境,程序能夠使用的內(nèi)存為 4GB,最小的地址為0x00000000,最大的地址為0XFFFFFFFF

下圖是 4G 內(nèi)存中每個字的編號(以十進(jìn)制表示):

圖片

舉個簡單例子:下圖表明計算機(jī)中, 5個連續(xù)的字單元中的存儲內(nèi)容。

圖片

  • 不得不說,如果直接通過地址編號去讀取/修改這些數(shù)據(jù),是一件讓人為難的事情 ;
  • 高級語言提供了解決方案,支持通過變量名進(jìn)行訪問;
  • 通過變量名來訪問變量,對于開發(fā)者非常友好。但是要時刻記住計算機(jī)硬件依然是通過地址來訪問內(nèi)存單元(Hardware still accesses memory locations using addresses)

下圖和代碼表示通過變量名訪問內(nèi)存:

圖片

int a = 112, b = -1;
float c = 3.14;
int *d = &a;
float *e = &c;

在上述代碼中,變量d和e是指針,它們不是int和float類型,而分別是(int *)和(float *)類型,它們是變量,也存儲在內(nèi)存中。在變量d中,可以存儲int類型變量的地址,在變量e中,可以存儲float類型變量的地址。

通過前面的圖,我們已經(jīng)知道,變量a存儲在地址編號為100的格子中。如果需要將變量a的數(shù)值修改為200,則下面語句互相完全等價:

a = 200;
*d = 200; /*變量d之前的*,是指針變量的解引用操作符,derefrence,返回存儲在指針地址中的值*/
*( (int *)(100) ) = 200;
  • 第三條語句是典型的C語言Cast,即類型轉(zhuǎn)換。
  • 第三條語句將無符號數(shù)100強(qiáng)制轉(zhuǎn)換成了(int *)的指針,然后在編號為100的地址中寫入數(shù)據(jù)200。
  • 但是,務(wù)必要注意,這種寫法很危險。我們在編譯程序之后,一般并不知道某個變量在內(nèi)存中的存放地址,通過直接地址編號進(jìn)行數(shù)據(jù)操作,很容易造成程序崩潰。
  • 但是,ST HAL庫對內(nèi)部寄存器操作,卻主動采用了這種看似危險的做法。后文會清晰說明原因。

3.1.2 指針是變量

假設(shè)聲明的變量被依次存放在0x20000000UL地址開始的單元格內(nèi)。

unsignedint  a    = 0xFFFFFFFF; /*無符號數(shù)據(jù),4294967295*/
signedint    b    = -1;         /*有符號數(shù),-1*/
unsignedint  c    = 0xFFFFFFFD; /*無符號數(shù)據(jù),4294967293*/
signedint    d    = -2;         /*有符號數(shù),-2*/
unsignedint *pa   = &a;         /*指針變量pa指向a,即,將a的地址賦值給變量pa*/
unsignedint **ppa = &pa;        /*指針變量ppa指向pa,即,將pa的地址賦值給變量ppa*/
typedefstruct{
    unsignedint a;
    signedint b;
    unsignedint c;
    signedint   d;
}User_Typedef; /*自定義某個數(shù)據(jù)類型,將其命名為User_Typedef*/

User_Typedef data     = {0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFD,0xFFFFFFFD};
User_Typedef *pdata   = &data;  /*指針變量pdata指向data*/
User_Typedef **ppdata = &pdata; /*指針變量ppdata指向pdata*/

在C語言中,字節(jié)對齊的情況下,結(jié)構(gòu)體所占用的內(nèi)存是連續(xù)的,且每個成員也是連續(xù)存放的。在本例中,結(jié)構(gòu)體變量data中的各個成員data.a、data.b、data.c、data.d的內(nèi)存地址是連續(xù)的。因此,雖然兩段代碼表面上完全不同,但是程序編譯和運(yùn)行后,數(shù)據(jù)在內(nèi)存中的分布完全相同。

值得指出的是,結(jié)構(gòu)體指針中,存放的數(shù)據(jù)是結(jié)構(gòu)體變量第一個成員的地址。在本例中,data.a的地址,即0x20000000被賦值給了結(jié)構(gòu)體指針pdata。而pdata存放在編號為0x20000010的內(nèi)存地址中,所以該地址中存放的數(shù)據(jù)是0x20000000。

圖片

圖片

從上面的程序中可以看出:

  • C語言是強(qiáng)類型語言,不僅要聲明變量,還要關(guān)注變量類型。a和b的內(nèi)存地址中存放的數(shù)據(jù)其實是一樣的,但是因為類型不同,所以程序?qū)?shù)據(jù)的理解完全不同。
  • 指針也是變量,所以也需要存儲在某個內(nèi)存地址中。指針并不特殊,(Type *)類型的指針變量中,只能存儲Type類型變量的地址。此處的Type,適用于C語言的基礎(chǔ)類型數(shù)據(jù)、結(jié)構(gòu)體、聯(lián)合體、函數(shù)等各種類型。
  • 在32位環(huán)境中,一個指針變量占用4個字節(jié)的存儲空間,無論該指針是何種類型。

在第二段代碼中,可以用如下方式訪問結(jié)構(gòu)體中的各個成員,第5~7行完全等價。

User_Typedef data;/*data中的成員還沒有初始化*/
User_Typedef *pdata   = &data;  /*指針變量,pdata指向data*/
User_Typedef **ppdata = &pdata; /*指針變量,ppdata指向pdata*/

data.a       = 0xFFFFFFFF;
pdata- >a     = 0xFFFFFFFF;
(*ppdata)- >a = 0xFFFFFFFF

3.2 初識GPIOx

在GPIOC上點(diǎn)擊右鍵,選擇Go To Definition of 'GPIOC'

#define GPIOA               ((GPIO_TypeDef *) GPIOA_BASE)
#define GPIOB               ((GPIO_TypeDef *) GPIOB_BASE)
#define GPIOC               ((GPIO_TypeDef *) GPIOC_BASE)
#define GPIOD               ((GPIO_TypeDef *) GPIOD_BASE)
#define GPIOE               ((GPIO_TypeDef *) GPIOE_BASE)
#define GPIOH               ((GPIO_TypeDef *) GPIOH_BASE)

目前,先不管GPIO_TypeDef這種自定義的結(jié)構(gòu)體中含有哪些成員,但是我們可以清楚地知道,GPIOx是一個自定義的GPIO_TypeDef *類型的指針,通過GPIOx->member的方式,可以直接訪問到各個成員。

進(jìn)一步在GPIOC_BASE上點(diǎn)擊右鍵,依次得到:

#define GPIOA_BASE            (AHB2PERIPH_BASE + 0x0000UL)
#define GPIOB_BASE            (AHB2PERIPH_BASE + 0x0400UL)
#define GPIOC_BASE            (AHB2PERIPH_BASE + 0x0800UL)
#define GPIOD_BASE            (AHB2PERIPH_BASE + 0x0C00UL)
#define GPIOE_BASE            (AHB2PERIPH_BASE + 0x1000UL)
#define GPIOH_BASE            (AHB2PERIPH_BASE + 0x1C00UL)

#define AHB2PERIPH_BASE       (PERIPH_BASE + 0x08000000UL)

#define PERIPH_BASE           (0x40000000UL)

通過換算,GPIOA、GPIOB、GPIOC等實際上等價于:

#define GPIOA               ((GPIO_TypeDef *) (0x40800000UL))
#define GPIOB               ((GPIO_TypeDef *) (0x40800400UL))
#define GPIOC               ((GPIO_TypeDef *) (0x40800800UL))

結(jié)合C語言存儲結(jié)構(gòu)體變量的特點(diǎn),我們可以得出推論:以GPIOC為例,從地址0x40800800UL開始,是一段連續(xù)地址空間,這段連續(xù)的空間可以完整存儲GPIO_TypeDef類型的數(shù)據(jù)。但是,這一段連續(xù)地址空間到底占用了多少字節(jié)?我們還需要深入了解自定義結(jié)構(gòu)體GPIO_TypeDef。

3.3 深入了解GPIO_TypeDef

認(rèn)識GPIO_TypeDef,等于認(rèn)識了ST HAL中所有外設(shè)的xxx_TypeDef。在GPIO_TypeDef上點(diǎn)擊右鍵,選擇Go To Definition of 'GPIO_TypeDef',它是一個結(jié)構(gòu)體,包括MODER、OTYPER等成員,每個成員都是uint32_t類型(無符號32位整型),__IO表示volatile。每個成員的作用見下圖的注釋部分,翻譯成中文分別是模式寄存器、輸出模式寄存器、輸出速度寄存器、上拉-下拉寄存器、輸入數(shù)據(jù)寄存器、輸出數(shù)據(jù)寄存器、置位-復(fù)位寄存器、鎖定配置寄存器、復(fù)用功能寄存器、Bit復(fù)位寄存器。

圖片

在RM0394.pdf的274 ~ 275頁,有GPIOx的寄存器布局圖,其中x表示A ~ E,H

圖片

圖片

結(jié)合GPIOx的地址和寄存器布局圖,可以得到推論:

  • 如果要設(shè)置GPIOx的各個引腳模式,需要向GPIOx的MODER寄存器中寫入相應(yīng)數(shù)值;
  • 如果要設(shè)置GPIOx的各個引腳輸出模式,需要向GPIOx的OTYPER寄存器中寫入相應(yīng)數(shù)值;
  • GPIOA MODER的地址是0x40800000UL,GPIOA OTYPER的地址是0x40800004UL;
  • GPIOB MODER的地址是0x40800400UL,GPIOB OTYPER的地址是0x40800404UL;
  • GPIOC MODER的地址是0x40800800UL,GPIOC OTYPER的地址是0x40800804UL。

顯然,對于GPIOA ~ GPIOH,所有寄存器的布局是相同的,寄存器地址依次偏移4個字節(jié),圖示如下:

圖片

  • 圖中,每個地址都是32位的,每個地址中能容納的數(shù)據(jù)也是32位。
  • 地址0x40800000UL中寫入一個32位的數(shù)據(jù),等價于向GPIOA的MODER寄存器中寫入一個32位的數(shù)據(jù),顯然,地址編號不如寄存器名稱方便。
  • 在C語言中,字節(jié)對齊的情況下,結(jié)構(gòu)體所占用的內(nèi)存是連續(xù)的,且每個成員也是連續(xù)存放的。利用C語言的特性,HAL庫中聲明了一個自定義的結(jié)構(gòu)體GPIO_TypeDef,該結(jié)構(gòu)體的各個成員嚴(yán)格按照STM32L4xx系列的GPIOx各寄存器順序進(jìn)行排序,且每個成員都能容納(存儲)一個32位的數(shù)據(jù)。
  • 在STM32中,還有諸如USART、IIC、SPI、CAN、ADC等各種不同的外設(shè),自然也就有對應(yīng)的xxx_Typedef的自定義結(jié)構(gòu)體類型。下圖給出了USART_TypeDef的結(jié)構(gòu)體定義,我們無需查看手冊就知道在STM32處理器中,控制USART外設(shè)工作需要向CR1、CR2等系列寄存器寫入符合芯片RM手冊中規(guī)定的數(shù)據(jù)即可。USART_TypeDef的聲明如下圖所示:

圖片

3.4 進(jìn)一步了解GPIOx

#define GPIOC   ((GPIO_TypeDef *) (0x40800800UL))

define是一個宏,表示GPIOC等價于((GPIO_TypeDef *) (0x40800800UL))。因此,GPIOC本質(zhì)上是GPIO_TypeDef *類型的指針。

Q&A

Q1: 如何對GPIOA的MODER寄存器執(zhí)行寫操作?如何對GPIOC的OTYPER寄存器執(zhí)行寫操作?

A1: ->是C語言中的指向結(jié)構(gòu)體成員運(yùn)算符,用于使用指向某種結(jié)構(gòu)的指針來訪問結(jié)構(gòu)內(nèi)的成員。使用GPIOA->MODE = 0x1234; GPIOC->OTYPER= 0x789A;即可完成GPIOA和GPIOC對應(yīng)寄存器的數(shù)據(jù)寫入。

Q2: (0x40800800UL)是一個整形數(shù)據(jù),也能轉(zhuǎn)化為指針嗎?

A2: 通過前文,已經(jīng)知道GPIOx的所有寄存器在STM32的內(nèi)存中,是連續(xù)存放的。而C語言的結(jié)構(gòu)體在字節(jié)對齊的情況下,內(nèi)部成員也是連續(xù)存放的,且結(jié)構(gòu)體指針指向結(jié)構(gòu)體第一個成員的地址。利用這個特點(diǎn),將數(shù)據(jù)0x40800800UL強(qiáng)制轉(zhuǎn)換為(GPIO_TypeDef *)類型的指針,那么,從0x40800800UL到0x40800828UL地址段,每4個字節(jié)就對應(yīng)GPIOx中的一個寄存器,完美構(gòu)建了軟件與硬件的溝通橋梁。

Q3: 如果不用宏表示GPIOC,那么GPIOC->OTYPER = 0x1234應(yīng)該用什么形式實現(xiàn)?

A3: ( (GPIO_TypeDef *) (0x40800800UL) )->OTYPER = 0x1234;,意味著,程序?qū)⒃L問0x40800800UL開始的地址空間內(nèi)的OTYPER成員,即將32位的十六進(jìn)制數(shù)據(jù)0x1234寫入地址0x40800804UL。顯然,這種寫法很難看,不如GPIOC->OTYPER 直觀。

3.5 HAL API的設(shè)計

在C語言中,指針是最核心的內(nèi)容,也是難點(diǎn)。通過前文分析,我們已經(jīng)知道指針只是變量而已,并不復(fù)雜,HAL庫中所用的指針很簡單。

現(xiàn)在對比兩種不同方式設(shè)計的HAL_GPIO_TogglePin函數(shù),其中,方式1是ST HAL官方庫的正確設(shè)計,方式2是不合理方案。

/* 方式1:HAL庫官方方案*/
void HAL_GPIO_TogglePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
/* 方式2:不合理方案*/    
GPIO_TypeDef HAL_GPIO_TogglePin(GPIO_TypeDef GPIOx, uint16_t GPIO_Pin)

/* 方式1:HAL庫官方方案進(jìn)行函數(shù)調(diào)用*/
HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
/* 方式2:不合理方案進(jìn)行函數(shù)調(diào)用*/
*(GPIOC) = HAL_GPIO_TogglePin(*(GPIOC), GPIO_PIN_13);

C 語言使用傳值調(diào)用方法來傳遞參數(shù),即將形參的值復(fù)制給實參。在發(fā)生函數(shù)調(diào)用時,形參的存放地址空間來源于堆棧。

方式1:HAL庫官方方案進(jìn)行函數(shù)調(diào)用:

  • 第一個實參的值,GPIOC,即0x40800800UL 被復(fù)制給了形參GPIOx,占用4個字節(jié);
  • 第二個實參的值,GPIO_PIN_13,被復(fù)制給了形參GPIO_Pin,占用4個字節(jié)。
  • 堆棧在形參上的開銷至少是8個字節(jié)。
  • 傳遞指針GPIOC的值給了臨時變量GPIOx,臨時變量GPIOx存放的具體地址不明,但是,可直接通過GPIOx->MODE = xx的方式,即( (GPIO_TypeDef *) (0x40800800UL) )->MODE = xx,以地址訪問的形式直接修改了GPIOC MODE寄存器所對應(yīng)的內(nèi)存,從而成功修改寄存器的值。

方式2:不合理方案進(jìn)行函數(shù)調(diào)用:

  • 第一個實參的值,*GPIOC,即從0x40800800UL到0x40800828UL地址空間內(nèi)的所有數(shù)據(jù),被復(fù)制給了形參GPIOx,合計占用44字節(jié);
  • 第二個實參的值,GPIO_PIN_13,被復(fù)制給了形參GPIO_Pin,占用4個字節(jié)。
  • 堆棧在形參上的開銷至少是48個字節(jié)。
  • 由于GPIOx是個GPIO_TypeDef類型的臨時變量,存放的具體地址不明,即使在程序中使用GPIOx.MODE修改了GPIOx成員MODE的數(shù)值,也不會真正影響GPIOC->MODE。GPIOC->MODE表示地址0x40800800UL,而GPIOx.MODE肯定不存放在該地址,修改GPIOx.MODE中存放的數(shù)值,自然不可能影響到內(nèi)存地址0x40800800UL,必須通過函數(shù)返回值進(jìn)行賦值,而這又會帶來一系列堆棧開銷。

1.jpg

綜上,對比兩種設(shè)計方法,毫無疑問是HAL庫提供的方式1效果更加,更加高效,占用內(nèi)存更少。HAL庫中,都是通過傳遞指針來進(jìn)行API函數(shù)設(shè)計的。

4. 小結(jié)

  1. HAL的精髓在于Abstract抽象。
  2. STM32的RM、UM手冊是基礎(chǔ),AN手冊是進(jìn)階。
  3. 指針到底是什么?指針是變量。
  4. 指向int指針和指向結(jié)構(gòu)體的指針的相同點(diǎn)在于,在32位環(huán)境中占用4個字節(jié);不同點(diǎn)是存儲不同類型變量的地址。
  5. HAL的GPIO_TypeDef之類的xxx_TypeDef是嚴(yán)格與RM手冊中的寄存器分布一一對應(yīng)的。
  6. HAL庫通過封裝xxx_TypeDef類型的指針,利用C語言的結(jié)構(gòu)體實現(xiàn)了典型的面向?qū)ο缶幊痰乃悸贰?/li>
聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • C語言
    +關(guān)注

    關(guān)注

    180

    文章

    7594

    瀏覽量

    135864
  • GPIO
    +關(guān)注

    關(guān)注

    16

    文章

    1188

    瀏覽量

    51836
  • STM32L4
    +關(guān)注

    關(guān)注

    1

    文章

    42

    瀏覽量

    9374
  • HAL庫
    +關(guān)注

    關(guān)注

    1

    文章

    114

    瀏覽量

    6144
收藏 人收藏

    評論

    相關(guān)推薦

    Linux內(nèi)核面向對象編程的實現(xiàn)

    面向對象編程(OOP),是一種設(shè)計思想或者架構(gòu)風(fēng)格。OO語言之父Alan Kay,Smalltalk的發(fā)明人,在談到OOP時是這樣說的。
    發(fā)表于 07-21 14:51 ?558次閱讀

    面向對象思想讓裸編程帶上靈魂

    告訴我:寫好的程序不是如何去完成代碼,而是如何去組織代碼,是如何組織,不是組織。上位機(jī)面向對象的編程思想,就是一個非常可取的思想。
    發(fā)表于 11-24 10:00

    如何用C語言實現(xiàn)面向對象編程

    1 用C語言實現(xiàn)面向對象編程GOF的《設(shè)計模式》一書的副標(biāo)題叫做“可復(fù)用面向對象軟件的基礎(chǔ)”,從標(biāo)題就能看出面向
    發(fā)表于 07-12 07:24

    談?wù)?b class='flag-5'>面向對象編程

    工業(yè)控制系統(tǒng)的PLC程序也可以采用這種設(shè)計思想,雖然我們無法實現(xiàn)面向對象的很多優(yōu)秀特點(diǎn)如“繼承”,甚至于它根本就不具備面向
    發(fā)表于 09-08 07:47

    面向對象編程語言的特點(diǎn)

    工業(yè)控制系統(tǒng)的PLC程序也可以采用這種設(shè)計思想,雖然我們無法實現(xiàn)面向對象的很多優(yōu)秀特點(diǎn)如“繼承”,甚至于它根本就不具備面向
    發(fā)表于 09-08 07:44

    面向對象編程的基本概念及其特點(diǎn)

    面向對象編程是計算機(jī)高級語言的一種先進(jìn)的編程模式,在工業(yè)控制系統(tǒng)的PLC程序也可以采用這種設(shè)計思想,雖然我們無法實現(xiàn)面向
    發(fā)表于 09-09 06:33

    面向對象編程介紹

    5.項目案例: 棧與隊列的封裝5.1 棧的封裝5.2 隊列的封裝一、面向對象編程介紹1.面向過程編程“面向過程”(Procedure Oriented)是一種以過程為中心的編程
    發(fā)表于 12-13 07:22

    面向對象編程練習(xí)

    實驗 3 面向對象編程練習(xí) 一、實驗?zāi)康?    通過編程和上機(jī)實驗理解 Java 語言是如何體現(xiàn)面向對象編程基本思想
    發(fā)表于 09-23 18:57 ?3034次閱讀

    面向過程和面向對象有什么區(qū)別

    面向過程(pop)和面向對象(oop)是什么  1. pop(Process-oriented programming)的縮寫,“面向過程”是一種是事件為中心的編程
    發(fā)表于 05-13 18:12 ?2次下載
    <b class='flag-5'>面向</b>過程和<b class='flag-5'>面向</b><b class='flag-5'>對象</b>有什么區(qū)別

    在單片機(jī)引入面向對象思想

    的代碼也無法使用,得重新敲,代碼重用度不高,編程效率低下,代碼無法積累。而且感覺寫這個代碼沒有思想,沒有靈魂,沒有框架,只是一個一個功能代碼的堆砌,很空泛。 那么這個時候,你也許應(yīng)該在單片機(jī)引入面向
    的頭像 發(fā)表于 11-01 11:36 ?1913次閱讀

    C/C++之面向對象編程思想1

    C++作為一門在C和Java之間的語言,其既可以使用C語言中的高效指針,又繼承了Java面向對象編程思想,在去年編程語言排行榜上更是首次超過Java,進(jìn)入前三。
    的頭像 發(fā)表于 03-30 15:14 ?609次閱讀
    C/C++之<b class='flag-5'>面向</b><b class='flag-5'>對象</b>編程<b class='flag-5'>思想</b>1

    C/C++之面向對象編程思想2

    C++作為一門在C和Java之間的語言,其既可以使用C語言中的高效指針,又繼承了Java面向對象編程思想,在去年編程語言排行榜上更是首次超過Java,進(jìn)入前三。
    的頭像 發(fā)表于 03-30 15:14 ?549次閱讀
    C/C++之<b class='flag-5'>面向</b><b class='flag-5'>對象</b>編程<b class='flag-5'>思想</b>2

    C/C++之面向對象編程思想3

    C++作為一門在C和Java之間的語言,其既可以使用C語言中的高效指針,又繼承了Java面向對象編程思想,在去年編程語言排行榜上更是首次超過Java,進(jìn)入前三。
    的頭像 發(fā)表于 03-30 15:16 ?534次閱讀
    C/C++之<b class='flag-5'>面向</b><b class='flag-5'>對象</b>編程<b class='flag-5'>思想</b>3

    面向對象思想封裝IIC、AT24C64驅(qū)動

    使用面向對象的編程思想封裝IIC驅(qū)動,將IIC的屬性和操作封裝成一個庫,在需要創(chuàng)建一個IIC設(shè)備時只需要實例化一個IIC對象即可,本文是基于STM32和
    的頭像 發(fā)表于 10-08 15:35 ?840次閱讀

    淺談C語言面向對象編程思想

    C語言是一種面向過程的語言,但是也可以用結(jié)構(gòu)體和函數(shù)指針來模擬面向對象的特性,比如封裝、繼承和多態(tài)。
    發(fā)表于 11-02 12:27 ?990次閱讀