第7章 使用寄存器點亮LED燈—零死角玩轉STM32-F429系列


第7章     使用寄存器點亮LED燈

全套200集視頻教程和1000PDF教程請到秉火論壇下載:www.firebbs.cn

野火視頻教程優酷觀看網址:http://i.youku.com/firege

 

本章參考資料:《STM32F4xx 中文參考手冊》、《STM32F429規格書》。

學習本章時,配合《STM32F4xx 中文參考手冊》"通用I/O(GPIO)"章節一起閱讀,效果會更佳,特別是涉及到寄存器說明的部分。關於建立工程時使用KEIL5的基本操作,請參考前面的章節。

7.1 GPIO簡介

GPIO是通用輸入輸出端口的簡稱,簡單來說就是STM32可控制的引腳,STM32芯片的GPIO引腳與外部設備連接起來,從而實現與外部通訊、控制以及數據采集的功能。STM32芯片的GPIO被分成很多組,每組有16個引腳,如型號為STM32F4IGT6型號的芯片有GPIOAGPIOBGPIOCGPIOI9GPIO,芯片一共176個引腳,其中GPIO就占了一大部分,所有的GPIO引腳都有基本的輸入輸出功能。

最基本的輸出功能是由STM32控制引腳輸出高、低電平,實現開關控制,如把GPIO引腳接入到LED燈,那就可以控制LED燈的亮滅,引腳接入到繼電器或三極管,那就可以通過繼電器或三極管控制外部大功率電路的通斷。

最基本的輸入功能是檢測外部輸入電平,如把GPIO引腳連接到按鍵,通過電平高低區分按鍵是否被按下。

7.2 GPIO框圖剖析

71 GPIO結構框圖

通過GPIO硬件結構框圖,就可以從整體上深入了解GPIO外設及它的各種應用模式。該圖從最右端看起,最右端就是代表STM32芯片引出的GPIO引腳,其余部件都位於芯片內部。

7.2.1 基本結構分析

下面我們按圖中的編號對GPIO端口的結構部件進行說明。

1.    保護二極管及上、下拉電阻

引腳的兩保護個二級管可以防止引腳外部過高或過低的電壓輸入,當引腳電壓高於VDD_FT時,上方的二極管導通,當引腳電壓低於VSS時,下方的二極管導通,防止不正常電壓引入芯片導致芯片燒毀。盡管有這樣的保護,並不意味着STM32的引腳能直接外接大功率驅動器件,如直接驅動電機,強制驅動要么電機不轉,要么導致芯片燒壞,必須要加大功率及隔離電路驅動。具體電壓、電流范圍可查閱《STM32F4xx規格書》。

上拉、下拉電阻,從它的結構我們可以看出,通過上、下拉對應的開關配置,我們可以控制引腳默認狀態的電壓,開啟上拉的時候引腳電壓為高電平,開啟下拉的時候引腳電壓為低電平,這樣可以消除引腳不定狀態的影響。如引腳外部沒有外接器件,或者外部的器件不干擾該引腳電壓時,STM32的引腳都會有這個默認狀態。

也可以設置"既不上拉也不下拉模式",我們也把這種狀態稱為浮空模式,配置成這個模式時,直接用電壓表測量其引腳電壓為1點幾伏,這是個不確定值。所以一般來說我們都會選擇給引腳設置"上拉模式"或"下拉模式"使它有默認狀態。

STM32的內部上拉是"弱上拉",即通過此上拉輸出的電流是很弱的,如要求大電流還是需要外部上拉。

通過"上拉/下拉寄存器GPIOx_PUPDR"控制引腳的上、下拉以及浮空模式。

2.    P-MOS管和N-MOS管

GPIO引腳線路經過上、下拉電阻結構后,向上流向"輸入模式"結構,向下流向"輸出模式"結構。先看輸出模式部分,線路經過一個由P-MOSN-MOS管組成的單元電路。這個結構使GPIO具有了"推挽輸出"和"開漏輸出"兩種模式。

