【直达本质】超快 STM32 系统入门指南
?計(jì)算機(jī)類的教程多,框架和 API 用法講的全面,成系統(tǒng)的教程很多,CSDN上、知乎上很多個(gè)人學(xué)習(xí)記錄和全面的成書(shū)的教程,而且生動(dòng)形象有甚至有動(dòng)畫(huà)講解,回過(guò)頭來(lái)看嵌入式的教程,又臭又長(zhǎng)。本文 Github 地址。
兩種學(xué)習(xí)模式,一種是從底層開(kāi)始看大厚書(shū)學(xué)習(xí),但這只適合那些理解能力和前后關(guān)聯(lián)能力強(qiáng)甚至有天賦的人來(lái)看,說(shuō)白了不是設(shè)計(jì)給新人看的,而是給熟練的人當(dāng)字典來(lái)看的,現(xiàn)在學(xué)校的課本一上來(lái)直接懟抽象的概念和公式,可能導(dǎo)致的在網(wǎng)上寫(xiě)教程的也有這毛病,不人性化。另一種學(xué)習(xí)是面向應(yīng)用來(lái)學(xué),就是下面要說(shuō)的,是 “真-面向應(yīng)用”,對(duì)于超快 STM32 入門(mén)來(lái)說(shuō)就是:聽(tīng)正常人能理解的句子來(lái)了解外設(shè)概念和意義,然后直接從 API 入手。
這篇文章需要有 基本數(shù)模電和單片機(jī)的概念、C 語(yǔ)言基礎(chǔ)和良好英文(或翻譯)。
目錄
第一個(gè)外設(shè)
進(jìn)入主題
資源站
總結(jié)
第一個(gè)外設(shè)
這時(shí)候可以備好 STM32 編程手冊(cè)《STM32F10xxx參考手冊(cè)》。
GPIO(General-purpose input/output)為通用目的輸入輸出口,所謂通用即不只可以用軟件控制高低電平的變化,還有輸入、開(kāi)漏等功能,根據(jù)不同應(yīng)用場(chǎng)景配置成不同功能。以下是該外設(shè)的內(nèi)部數(shù)字電路的電路框圖。
該圖就是 STM32 芯片 里面 GPIO 外設(shè)部分的真實(shí)存在的電路的框圖。
下面兩個(gè) P-MOS 和 N-MOS 就是控制輸出 I/O 口的高低電平,如果 P-MOS 導(dǎo)通,則輸出高電平,這稱為 “推挽輸出” 模式,輸出有一定的驅(qū)動(dòng)能力,輸出高電平為 芯片供電電壓,即 3.3V,低電平為接地,即 0V,可以先這么理解。
如果 下面兩個(gè) P-MOS 和 N-MOS 均不導(dǎo)通,那就是 “浮空輸入” 模式,外接的高低電平可以讀入,外部接上按鍵,就可以用按鍵控制東西。
如果 輸出的時(shí)候是 P-MOS 一直處于關(guān)閉狀態(tài),而只有 N-MOS 打開(kāi)或關(guān)閉,那就是 “開(kāi)漏輸出” 模式,在該口上拉一個(gè)電阻到 Vref 電壓,那么輸出高電平就是 Vref 電壓,這么做可以改變輸出高電平的電壓,可以任定,而不是上面 “推挽輸出” 時(shí)候固定的 3.3V。
圖中還有還有上、下拉電阻,還有復(fù)用功能,就是配置別的外設(shè)比如 SPI、PWM 等的輸出要從此 I/O 輸出,這些功能組合可以得到這些模式:輸入浮空、輸入上拉、輸入下拉、模擬輸入、開(kāi)漏輸出、推挽式輸出、推挽式復(fù)用功能、開(kāi)漏復(fù)用功能。
進(jìn)入主題
下載、安裝和會(huì)用 STM32CubeMX 軟件。
STM32CubeMX 新建一個(gè)工程,選擇 STM32F103C8T6,將 PA8 設(shè)為 推挽輸出模式,如下圖。
導(dǎo)出工程。路徑不要有中文和空格,IDE 選擇 MDK(即 Keil 5),右上角生成。
打開(kāi) MDK 工程。
打開(kāi) main.c 即看到寫(xiě)用戶程序的地方,我們?cè)?STM32CubeMX 軟件里面圖形化的配置了一個(gè)推挽輸出模式的 PA8 引腳,所以現(xiàn)在工程中有了一個(gè) MX_GPIO_Init() 函數(shù),里面就是通過(guò) HAL 庫(kù)配置該 I/O 的程序。下面添加上注釋來(lái)說(shuō)明。
/* 聲明一個(gè) GPIO_InitTypeDef 類型的結(jié)構(gòu)體 名叫 GPIO_InitStruct,該結(jié)構(gòu)體打包了配置 I/O 的所有參數(shù),填這個(gè)結(jié)構(gòu)體即可 */GPIO_InitTypeDef GPIO_InitStruct = {0};/* 使能 GPIO 的時(shí)鐘,STM32 中,每個(gè)外設(shè)都要有時(shí)鐘信號(hào)做驅(qū)動(dòng),數(shù)字電路尤其是時(shí)序、同步邏輯電路,當(dāng)然都需要時(shí)鐘 *//* GPIO Ports Clock Enable */__HAL_RCC_GPIOA_CLK_ENABLE();/* 預(yù)先設(shè)置該 I/O 的輸出電壓。在初始化之前,I/O 是浮空的,當(dāng)初始化完畢之后 I/O 立馬變?yōu)樵O(shè)置的高或低電平 *//*Configure GPIO pin Output Level */HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET);/* 配置 I/O,結(jié)構(gòu)體 GPIO_InitStruct 共有 Pin、Mode、Pull 和 Speed 這幾個(gè)參數(shù),分別填為 I/O口 8、推挽輸出、沒(méi)有上下拉電阻、翻轉(zhuǎn)速度為低然后調(diào)用 HAL_GPIO_Init() 函數(shù),填入 結(jié)構(gòu)體 GPIO_InitStruct 的指針,該函數(shù)會(huì)根據(jù)結(jié)構(gòu)體 GPIO_InitStruct 里面的參數(shù)配置 I/O 的寄存器 *//*Configure GPIO pin : PA8 */GPIO_InitStruct.Pin = GPIO_PIN_8;GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);那么問(wèn)題就來(lái)了,結(jié)構(gòu)體 GPIO_InitStruct 共有 Pin、Mode、Pull 和 Speed 這幾個(gè)參數(shù),除此之外,庫(kù)里面外設(shè)那么多,每個(gè)外設(shè)都有好幾個(gè)結(jié)構(gòu)體和那么多 API,我怎么知道怎么用?
先進(jìn)行全編譯,如下圖。不全編譯不能做下一步的 “跳轉(zhuǎn)”。
在 GPIO_InitTypeDef 上面右擊,選擇 Go To Definition Of 'GPIO_InitTypeDef',即可跳轉(zhuǎn)到 stm32f1xx_hal_gpio.h 文件里面 該結(jié)構(gòu)體類型定義的地方。
在這里面,一目了然,該結(jié)構(gòu)體都有哪些參數(shù),每一個(gè)參數(shù)都是做什么的,如下圖。
那么每一個(gè)參數(shù)可以填寫(xiě)的值,HAL 庫(kù)也有定義,每一項(xiàng)后面都有注釋,比如上圖的 Mode 參數(shù),注釋說(shuō) 可填入的值 參考 GPIO_mode_define這里,那么就 按快捷鍵 ctrl+f 調(diào)出搜索框,填入GPIO_mode_define搜索,如下圖,找到這些宏定義。其中GPIO_MODE_INPUT就是浮空輸入模式,GPIO_MODE_OUTPUT_OD就是開(kāi)漏輸出模式,GPIO_MODE_ANALOG就是模擬輸入模式(用于 ADC 模數(shù)轉(zhuǎn)換外設(shè)引腳),帶有 AF 字樣的就是復(fù)用功能,帶有 IT 字樣的就是中斷功能。
HAL 庫(kù)好就好在,每個(gè)外設(shè)的配置流程和結(jié)構(gòu)體、宏定義的命名非常規(guī)范,命名有意義而且有規(guī)律。結(jié)構(gòu)體知道怎么填寫(xiě)了,那么想知道一個(gè)外設(shè)有哪些 API,就在每一個(gè)外設(shè)的 .h 文件里面。還在stm32f1xx_hal_gpio.h里面,如下圖所示,就是 GPIO 外設(shè)所有的可供用戶調(diào)用的函數(shù),即Exported functions部分。其中HAL_GPIO_Init()為初始化函數(shù),HAL_GPIO_ReadPin()為讀 I/O 電平函數(shù),HAL_GPIO_WritePin()為寫(xiě) I/O 電平函數(shù),等等。
還有最后一件事,這些 API 在哪里使用,比如初始化時(shí)候先用什么后用什么,這些也在源碼注釋里有詳細(xì)的介紹,請(qǐng)打開(kāi)stm32f1xx_hal_gpio.c文件,拉到最上面,如下圖。兩大塊,第一個(gè)GPIO Peripheral features就是介紹該外設(shè)的特性,即能做什么,另一個(gè)How to use this driver就是細(xì)致介紹如何使用這些 API,即怎么做,需要會(huì)英文或者用翻譯哈。這里介紹的是 GPIO 外設(shè),HAL 庫(kù)具有一貫性,對(duì)于每一個(gè)外設(shè)的源文件和組織形式都是這樣的哈,比較人性化。
我跟你講,大多數(shù)第一個(gè)寫(xiě)教程的,基本都是看源碼、看源碼注釋和看官方手冊(cè),再加上不斷測(cè)試、驗(yàn)證想法而得到足夠多經(jīng)驗(yàn)的時(shí)候才學(xué)會(huì)的,所以我這里把這個(gè)從源頭獲取技能的流程介紹一遍,是更有用的。
該工程還包括的函數(shù)SystemClock_Config()用于 STM32 時(shí)鐘(RCC)初始化,其它還包括 STM32 的眾多外設(shè),在此不多做介紹,漁已經(jīng)演示了。還有一些底層概念需要了解,接著往下看。
看看 MDK 界面中左邊的各種源文件:
-
main.c:就是用戶寫(xiě)主程序的地方。
-
startup_stm32f103xb.s:該文件是官方用匯編寫(xiě)成的啟動(dòng)文件,MCU 是微處理器,處理器就是一個(gè)復(fù)雜的數(shù)字電路,該電路的核心有很多寄存器(處理器寄存器)需要初始化,啟動(dòng)文件就是把這些初始化程序固定下來(lái),用戶不用管也不用改動(dòng),主要內(nèi)容有初始化中斷向量表、定義堆棧空間、準(zhǔn)備 C 語(yǔ)言環(huán)境和跳轉(zhuǎn)到 main() 函數(shù)等等。
ARM Cortex-M 系列處理器在函數(shù)跳轉(zhuǎn)的時(shí)候有硬件自動(dòng)的使用棧來(lái)保存現(xiàn)場(chǎng)和恢復(fù)現(xiàn)場(chǎng):
ARM 系列系列詳細(xì)看這篇文章【主線劇情 番外01】ARM & SOC 系列快速鳥(niǎo)瞰 - 知乎 (zhihu.com),
棧和跳轉(zhuǎn)等可以看 【主線劇情01】ARM & i.MX6ULL 基礎(chǔ)學(xué)習(xí)記錄 - 知乎 (zhihu.com) 這篇文章最后的 “ARM異常處理 & 啟動(dòng)文件的示例” 章節(jié),雖然這些知識(shí)點(diǎn)對(duì)于新人有點(diǎn)超前了。
-
stm32f1xx_hal_gpio.h 和 stm32f1xx_hal_gpio.c :這類文件就是 HAL 庫(kù)的源文件,操作外設(shè)就調(diào)用這些文件里面的 API 即可,所有 API 和詳細(xì)使用方法 在 .h 和 .c 文件的注釋里均有詳細(xì)說(shuō)明。
-
stm32f103xb.h:該文件定義 stm32f103xb 系列 MCU 的所有 外設(shè)的寄存器,給各個(gè)外設(shè)的寄存器地址上面加個(gè)結(jié)構(gòu)體,以便訪問(wèn)和修改,下文會(huì)幫助理解這段話。
MCU 的外設(shè)的寄存器都被映射到內(nèi)存的各個(gè)地址上(物理連接),在 C 語(yǔ)言中讀/寫(xiě)該寄存器,就是讀該外設(shè)的狀態(tài)和控制外設(shè)行為,外設(shè)本質(zhì)都是數(shù)字電路,外設(shè)只會(huì)根據(jù)寄存器內(nèi) 0 / 1 二進(jìn)制值去做對(duì)應(yīng)的行為。
以下例子,比如要對(duì)內(nèi)存中 0x20E0084 位置開(kāi)始的四個(gè)字節(jié)進(jìn)行復(fù)位(寫(xiě) 0)和置位(寫(xiě) 1)的操作,C 語(yǔ)言寫(xiě)法如下(程序引自 Staok/coding-style-and-more):
static volatile unsigned int *reg_temp = (volatile unsigned int *)(0x20E0084);/* 置位的標(biāo)準(zhǔn)寫(xiě)法 */ /* 下句表示把 內(nèi)存中 0x20E0084 位置的 第1、2、5、14位進(jìn)行置1,其他位不變 */ *reg_temp |= ( (1 << 14) | (1 << 5) | (1 << 2) | (1 << 1) );/* 清位的標(biāo)準(zhǔn)寫(xiě)法 */ /* 下句表示把 內(nèi)存中 0x20E0084 位置的 第0、3位進(jìn)行清0,其他位不變 */ *reg_temp &= ( ~( (1 << 3) | (1 << 0) ) );/* 讀寄存器 */ volatile unsigned int val = *reg_temp;進(jìn)一步,MCU 有上千個(gè)寄存器,這么一個(gè)一個(gè)定義肯定不行,下面就是 HAL 庫(kù)里面的方法,將結(jié)構(gòu)體的地址賦值為相應(yīng)寄存器的地址,即創(chuàng)建內(nèi)存地址上連續(xù)區(qū)域的結(jié)構(gòu)體,該方法常用于嵌入式開(kāi)發(fā)。如下例子(程序引自 Staok/coding-style-and-more):
typedef struct {volatile unsigned int URXD; /**< UART Receiver Register, offset: 0x00 */volatile unsigned char RESERVED_0[60];volatile unsigned int UTXD; /**< UART Transmitter Register, offset: 0x40 */volatile unsigned int UCR1; /**< UART Transmitter Register, offset: 0x44 */ } Periph_x_Type;/* Periph_x 這個(gè)外設(shè)的寄存器的基地址為 0x2020000 */ #define Periph_x_BASE (0x2020000u)/* 設(shè)置結(jié)構(gòu)體 Periph_x 的地址為 Periph_x_BASE */ #define Periph_x ((Periph_x_Type *)Periph_x_BASE)/* 讀取和設(shè)置寄存器(這里以置位舉例) */ Periph_x->UCR1 |= (1 << 2);接著打開(kāi)stm32f103xb.h文件,看看是不是所有外設(shè)的寄存器都被打包成了結(jié)構(gòu)體,然后把結(jié)構(gòu)體的地址賦值為對(duì)應(yīng)寄存器的地址。
比如 TIM2(定時(shí)器 2) 外設(shè)的寄存器地址定義如下,外設(shè)基地址 + 外設(shè)偏移地址。
然后定義將所有 TIM 外設(shè)有關(guān)的寄存器打包的結(jié)構(gòu)體,如下圖所示。
然后將 TIM2 的地址(TIM2_BASE)強(qiáng)轉(zhuǎn)為T(mén)IM_TypeDef指針類型,然后將這個(gè)整體重命名為 TIM2,如下圖。
到此,該外設(shè)寄存器地址與該結(jié)構(gòu)體綁定完成,以后訪問(wèn)結(jié)構(gòu)體 TIM2 下面的參數(shù),都是直接訪問(wèn)對(duì)應(yīng)的實(shí)體寄存器。
STM32 HAL 庫(kù)將這些對(duì)寄存器的操作封裝成了函數(shù),調(diào)用函數(shù)即可操控外設(shè)。
STM32 的庫(kù)函數(shù)有兩個(gè),標(biāo)準(zhǔn)庫(kù) 和 HAL 庫(kù),前者早在 2011 年停止更新維護(hù), HAL 庫(kù)是現(xiàn)行主流的,STM32CubeMX 軟件生成的工程就是使用 HAL 庫(kù)的,不過(guò)我不太信任用該軟件生成的工程,而且該軟件產(chǎn)生的工程所用的 HAL 庫(kù)與單獨(dú)下載 HAL 庫(kù)在 API 上竟有出入,所以一般我習(xí)慣拿它來(lái)產(chǎn)生驅(qū)動(dòng)配置程序,然后手動(dòng)移植到自己的工程,這樣心里有底。
以上描述的過(guò)程是自己探索與發(fā)現(xiàn)的形式,就像探索世界,但可能也會(huì)遇到很多新東西和困難,有參考總歸比沒(méi)有強(qiáng),推薦可以同時(shí)參考一個(gè)手冊(cè)來(lái)學(xué),比如正點(diǎn)原子的 STM32 的 HAL 庫(kù)的手冊(cè),開(kāi)源的可以免費(fèi)下載,下面就是各大廠的資料網(wǎng)址匯總。
資源站
各大廠家對(duì) STM32 出了特別特別特別豐富的教程和例程,如果比較熟悉外設(shè),直接看他們的例程源碼即可,快速掌握各種技巧。各大家的官網(wǎng)和資料下載地址如下:
正點(diǎn)原子:
-
OpenEdv-開(kāi)源電子網(wǎng)-正點(diǎn)原子論壇 有問(wèn)題可以在這里找,也可以平時(shí)沒(méi)事逛一逛;
-
正點(diǎn)原子官方的個(gè)人空間_ 嗶哩嗶哩 _bilibili 所有教學(xué)視頻;
-
原子哥教學(xué)平臺(tái),專注電子技術(shù)教學(xué) (yuanzige.com);
-
正點(diǎn)原子資料下載中心 — 正點(diǎn)原子資料下載中心 1.0.0 文檔 (openedv.com) 各種開(kāi)發(fā)板的電路原理圖、例程和教程 統(tǒng)統(tǒng)薅走!
野火:
-
野火電子論壇 - (firebbs.cn) 論壇;
-
野火_ firege的個(gè)人空間 _ 嗶哩嗶哩 _bilibili 所有教學(xué)視頻;
-
野火產(chǎn)品資料下載中心 — 野火產(chǎn)品資料下載中心 文檔 (embedfire.com) 薅羊毛。
安富萊:
-
硬漢嵌入式論壇 - Powered by Discuz! (armbbs.cn) 論壇;
-
武漢安富萊電子有限公司官方網(wǎng)站。STM32開(kāi)發(fā)板,無(wú)線IO模塊,H7-TOOL工具,嵌入式系統(tǒng) (armfly.com) 官網(wǎng);
-
【安富萊】各種開(kāi)發(fā)板和模塊的資料下載匯總貼(2021-08-30) - 安富萊電子 - 博客園 (cnblogs.com) 資料下載站。
硬石:
-
硬石電子 - 社區(qū) (ing10bbs.com) 論壇;
-
硬石科技的個(gè)人空間_ 嗶哩嗶哩 _bilibili 教學(xué)視頻;
-
硬石開(kāi)源資料下載鏈接(該帖總是最新資料) - 硬石資料更新 - 硬石社區(qū)社區(qū) (ing10bbs.com) 資料下載站。
原子、野火、安富萊和硬石各有側(cè)重,可以廣泛借鑒:野火、正點(diǎn)原子 非常全面;安富萊偏 M4F 的 DSP 使用;硬石偏電機(jī)控制,有步進(jìn)電機(jī)、有、無(wú)刷電機(jī)。
STM32 官網(wǎng)資料下載站,是源頭,可以找到任何官方的東西,包括選型手冊(cè),好好把握:
-
中文站:STM32 | 產(chǎn)品 | STM32/STM8 | MCU單片機(jī) | 意法半導(dǎo)體STM | 意法半導(dǎo)體STM | STM32/STM8微控制器 | MCU單片機(jī) (stmcu.com.cn);
-
ST 官方:微控制器與微處理器 - STMicroelectronics。
總結(jié)
上述方法一句話總結(jié)。外設(shè)的概念,比如 FSMC、DMA 等,可以先上網(wǎng)查,知道它是做什么的(比如 UART 外設(shè)是串口來(lái)收發(fā)數(shù)據(jù),I2C、SPI,重點(diǎn)看明白時(shí)序圖,FSMC 是 SRAM 接口外設(shè),DMA 是數(shù)據(jù)在內(nèi)存間通過(guò)硬件傳輸?shù)耐緩角也徽加锰幚砥髻Y源,等等),然后用 STM32CubeMX 生成例程,看外設(shè)如何初始化(看例程學(xué)習(xí)是最快的),然后看源碼注釋了解 API 詳細(xì)使用(當(dāng)成字典隨用隨查),就用起來(lái)一個(gè)外設(shè)了,然后按此法循環(huán)每一個(gè)外設(shè),外設(shè)都依照此方法一個(gè)一個(gè)擊破,精神集中的話沒(méi)幾天就掌握不少外設(shè)的使用了。
這里有一個(gè) STM32 程序模板 Staok/stm32_framework (github.com),其幾乎寫(xiě)好了大部分外設(shè)的驅(qū)動(dòng),大塊復(fù)制的時(shí)候要注意其開(kāi)源協(xié)議。這里有一個(gè) C 語(yǔ)言的編寫(xiě)規(guī)范 Staok/coding-style-and-more (github.com),其幾乎 “無(wú)所不包”。
要知道適合大多數(shù)人的上道的學(xué)習(xí),是先會(huì)用(會(huì)快速獲得成就感,如同游戲般及時(shí)獲得反饋),然后再去了解架構(gòu)和細(xì)節(jié)方面的東西(有興趣、有信心了之后才會(huì)面對(duì)這些而不犯怵),當(dāng)用的比較熟了之后,有了一些自己的感悟和理解,然后去 干 大部頭的教程,比如幾十個(gè)小時(shí)的視頻或者上千頁(yè)的 PDF(推薦只看 PDF 文字教程而不去看視頻教程)。
—— 我一直覺(jué)得,應(yīng)該減少人們走彎路,這也是 “二項(xiàng)玻”定則 中 “簡(jiǎn)化之能夠簡(jiǎn)化” 的一個(gè)重要延申理念。peace。
首發(fā)? 知乎?Github 地址?于 2021.9
總結(jié)
以上是生活随笔為你收集整理的【直达本质】超快 STM32 系统入门指南的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 解决Vue跨域问题 : 正向代理与反向代
- 下一篇: 网易云音乐极速版,开屏无广告,免升级,无