所謂的推挽輸出模式,是根據這兩個MOS管的工作方式來命名的。在該結構中輸入高電平時,上方的P-MOS導通,下方的N-MOS關閉,對外輸出高電平;而在該結構中輸入低電平時,N-MOS管導通,P-MOS關閉,對外輸出低電平。當引腳高低電平切換時,兩個管子輪流導通,一個負責灌電流,一個負責拉電流,使其負載能力和開關速度都比普通的方式有很大的提高。推挽輸出的低電平為0伏,高電平為3.3伏,參考圖 72左側,它是推挽輸出模式時的等效電路。

72 等效電路

而在開漏輸出模式時,上方的P-MOS管完全不工作。如果我們控制輸出為0,低電平,則P-MOS管關閉,N-MOS管導通,使輸出接地,若控制輸出為1 (它無法直接輸出高電平)時,則P-MOS管和N-MOS管都關閉,所以引腳既不輸出高電平,也不輸出低電平,為高阻態。為正常使用時必須接上拉電阻(可用STM32的內部上拉,但建議在STM32外部再接一個上拉電阻),參考圖 72中的右側等效電路。它具"線與"特性,也就是說,若有很多個開漏模式引腳連接到一起時,只有當所有引腳都輸出高阻態,才由上拉電阻提供高電平,此高電平的電壓為外部上拉電阻所接的電源的電壓。若其中一個引腳為低電平,那線路就相當於短路接地,使得整條線路都為低電平,0伏。

推挽輸出模式一般應用在輸出電平為03.3伏而且需要高速切換開關狀態的場合。在STM32的應用中,除了必須用開漏模式的場合,我們都習慣使用推挽輸出模式。

開漏輸出一般應用在I2CSMBUS通訊等需要"線與"功能的總線電路中。除此之外,還用在電平不匹配的場合,如需要輸出5伏的高電平,就可以在外部接一個上拉電阻,上拉電源為5伏,並且把GPIO設置為開漏模式,當輸出高阻態時,由上拉電阻和電源向外輸出5伏的電平。

通過"輸出類型寄存器GPIOx_OTYPER"可以控制GPIO端口是推挽模式還是開漏模式。

3.    輸出數據寄存器

前面提到的雙MOS管結構電路的輸入信號,是由GPIO"輸出數據寄存器GPIOx_ODR"提供的,因此我們通過修改輸出數據寄存器的值就可以修改GPIO引腳的輸出電平。而"置位/復位寄存器GPIOx_BSRR"可以通過修改輸出數據寄存器的值從而影響電路的輸出。

4.    復用功能輸出

"復用功能輸出"中的"復用"是指STM32的其它片上外設對GPIO引腳進行控制,此時GPIO引腳用作該外設功能的一部分,算是第二用途。從其它外設引出來的"復用功能輸出信號"與GPIO本身的數據據寄存器都連接到雙MOS管結構的輸入中,通過圖中的梯形結構作為開關切換選擇。

例如我們使用USART串口通訊時,需要用到某個GPIO引腳作為通訊發送引腳,這個時候就可以把該GPIO引腳配置成USART串口復用功能,由串口外設控制該引腳,發送數據。

5.    輸入數據寄存器

GPIO結構框圖的上半部分,它是GPIO引腳經過上、下拉電阻后引入的,它連接到施密特觸發器,信號經過觸發器后,模擬信號轉化為01的數字信號,然后存儲在"輸入數據寄存器GPIOx_IDR"中,通過讀取該寄存器就可以了解GPIO引腳的電平狀態。

6.    復用功能輸入

與"復用功能輸出"模式類似,在"復用功能輸出模式"時,GPIO引腳的信號傳輸到STM32其它片上外設,由該外設讀取引腳狀態。

同樣,如我們使用USART串口通訊時,需要用到某個GPIO引腳作為通訊接收引腳,這個時候就可以把該GPIO引腳配置成USART串口復用功能,使USART可以通過該通訊引腳的接收遠端數據。

7.    模擬輸入輸出

GPIO引腳用於ADC采集電壓的輸入通道時,用作"模擬輸入"功能,此時信號是不經過施密特觸發器的,因為經過施密特觸發器后信號只有01兩種狀態,所以ADC外設要采集到原始的模擬信號,信號源輸入必須在施密特觸發器之前。類似地,當GPIO引腳用於DAC作為模擬電壓輸出通道時,此時作為"模擬輸出"功能,DAC的模擬信號輸出就不經過雙MOS管結構了,在GPIO結構框圖的右下角處,模擬信號直接輸出到引腳。同時,當GPIO用於模擬功能時(包括輸入輸出),引腳的上、下拉電阻是不起作用的,這個時候即使在寄存器配置了上拉或下拉模式,也不會影響到模擬信號的輸入輸出。

7.2.2 GPIO工作模式

總結一下,由GPIO的結構決定了GPIO可以配置成以下模式:

1.    輸入模式(上拉/下拉/浮空)

在輸入模式時,施密特觸發器打開,輸出被禁止。數據寄存器每隔1AHB1時鍾周期更新一次,可通過輸入數據寄存器GPIOx_IDR讀取I/O狀態。其中AHB1的時鍾如按默認配置一般為180MHz

用於輸入模式時,可設置為上拉、下拉或浮空模式。

2.    輸出模式(推挽/開漏,上拉/下拉)

在輸出模式中,輸出使能,推挽模式時雙MOS管以方式工作,輸出數據寄存器GPIOx_ODR可控制I/O輸出高低電平。開漏模式時,只有N-MOS管工作,輸出數據寄存器可控制I/O輸出高阻態或低電平。輸出速度可配置,有2MHz\25MHz\50MHz\100MHz的選項。此處的輸出速度即I/O支持的高低電平狀態最高切換頻率,支持的頻率越高,功耗越大,如果功耗要求不嚴格,把速度設置成最大即可。

此時施密特觸發器是打開的,即輸入可用,通過輸入數據寄存器GPIOx_IDR可讀取I/O的實際狀態。

用於輸出模式時,可使用上拉、下拉模式或浮空模式。但此時由於輸出模式時引腳電平會受到ODR寄存器影響,而ODR寄存器對應引腳的位為0,即引腳初始化后默認輸出低電平,所以在這種情況下,上拉只起到小幅提高輸出電流能力,但不會影響引腳的默認狀態。

3.    復用功能(推挽/開漏,上拉/下拉)

復用功能模式中,輸出使能,輸出速度可配置,可工作在開漏及推挽模式,但是輸出信號源於其它外設,輸出數據寄存器GPIOx_ODR無效;輸入可用,通過輸入數據寄存器可獲取I/O實際狀態,但一般直接用外設的寄存器來獲取該數據信號。

用於復用功能時,可使用上拉、下拉模式或浮空模式。同輸出模式,在這種情況下,初始化后引腳默認輸出低電平,上拉只起到小幅提高輸出電流能力,但不會影響引腳的默認狀態。

4.    模擬輸入輸出

模擬輸入輸出模式中,雙MOS管結構被關閉,施密特觸發器停用,上/下拉也被禁止。其它外設通過模擬通道進行輸入輸出。

通過對GPIO寄存器寫入不同的參數,就可以改變GPIO的應用模式,再強調一下,要了解具體寄存器時一定要查閱《STM32F4xx參考手冊》中對應外設的寄存器說明。在GPIO外設中,通過設置"模式寄存器GPIOx_MODER"可配置GPIO的輸入/輸出/復用/模擬模式,"輸出類型寄存器GPIOx_OTYPER"配置推挽/開漏模式,配置"輸出速度寄存器GPIOx_OSPEEDR"可選2/25/50/100MHz輸出速度,"上/下拉寄存器GPIOx_PUPDR"可配置上拉/下拉/浮空模式,各寄存器的具體參數值見表 71

71 GPIO寄存器的參數配置

模式寄存器的MODER[0:1]

輸出類型寄存器的OTYPER

輸出速度寄存器的OSPEEDR

/下拉寄存器的PUPDR[0:1]

01 -輸出模式

0 -推挽模式
1 -
開漏模式

00 -速度2MHz
01 -
速度25MHz
10 -
速度50MHz
11 -
速度100MHz

00 -無上拉無下拉
01 -
上拉
10 -
下拉
11 -
保留

10 -復用模式

00 -輸入模式

不可用

不可用

11 -模擬功能

不可用

不可用

00 -無上拉無下拉
01 -
保留
10 -
保留
11 -
保留

7.3 實驗:使用寄存器點亮LED燈

本小節中,我們以實例講解如何通過控制寄存器來點亮LED燈。此處側重於講解原理,請您直接用KEIL5軟件打開我們提供的實驗例程配合閱讀,先了解原理,學習完本小節后,再嘗試自己建立一個同樣的工程。本節配套例程名稱為"GPIO輸出—寄存器點亮LED燈",在工程目錄下找到后綴為".uvprojx"的文件,用KEIL5打開即可。

自己嘗試新建工程時,請對照查閱《用KEIL5新建工程模版寄存器版本》章節。

若沒有安裝KEIL5軟件,請參考《如何安裝KEIL5》章節。

打開該工程,見圖 73,可看到一共有三個文件,分別startup_stm32f429_439xx.s stm32f4xx.h 以及main.c,下面我們對這三個工程進行講解。

73 工程文件結構

7.3.1 硬件連接

在本教程中STM32芯片與LED燈的連接見圖 74

74 LED燈電路連接圖

圖中從3LED燈的陽極引出連接到3.3V電源,陰極各經過1個電阻引入至STM323GPIO引腳PH10PH11PH12中,所以我們只要控制這三個引腳輸出高低電平,即可控制其所連接LED燈的亮滅。如果您的實驗板STM32連接到LED燈的引腳或極性不一樣,只需要修改程序到對應的GPIO引腳即可,工作原理都是一樣的。

我們的目標是把GPIO的引腳設置成推挽輸出模式並且默認下拉,輸出低電平,這樣就能讓LED燈亮起來了。

7.3.2 啟動文件

名為"startup_stm32f429_439xx.s"的文件,它里邊使用匯編語言寫好了基本程序,當STM32芯片上電啟動的時候,首先會執行這里的匯編程序,從而建立起C語言的運行環境,所以我們把這個文件稱為啟動文件。該文件使用的匯編指令是Cortex-M4內核支持的指令,可從《Cortex-M4 Technical Reference Manual》查到,也可參考《Cortex-M3權威指南中文》,M3M4大部分匯編指令相同。

startup_stm32f429_439xx.s文件是由官方提供的,一般有需要也是在官方的基礎上修改,不會自己完全重寫。該文件可以從 KEIL5 安裝目錄找到,也可以從 ST 庫里面找到,找到該文件后把啟動文件添加到工程里面即可。不同型號的芯片以及不同編譯環境下使用的匯編文件是不一樣的,但功能相同。

對於啟動文件這部分我們主要總結它的功能,不詳解講解里面的代碼,其功能如下:

    初始化堆棧指針SP;

    初始化程序計數器指針PC;

    設置堆、棧的大小;

    設置中斷向量表的入口地址;

    配置外部SRAM作為數據存儲器(這個由用戶配置,一般的開發板可沒有外部SRAM;

    調用SystemIni() 函數配置STM32的系統時鍾。

    設置C庫的分支入口"__main"(最終用來調用main函數);

 

先去除繁枝細節,挑重點的講,主要理解最后兩點,在啟動文件中有一段復位后立即執行的程序,代碼見代碼清單 71。在實際工程中閱讀時,可使用編輯器的搜索(Ctrl+F)功能查找這段代碼在文件中的位置。

代碼清單 71復位后執行的程序

1 ;Reset handler

2 Reset_Handler PROC

3 EXPORT Reset_Handler [WEAK]

4     IMPORT SystemInit

5     IMPORT __main

6

7         LDR R0, =SystemInit

8         BLX R0

9         LDR R0, =__main

10         BX R0

11         ENDP

開頭的是程序注釋,在匯編里面注釋用的是";",相當於 C 語言的"//"注釋符

第二行是定義了一個子程序:Reset_HandlerPROC 是子程序定義偽指令。這里就相當於C語言里定義了一個函數,函數名為Reset_Handler

第三行 EXPORT 表示 Reset_Handler 這個子程序可供其他模塊調用。相當於C語言的函數聲明。關鍵字[WEAK] 表示弱定義,如果編譯器發現在別處定義了同名的函數,則在鏈接時用別處的地址進行鏈接,如果其它地方沒有定義,編譯器也不報錯,以此處地址進行鏈接,如果不理解WEAK,那就忽略它好了。

第四行和第五行 IMPORT 說明 SystemInit __main 這兩個標號在其他文件,在鏈接的時候需要到其他文件去尋找。相當於C語言中,從其它文件引入函數聲明。以便下面對外部函數進行調用。

SystemInit 需要由我們自己實現,即我們要編寫一個具有該名稱的函數,用來初始化 STM32 芯片的時鍾,一般包括初始化AHBAPB等各總線的時鍾,需要經過一系列的配置STM32才能達到穩定運行的狀態。

__main 其實不是我們定義的(不要與C語言中的main函數混淆),當編譯器編譯時,只要遇到這個標號就會定義這個函數,該函數的主要功能是:負責初始化棧、堆,配置系統環境,准備好C語言並在最后跳轉到用戶自定義的 main 函數,從此來到 C 的世界。

第六行把 SystemInit 的地址加載到寄存器 R0

第七行程序跳轉到 R0 中的地址執行程序,即執行SystemInit函數的內容。

第八行把__main 的地址加載到寄存器 R0

第九行程序跳轉到 R0 中的地址執行程序,即執行__main函數,執行完畢之后就去到我們熟知的 C 世界,進入main函數。

第十行表示子程序的結束。

總之,看完這段代碼后,了解到如下內容即可:我們需要在外部定義一個SystemInit函數設置STM32的時鍾;STM32上電后,會執行SystemInit函數,最后執行我們C語言中的main函數。

7.3.3 stm32f4xx.h文件

看完啟動文件,那我們立即寫SystemInitmain函數吧?別着急,定義好了SystemInit函數和main我們又能寫什么內容?連接LED燈的GPIO引腳,是要通過讀寫寄存器來控制的,就這樣空着手,如何控制寄存器呢。在上一章,我們知道寄存器就是特殊的內存空間,可以通過指針操作訪問寄存器。所以此處我們根據STM32的存儲分配先定義好各個寄存器的地址,把這些地址定義都統一寫在stm32f4xx.h文件中,見代碼清單 72

代碼清單 72 外設地址定義

1 /*片上外設基地址 */

2 #define PERIPH_BASE ((unsigned int)0x40000000)

3 /*總線基地址 */

4 #define AHB1PERIPH_BASE (PERIPH_BASE + 0x00020000)

5 /*GPIO外設基地址*/

6 #define GPIOH_BASE (AHB1PERIPH_BASE + 0x1C00)

7

8 /* GPIOH寄存器地址,強制轉換成指針 */

9 #define GPIOH_MODER *(unsigned int*)(GPIOH_BASE+0x00)

10 #define GPIOH_OTYPER *(unsigned int*)(GPIOH_BASE+0x04)

11 #define GPIOH_OSPEEDR *(unsigned int*)(GPIOH_BASE+0x08)

12 #define GPIOH_PUPDR *(unsigned int*)(GPIOH_BASE+0x0C)

13 #define GPIOH_IDR *(unsigned int*)(GPIOH_BASE+0x10)

14 #define GPIOH_ODR *(unsigned int*)(GPIOH_BASE+0x14)

15 #define GPIOH_BSRR *(unsigned int*)(GPIOH_BASE+0x18)

16 #define GPIOH_LCKR *(unsigned int*)(GPIOH_BASE+0x1C)

17 #define GPIOH_AFRL *(unsigned int*)(GPIOH_BASE+0x20)

18 #define GPIOH_AFRH *(unsigned int*)(GPIOH_BASE+0x24)

19

20 /*RCC外設基地址*/

21 #define RCC_BASE (AHB1PERIPH_BASE + 0x3800)

22 /*RCCAHB1時鍾使能寄存器地址,強制轉換成指針*/

23 #define RCC_AHB1ENR *(unsigned int*)(RCC_BASE+0x30)

GPIO外設的地址跟上一章講解的相同,不過此處把寄存器的地址值都直接強制轉換成了指針,方便使用。代碼的最后兩段是RCC外設寄存器的地址定義,RCC外設是用來設置時鍾的,以后我們會詳細分析,本實驗中只要了解到使用GPIO外設必須開啟它的時鍾即可。

7.3.4 main文件

現在就可以開始編寫程序了,在main文件中先編寫一個 main 函數,里面什么都沒有,暫時為空。

1 int main (void)

2 {

3 }

此時直接編譯的話,會出現如下錯誤:

"Error: L6218E: Undefined symbol SystemInit (referred from startup_stm32f429_439xx.o)"

錯誤提示SystemInit 沒有定義。從分析啟動文件時我們知道,Reset_Handler 調用了該函數用來初始化SMT32系統時鍾,為了簡單起見,我們在 main 文件里面定義一個 SystemInit 空函數,什么也不做,為的是騙過編譯器,把這個錯誤去掉。關於配置系統時鍾我們在后面再寫。當我們不配置系統時鍾時,STM32芯片會自動按系統內部的默認時鍾運行,程序還是能跑的。我們在main中添加如下函數:

1 // 函數為空,目的是為了騙過編譯器不報錯

2 void SystemInit(void)

3 {

4 }

這時再編譯就沒有錯了,完美解決。還有一個方法就是在啟動文件中把有關SystemInit 的代碼注釋掉也可以,見代碼清單 73

代碼清單 73 注釋掉啟動文件中調用SystemInit的代碼

1 ; Reset handler

2 Reset_Handler PROC

3 EXPORT Reset_Handler [WEAK]

4 ;IMPORT SystemInit

5 IMPORT __main

6

7 ;LDR R0, =SystemInit

8 ;BLX R0

9 LDR R0, =__main

10 BX R0

11 ENDP

接下來在main函數中添加代碼,對寄存器進行控制,寄存器的控制參數可參考表 71(點擊可跳轉)或《STM32F4xx參考手冊》。

1.    GPIO模式

首先我們把連接到LED燈的PH10引腳配置成輸出模式,即配置GPIOMODER寄存器,見圖 75MODER中包含0-15號引腳,每個引腳占用2個寄存器位。這兩個寄存器位設置成"01"時即為GPIO的輸出模式,見代碼清單 74

代碼清單 74 配置輸出模式

1 /*GPIOH MODER10清空*/

2 GPIOH_MODER &= ~( 0x03<< (2*10));

3 /*PH10 MODER10 = 01b 輸出模式*/

4 GPIOH_MODER |= (1<<2*10);

75 MODER寄存器說明(摘自《STM32F4xx參考手冊》)

在代碼中,我們先把GPIOH MODER寄存器的MODER10對應位清0,然后再向它賦值"01",從而使GPIOH10引腳設置成輸出模式。

代碼中使用了"&=~"、"|="這種復雜位操作方法是為了避免影響到寄存器中的其它位,因為寄存器不能按位讀寫,假如我們直接給MODER寄存器賦值:

1 GPIOH_MODER = 0x00100000;

這時MODER10的兩個位被設置成"01"輸出模式,但其它GPIO引腳就有意見了,因為其它引腳的MODER位都已被設置成輸入模式。

如果對此處"&=""|="這樣的位操作方法還不理解,請閱讀前面的《規范的位操作方法》小節。熟悉這種方法之后,會發現這樣按位操作其實比直接賦值還要直觀。

2.    輸出類型

GPIO輸出有推挽和開漏兩種類型,我們了解到開漏類型不能直接輸出高電平,要輸出高電平還要在芯片外部接上拉電阻,不符合我們的硬件設計,所以我們直接使用推挽模式。配置OTYPER寄存中的OTYPER10寄存器位,該位設置為0PH10引腳即為推挽模式,見代碼清單 75

代碼清單 75 設置為推挽模式

1 /*GPIOH OTYPER10清空*/

2 GPIOH_OTYPER &= ~(1<<1*10);

3 /*PH10 OTYPER10 = 0b 推挽模式*/

4 GPIOH_OTYPER |= (0<<1*10);

3.    輸出速度

GPIO引腳的輸出速度是引腳支持高低電平切換的最高頻率,本實驗可以隨便設置。此處我們配置OSPEEDR寄存器中的寄存器位OSPEEDR10即可控制PH10的輸出速度,見代碼清單 76

代碼清單 76 設置輸出速度為2MHz

1 /*GPIOH OSPEEDR10清空*/

2 GPIOH_OSPEEDR &= ~(0x03<<2*10);

3 /*PH10 OSPEEDR10 = 0b 速率2MHz*/

4 GPIOH_OSPEEDR |= (0<<2*10);

4.    上/下拉模式

GPIO引腳用於輸入時,引腳的上/下拉模式可以控制引腳的默認狀態。但現在我們的GPIO引腳用於輸出,引腳受ODR寄存器影響,ODR寄存器對應引腳位初始初始化后默認值為0,引腳輸出低電平,所以這時我們配置上/下拉模式都不會影響引腳電平狀態。但因此處上拉能小幅提高電流輸出能力,我們配置它為上拉模式,即配置PUPDR寄存器的PUPDR10位,設置為二進制值"01",見代碼清單 77

代碼清單 77 設置為下拉模式

1 /*GPIOH PUPDR10清空*/

2 GPIOH_PUPDR &= ~(0x03<<2*10);

3 /*PH10 PUPDR10 = 01b 下拉模式*/

4 GPIOH_PUPDR |= (1<<2*10);

5.    控制引腳輸出電平

在輸出模式時,對BSRR寄存器和ODR寄存器寫入參數即可控制引腳的電平狀態。簡單起見,此處我們使用BSRR寄存器控制,對相應的BR10位設置為1PH10即為低電平,點亮LED燈,對它的BS10位設置為1PH10即為高電平,關閉LED燈,見代碼清單 78

代碼清單 78 控制引腳輸出電平

1 /*PH10 BSRR寄存器的 BR101,使引腳輸出低電平*/

2 GPIOH_BSRR |= (1<<16<<10);

3

4 /*PH10 BSRR寄存器的 BS101,使引腳輸出高電平*/

5 GPIOH_BSRR |= (1<<10);

6.    開啟外設時鍾

設置完GPIO的引腳,控制電平輸出,以為現在總算可以點亮 LED 了吧,其實還差最后一步。

STM32芯片架構》的外設章節中提到STM32 外設很多,為了降低功耗,每個外設都對應着一個時鍾,在芯片剛上電的時候這些時鍾都是被關閉的,如果想要外設工作,必須把相應的時鍾打開。

STM32 的所有外設的時鍾由一個專門的外設來管理,叫 RCCreset and clockcontrol),RCC 在《 STM32 中文參考手冊》的第六章。

所有的 GPIO都掛載到 AHB1 總線上,所以它們的時鍾由AHB1外設時鍾使能寄存器(RCC_AHB1ENR)來控制,其中 GPIOH 端口的時鍾由該寄存器的位 7 1 使能,開啟GPIOH端口時鍾。以后我們還會詳細解釋STM32的時鍾系統,此處我們了解到在訪問GPIO的寄存器之前,要先使能它的時鍾即可,使用代碼清單 79中的代碼可以開啟GPIOH時鍾。

代碼清單 79 開啟端口時鍾

1 /*開啟 GPIOH 時鍾,使用外設時都要先開啟它的時鍾*/

2 RCC_AHB1ENR |= (1<<7);

7.    水到渠成

開啟時鍾,配置引腳模式,控制電平,經過這三步,我們總算可以控制一個 LED了。現在我們完整組織下用 STM32 控制一個 LED 的代碼,見代碼清單 710

代碼清單 710 main文件中控制LED燈的代碼

1

2 /*

3 使用寄存器的方法點亮LED

4 */

5 #include "stm32f4xx.h"

6

7

8 /**

9 * 主函數

10 */

11 int main(void)

12 {

13 /*開啟 GPIOH 時鍾,使用外設時都要先開啟它的時鍾*/

14 RCC_AHB1ENR |= (1<<7);

15

16 /* LED 端口初始化 */

17

18 /*GPIOH MODER10清空*/

19 GPIOH_MODER &= ~( 0x03<< (2*10));

20 /*PH10 MODER10 = 01b 輸出模式*/

21 GPIOH_MODER |= (1<<2*10);

22

23 /*GPIOH OTYPER10清空*/

24 GPIOH_OTYPER &= ~(1<<1*10);

25 /*PH10 OTYPER10 = 0b 推挽模式*/

26 GPIOH_OTYPER |= (0<<1*10);

27

28 /*GPIOH OSPEEDR10清空*/

29 GPIOH_OSPEEDR &= ~(0x03<<2*10);

30 /*PH10 OSPEEDR10 = 0b 速率2MHz*/

31 GPIOH_OSPEEDR |= (0<<2*10);

32

33 /*GPIOH PUPDR10清空*/

34 GPIOH_PUPDR &= ~(0x03<<2*10);

35 /*PH10 PUPDR10 = 01b 拉模式*/

36 GPIOH_PUPDR |= (1<<2*10);

37

38 /*PH10 BSRR寄存器的 BR101,使引腳輸出低電平*/

39 GPIOH_BSRR |= (1<<16<<10);

40

41 /*PH10 BSRR寄存器的 BS101,使引腳輸出高電平*/

42 //GPIOH_BSRR |= (1<<10);

43

44 while (1);

45

46 }

47

48 // 函數為空,目的是為了騙過編譯器不報錯

49 void SystemInit(void)

50 {

51 }

在本章節中,要求完全理解stm32f4xx.h文件及main文件的內容(RCC相關的除外)

7.3.1 下載驗證

把編譯好的程序下載到開發板並復位,可看到板子上的LED燈被點亮。

7.4 每課一問

1.    在《STM32F4xx參考手冊》中閱讀GPIO章節中的各個寄存器說明。

2.    對照本章節的工程文件,自己建立一個同樣的工程,可參考《用KEIL5新建工程模版 寄存器版本》、《如何安裝KEIL5》。

3.    修改本章節的工程文件,通過控制ODR寄存器點亮實驗板上的燈。

4.    修改本章節的工程文件,點亮實驗板上的其它LED燈。

5.    修改本章節的工程文件,控制LED燈閃爍,即循環亮、滅。(提示:在亮、滅控制之間加延時,才能讓肉眼看清閃爍)。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM