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

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

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

如何通過控制寄存器來點(diǎn)亮LED燈

454398 ? 來源:csdn ? 作者:0木木0 ? 2020-09-30 15:40 ? 次閱讀

學(xué)習(xí)本章時(shí),配合《STM32F4xx中文參考手冊(cè)》"通用I/O(GPIO)"章節(jié)一起閱讀,效果會(huì)更佳,特別是涉及到寄存器說明的部分。關(guān)于建立工程時(shí)使用KEIL5的基本操作,請(qǐng)參考前面的章節(jié)。

7.1 GPIO簡(jiǎn)介

GPIO是通用輸入輸出端口的簡(jiǎn)稱,簡(jiǎn)單來說就是STM32可控制的引腳,STM32芯片的GPIO引腳與外部設(shè)備連接起來,從而實(shí)現(xiàn)與外部通訊、控制以及數(shù)據(jù)采集的功能。STM32芯片的GPIO被分成很多組,每組有16個(gè)引腳,如型號(hào)為STM32F4IGT6型號(hào)的芯片有GPIOA、GPIOB、GPIOC至GPIOI共9組GPIO,芯片一共176個(gè)引腳,其中GPIO就占了一大部分,所有的GPIO引腳都有基本的輸入輸出功能。

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

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

7.2 GPIO框圖剖析

圖71 GPIO結(jié)構(gòu)框圖

通過GPIO硬件結(jié)構(gòu)框圖,就可以從整體上深入了解GPIO外設(shè)及它的各種應(yīng)用模式。該圖從最右端看起,最右端就是代表STM32芯片引出的GPIO引腳,其余部件都位于芯片內(nèi)部。

7.2.1基本結(jié)構(gòu)分析

下面我們按圖中的編號(hào)對(duì)GPIO端口的結(jié)構(gòu)部件進(jìn)行說明。

1.保護(hù)二極管及上、下拉電阻

引腳的兩保護(hù)個(gè)二級(jí)管可以防止引腳外部過高或過低的電壓輸入,當(dāng)引腳電壓高于VDD_FT時(shí),上方的二極管導(dǎo)通,當(dāng)引腳電壓低于VSS時(shí),下方的二極管導(dǎo)通,防止不正常電壓引入芯片導(dǎo)致芯片燒毀。盡管有這樣的保護(hù),并不意味著STM32的引腳能直接外接大功率驅(qū)動(dòng)器件,如直接驅(qū)動(dòng)電機(jī),強(qiáng)制驅(qū)動(dòng)要么電機(jī)不轉(zhuǎn),要么導(dǎo)致芯片燒壞,必須要加大功率及隔離電路驅(qū)動(dòng)。具體電壓、電流范圍可查閱《STM32F4xx規(guī)格書》。

上拉、下拉電阻,從它的結(jié)構(gòu)我們可以看出,通過上、下拉對(duì)應(yīng)的開關(guān)配置,我們可以控制引腳默認(rèn)狀態(tài)的電壓,開啟上拉的時(shí)候引腳電壓為高電平,開啟下拉的時(shí)候引腳電壓為低電平,這樣可以消除引腳不定狀態(tài)的影響。如引腳外部沒有外接器件,或者外部的器件不干擾該引腳電壓時(shí),STM32的引腳都會(huì)有這個(gè)默認(rèn)狀態(tài)。

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

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

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

2.P-MOS管和N-MOS管

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

所謂的推挽輸出模式,是根據(jù)這兩個(gè)MOS管的工作方式來命名的。在該結(jié)構(gòu)中輸入高電平時(shí),上方的P-MOS導(dǎo)通,下方的N-MOS關(guān)閉,對(duì)外輸出高電平;而在該結(jié)構(gòu)中輸入低電平時(shí),N-MOS管導(dǎo)通,P-MOS關(guān)閉,對(duì)外輸出低電平。當(dāng)引腳高低電平切換時(shí),兩個(gè)管子輪流導(dǎo)通,一個(gè)負(fù)責(zé)灌電流,一個(gè)負(fù)責(zé)拉電流,使其負(fù)載能力和開關(guān)速度都比普通的方式有很大的提高。推挽輸出的低電平為0伏,高電平為3.3伏,參考圖72左側(cè),它是推挽輸出模式時(shí)的等效電路。

圖72等效電路

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

推挽輸出模式一般應(yīng)用在輸出電平為0和3.3伏而且需要高速切換開關(guān)狀態(tài)的場(chǎng)合。在STM32的應(yīng)用中,除了必須用開漏模式的場(chǎng)合,我們都習(xí)慣使用推挽輸出模式。

開漏輸出一般應(yīng)用在I2C、SMBUS通訊等需要"線與"功能的總線電路中。除此之外,還用在電平不匹配的場(chǎng)合,如需要輸出5伏的高電平,就可以在外部接一個(gè)上拉電阻,上拉電源為5伏,并且把GPIO設(shè)置為開漏模式,當(dāng)輸出高阻態(tài)時(shí),由上拉電阻和電源向外輸出5伏的電平。

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

3.輸出數(shù)據(jù)寄存器

前面提到的雙MOS管結(jié)構(gòu)電路的輸入信號(hào),是由GPIO"輸出數(shù)據(jù)寄存器GPIOx_ODR"提供的,因此我們通過修改輸出數(shù)據(jù)寄存器的值就可以修改GPIO引腳的輸出電平。而"置位/復(fù)位寄存器GPIOx_BSRR"可以通過修改輸出數(shù)據(jù)寄存器的值從而影響電路的輸出。

4.復(fù)用功能輸出

"復(fù)用功能輸出"中的"復(fù)用"是指STM32的其它片上外設(shè)對(duì)GPIO引腳進(jìn)行控制,此時(shí)GPIO引腳用作該外設(shè)功能的一部分,算是第二用途。從其它外設(shè)引出來的"復(fù)用功能輸出信號(hào)"與GPIO本身的數(shù)據(jù)據(jù)寄存器都連接到雙MOS管結(jié)構(gòu)的輸入中,通過圖中的梯形結(jié)構(gòu)作為開關(guān)切換選擇。

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

5.輸入數(shù)據(jù)寄存器

看GPIO結(jié)構(gòu)框圖的上半部分,它是GPIO引腳經(jīng)過上、下拉電阻后引入的,它連接到施密特觸發(fā)器,信號(hào)經(jīng)過觸發(fā)器后,模擬信號(hào)轉(zhuǎn)化為0、1的數(shù)字信號(hào),然后存儲(chǔ)在"輸入數(shù)據(jù)寄存器GPIOx_IDR"中,通過讀取該寄存器就可以了解GPIO引腳的電平狀態(tài)。

6.復(fù)用功能輸入

與"復(fù)用功能輸出"模式類似,在"復(fù)用功能輸出模式"時(shí),GPIO引腳的信號(hào)傳輸?shù)絊TM32其它片上外設(shè),由該外設(shè)讀取引腳狀態(tài)。

同樣,如我們使用USART串口通訊時(shí),需要用到某個(gè)GPIO引腳作為通訊接收引腳,這個(gè)時(shí)候就可以把該GPIO引腳配置成USART串口復(fù)用功能,使USART可以通過該通訊引腳的接收遠(yuǎn)端數(shù)據(jù)。

7.模擬輸入輸出

當(dāng)GPIO引腳用于ADC采集電壓的輸入通道時(shí),用作"模擬輸入"功能,此時(shí)信號(hào)是不經(jīng)過施密特觸發(fā)器的,因?yàn)榻?jīng)過施密特觸發(fā)器后信號(hào)只有0、1兩種狀態(tài),所以ADC外設(shè)要采集到原始的模擬信號(hào),信號(hào)源輸入必須在施密特觸發(fā)器之前。類似地,當(dāng)GPIO引腳用于DAC作為模擬電壓輸出通道時(shí),此時(shí)作為"模擬輸出"功能,DAC的模擬信號(hào)輸出就不經(jīng)過雙MOS管結(jié)構(gòu)了,在GPIO結(jié)構(gòu)框圖的右下角處,模擬信號(hào)直接輸出到引腳。同時(shí),當(dāng)GPIO用于模擬功能時(shí)(包括輸入輸出),引腳的上、下拉電阻是不起作用的,這個(gè)時(shí)候即使在寄存器配置了上拉或下拉模式,也不會(huì)影響到模擬信號(hào)的輸入輸出。

7.2.2GPIO工作模式

總結(jié)一下,由GPIO的結(jié)構(gòu)決定了GPIO可以配置成以下模式:

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

在輸入模式時(shí),施密特觸發(fā)器打開,輸出被禁止。數(shù)據(jù)寄存器每隔1個(gè)AHB1時(shí)鐘周期更新一次,可通過輸入數(shù)據(jù)寄存器GPIOx_IDR讀取I/O狀態(tài)。其中AHB1的時(shí)鐘如按默認(rèn)配置一般為180MHz。

用于輸入模式時(shí),可設(shè)置為上拉、下拉或浮空模式。

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

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

此時(shí)施密特觸發(fā)器是打開的,即輸入可用,通過輸入數(shù)據(jù)寄存器GPIOx_IDR可讀取I/O的實(shí)際狀態(tài)。

用于輸出模式時(shí),可使用上拉、下拉模式或浮空模式。但此時(shí)由于輸出模式時(shí)引腳電平會(huì)受到ODR寄存器影響,而ODR寄存器對(duì)應(yīng)引腳的位為0,即引腳初始化后默認(rèn)輸出低電平,所以在這種情況下,上拉只起到小幅提高輸出電流能力,但不會(huì)影響引腳的默認(rèn)狀態(tài)。

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

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

用于復(fù)用功能時(shí),可使用上拉、下拉模式或浮空模式。同輸出模式,在這種情況下,初始化后引腳默認(rèn)輸出低電平,上拉只起到小幅提高輸出電流能力,但不會(huì)影響引腳的默認(rèn)狀態(tài)。

4.模擬輸入輸出

模擬輸入輸出模式中,雙MOS管結(jié)構(gòu)被關(guān)閉,施密特觸發(fā)器停用,上/下拉也被禁止。其它外設(shè)通過模擬通道進(jìn)行輸入輸出。

通過對(duì)GPIO寄存器寫入不同的參數(shù),就可以改變GPIO的應(yīng)用模式,再?gòu)?qiáng)調(diào)一下,要了解具體寄存器時(shí)一定要查閱《STM32F4xx參考手冊(cè)》中對(duì)應(yīng)外設(shè)的寄存器說明。在GPIO外設(shè)中,通過設(shè)置"模式寄存器GPIOx_MODER"可配置GPIO的輸入/輸出/復(fù)用/模擬模式,"輸出類型寄存器GPIOx_OTYPER"配置推挽/開漏模式,配置"輸出速度寄存器GPIOx_OSPEEDR"可選2/25/50/100MHz輸出速度,"上/下拉寄存器GPIOx_PUPDR"可配置上拉/下拉/浮空模式,各寄存器的具體參數(shù)值見表71。

表71 GPIO寄存器的參數(shù)配置

7.3 實(shí)驗(yàn):使用寄存器點(diǎn)亮LED燈

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

自己嘗試新建工程時(shí),請(qǐng)對(duì)照查閱《用KEIL5新建工程模版寄存器版本》章節(jié)。

若沒有安裝KEIL5軟件,請(qǐng)參考《如何安裝KEIL5》章節(jié)。

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

圖73工程文件結(jié)構(gòu)

7.3.1硬件連接

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

圖74 LED燈電路連接圖

圖中從3個(gè)LED燈的陽極引出連接到3.3V電源,陰極各經(jīng)過1個(gè)電阻引入至STM32的3個(gè)GPIO引腳PH10、PH11、PH12中,所以我們只要控制這三個(gè)引腳輸出高低電平,即可控制其所連接LED燈的亮滅。如果您的實(shí)驗(yàn)板STM32連接到LED燈的引腳或極性不一樣,只需要修改程序到對(duì)應(yīng)的GPIO引腳即可,工作原理都是一樣的。

我們的目標(biāo)是把GPIO的引腳設(shè)置成推挽輸出模式并且默認(rèn)下拉,輸出低電平,這樣就能讓LED燈亮起來了。

7.3.2啟動(dòng)文件

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

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

對(duì)于啟動(dòng)文件這部分我們主要總結(jié)它的功能,不詳解講解里面的代碼,其功能如下:

  • 初始化堆棧指針SP;
  • 初始化程序計(jì)數(shù)器指針PC;
  • 設(shè)置堆、棧的大小;
  • 設(shè)置中斷向量表的入口地址;
  • 配置外部SRAM作為數(shù)據(jù)存儲(chǔ)器(這個(gè)由用戶配置,一般的開發(fā)板可沒有外部SRAM);
  • 調(diào)用SystemIni()函數(shù)配置STM32的系統(tǒng)時(shí)鐘。
  • 設(shè)置C庫(kù)的分支入口"__main"(最終用來調(diào)用main函數(shù));

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

代碼清單71復(fù)位后執(zhí)行的程序

1;Reset handler

2Reset_HandlerPROC

3EXPORT Reset_Handler [WEAK]

4 IMPORTSystemInit

5 IMPORT__main

6

7 LDR R0, =SystemInit

8 BLX R0

9 LDR R0, =__main

10 BXR0

11 ENDP

開頭的是程序注釋,在匯編里面注釋用的是";",相當(dāng)于C語言的"http://"注釋符

第二行是定義了一個(gè)子程序:Reset_Handler。PROC是子程序定義偽指令。這里就相當(dāng)于C語言里定義了一個(gè)函數(shù),函數(shù)名為Reset_Handler。

第三行EXPORT表示Reset_Handler這個(gè)子程序可供其他模塊調(diào)用。相當(dāng)于C語言的函數(shù)聲明。關(guān)鍵字[WEAK]表示弱定義,如果編譯器發(fā)現(xiàn)在別處定義了同名的函數(shù),則在鏈接時(shí)用別處的地址進(jìn)行鏈接,如果其它地方?jīng)]有定義,編譯器也不報(bào)錯(cuò),以此處地址進(jìn)行鏈接,如果不理解WEAK,那就忽略它好了。

第四行和第五行IMPORT說明SystemInit和__main這兩個(gè)標(biāo)號(hào)在其他文件,在鏈接的時(shí)候需要到其他文件去尋找。相當(dāng)于C語言中,從其它文件引入函數(shù)聲明。以便下面對(duì)外部函數(shù)進(jìn)行調(diào)用。

SystemInit需要由我們自己實(shí)現(xiàn),即我們要編寫一個(gè)具有該名稱的函數(shù),用來初始化STM32芯片的時(shí)鐘,一般包括初始化AHB、APB等各總線的時(shí)鐘,需要經(jīng)過一系列的配置STM32才能達(dá)到穩(wěn)定運(yùn)行的狀態(tài)。

__main其實(shí)不是我們定義的(不要與C語言中的main函數(shù)混淆),當(dāng)編譯器編譯時(shí),只要遇到這個(gè)標(biāo)號(hào)就會(huì)定義這個(gè)函數(shù),該函數(shù)的主要功能是:負(fù)責(zé)初始化棧、堆,配置系統(tǒng)環(huán)境,準(zhǔn)備好C語言并在最后跳轉(zhuǎn)到用戶自定義的main函數(shù),從此來到C的世界。

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

第七行程序跳轉(zhuǎn)到R0中的地址執(zhí)行程序,即執(zhí)行SystemInit函數(shù)的內(nèi)容。

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

第九行程序跳轉(zhuǎn)到R0中的地址執(zhí)行程序,即執(zhí)行__main函數(shù),執(zhí)行完畢之后就去到我們熟知的C世界,進(jìn)入main函數(shù)。

第十行表示子程序的結(jié)束。

總之,看完這段代碼后,了解到如下內(nèi)容即可:我們需要在外部定義一個(gè)SystemInit函數(shù)設(shè)置STM32的時(shí)鐘;STM32上電后,會(huì)執(zhí)行SystemInit函數(shù),最后執(zhí)行我們C語言中的main函數(shù)。

7.3.3stm32f4xx.h文件

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

代碼清單72外設(shè)地址定義

1/*片上外設(shè)基地址*/

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

3/*總線基地址*/

4#define AHB1PERIPH_BASE (PERIPH_BASE + 0x00020000)

5/*GPIO外設(shè)基地址*/

6#define GPIOH_BASE (AHB1PERIPH_BASE + 0x1C00)

8/* GPIOH寄存器地址,強(qiáng)制轉(zhuǎn)換成指針*/

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)

20/*RCC外設(shè)基地址*/

21#define RCC_BASE (AHB1PERIPH_BASE + 0x3800)

22/*RCC的AHB1時(shí)鐘使能寄存器地址,強(qiáng)制轉(zhuǎn)換成指針*/

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

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

7.3.4main文件

現(xiàn)在就可以開始編寫程序了,在main文件中先編寫一個(gè)main函數(shù),里面什么都沒有,暫時(shí)為空。

1intmain (void)

2{

3}

此時(shí)直接編譯的話,會(huì)出現(xiàn)如下錯(cuò)誤:

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

錯(cuò)誤提示SystemInit沒有定義。從分析啟動(dòng)文件時(shí)我們知道,Reset_Handler調(diào)用了該函數(shù)用來初始化SMT32系統(tǒng)時(shí)鐘,為了簡(jiǎn)單起見,我們?cè)趍ain文件里面定義一個(gè)SystemInit空函數(shù),什么也不做,為的是騙過編譯器,把這個(gè)錯(cuò)誤去掉。關(guān)于配置系統(tǒng)時(shí)鐘我們?cè)诤竺嬖賹?。?dāng)我們不配置系統(tǒng)時(shí)鐘時(shí),STM32芯片會(huì)自動(dòng)按系統(tǒng)內(nèi)部的默認(rèn)時(shí)鐘運(yùn)行,程序還是能跑的。我們?cè)趍ain中添加如下函數(shù):

1//函數(shù)為空,目的是為了騙過編譯器不報(bào)錯(cuò)

2voidSystemInit(void)

3{

4}

這時(shí)再編譯就沒有錯(cuò)了,完美解決。還有一個(gè)方法就是在啟動(dòng)文件中把有關(guān)SystemInit的代碼注釋掉也可以,見代碼清單73。

代碼清單73注釋掉啟動(dòng)文件中調(diào)用SystemInit的代碼

1; Reset handler

2Reset_HandlerPROC

3EXPORT Reset_Handler [WEAK]

4;IMPORT SystemInit

5IMPORT__main

6

7;LDR R0, =SystemInit

8;BLX R0

9LDR R0, =__main

10BXR0

11ENDP

接下來在main函數(shù)中添加代碼,對(duì)寄存器進(jìn)行控制,寄存器的控制參數(shù)可參考表71(點(diǎn)擊可跳轉(zhuǎn))或《STM32F4xx參考手冊(cè)》。

1.GPIO模式

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

代碼清單74配置輸出模式

1/*GPIOH MODER10清空*/

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

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

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

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

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

代碼中使用了"&=~"、"|="這種復(fù)雜位操作方法是為了避免影響到寄存器中的其它位,因?yàn)榧拇嫫鞑荒馨次蛔x寫,假如我們直接給MODER寄存器賦值:

1GPIOH_MODER = 0x00100000;

這時(shí)MODER10的兩個(gè)位被設(shè)置成"01"輸出模式,但其它GPIO引腳就有意見了,因?yàn)槠渌_的MODER位都已被設(shè)置成輸入模式。

如果對(duì)此處"&=""|="這樣的位操作方法還不理解,請(qǐng)閱讀前面的《規(guī)范的位操作方法》小節(jié)。熟悉這種方法之后,會(huì)發(fā)現(xiàn)這樣按位操作其實(shí)比直接賦值還要直觀。

2.輸出類型

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

代碼清單75設(shè)置為推挽模式

1/*GPIOH OTYPER10清空*/

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

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

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

3.輸出速度

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

代碼清單76設(shè)置輸出速度為2MHz

1/*GPIOH OSPEEDR10清空*/

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

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

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

4.上/下拉模式

當(dāng)GPIO引腳用于輸入時(shí),引腳的上/下拉模式可以控制引腳的默認(rèn)狀態(tài)。但現(xiàn)在我們的GPIO引腳用于輸出,引腳受ODR寄存器影響,ODR寄存器對(duì)應(yīng)引腳位初始初始化后默認(rèn)值為0,引腳輸出低電平,所以這時(shí)我們配置上/下拉模式都不會(huì)影響引腳電平狀態(tài)。但因此處上拉能小幅提高電流輸出能力,我們配置它為上拉模式,即配置PUPDR寄存器的PUPDR10位,設(shè)置為二進(jìn)制值"01",見代碼清單77。

代碼清單77設(shè)置為下拉模式

1/*GPIOH PUPDR10清空*/

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

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

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

5.控制引腳輸出電平

在輸出模式時(shí),對(duì)BSRR寄存器和ODR寄存器寫入?yún)?shù)即可控制引腳的電平狀態(tài)。簡(jiǎn)單起見,此處我們使用BSRR寄存器控制,對(duì)相應(yīng)的BR10位設(shè)置為1時(shí)PH10即為低電平,點(diǎn)亮LED燈,對(duì)它的BS10位設(shè)置為1時(shí)PH10即為高電平,關(guān)閉LED燈,見代碼清單78。

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

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

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

3

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

5GPIOH_BSRR |= (1<<10);

6.開啟外設(shè)時(shí)鐘

設(shè)置完GPIO的引腳,控制電平輸出,以為現(xiàn)在總算可以點(diǎn)亮LED了吧,其實(shí)還差最后一步。

在《STM32芯片架構(gòu)》的外設(shè)章節(jié)中提到STM32外設(shè)很多,為了降低功耗,每個(gè)外設(shè)都對(duì)應(yīng)著一個(gè)時(shí)鐘,在芯片剛上電的時(shí)候這些時(shí)鐘都是被關(guān)閉的,如果想要外設(shè)工作,必須把相應(yīng)的時(shí)鐘打開。

STM32的所有外設(shè)的時(shí)鐘由一個(gè)專門的外設(shè)來管理,叫RCC(reset and clockcontrol),RCC在《STM32中文參考手冊(cè)》的第六章。

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

代碼清單79開啟端口時(shí)鐘

1/*開啟GPIOH時(shí)鐘,使用外設(shè)時(shí)都要先開啟它的時(shí)鐘*/

2RCC_AHB1ENR |= (1<<7);

7.水到渠成

開啟時(shí)鐘,配置引腳模式,控制電平,經(jīng)過這三步,我們總算可以控制一個(gè)LED了。現(xiàn)在我們完整組織下用STM32控制一個(gè)LED的代碼,見代碼清單710。

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

1

2/*

3使用寄存器的方法點(diǎn)亮LED燈

4*/

5#include"stm32f4xx.h"

6

7

8/**

9*主函數(shù)

10*/

11intmain(void)

12{

13/*開啟GPIOH時(shí)鐘,使用外設(shè)時(shí)都要先開啟它的時(shí)鐘*/

14RCC_AHB1ENR |= (1<<7);

15

16/* LED端口初始化*/

17

18/*GPIOH MODER10清空*/

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

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

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

22

23/*GPIOH OTYPER10清空*/

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

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

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

27

28/*GPIOH OSPEEDR10清空*/

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

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

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

32

33/*GPIOH PUPDR10清空*/

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

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

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

37

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

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

40

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

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

43

44while(1);

46}

47

48//函數(shù)為空,目的是為了騙過編譯器不報(bào)錯(cuò)

49voidSystemInit(void)

50{

51}

在本章節(jié)中,要求完全理解stm32f4xx.h文件及main文件的內(nèi)容(RCC相關(guān)的除外)。
編輯:hfy

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • led燈
    +關(guān)注

    關(guān)注

    22

    文章

    1588

    瀏覽量

    107405
  • 寄存器
    +關(guān)注

    關(guān)注

    31

    文章

    5253

    瀏覽量

    119212
  • STM32
    +關(guān)注

    關(guān)注

    2258

    文章

    10828

    瀏覽量

    352505
  • GPIO
    +關(guān)注

    關(guān)注

    16

    文章

    1175

    瀏覽量

    51515
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    寄存器是什么?怎么操作寄存器點(diǎn)亮LED?

    寄存器,是集成電路中非常重要的一種存儲(chǔ)單元,通常由觸發(fā)組成。在集成電路設(shè)計(jì)中,寄存器可分為電路內(nèi)部使用的寄存器和充當(dāng)內(nèi)外部接口的寄存器這兩
    的頭像 發(fā)表于 07-21 16:59 ?3623次閱讀
    <b class='flag-5'>寄存器</b>是什么?怎么操作<b class='flag-5'>寄存器</b><b class='flag-5'>點(diǎn)亮</b><b class='flag-5'>LED</b><b class='flag-5'>燈</b>?

    寄存器點(diǎn)亮led

    本篇文章介紹了STM32的基本知識(shí),以及寄存器編程,映射等有關(guān)知識(shí),最后實(shí)例為用寄存器點(diǎn)亮led
    發(fā)表于 08-24 06:57

    如何通過CubMX來點(diǎn)亮LED?

    如何通過CubMX來點(diǎn)亮LED
    發(fā)表于 09-27 08:11

    如何操作寄存器

    學(xué)習(xí)單片機(jī)實(shí)際上就是學(xué)習(xí)如何操作寄存器。51單片機(jī)使用sfr來定義具有特殊功能的寄存器。如:sfr P1 = 0x90;如果你想使用P1口的第1位來點(diǎn)亮LED
    發(fā)表于 11-23 09:01

    如何通過控制寄存器來點(diǎn)亮LED?

    如何通過控制寄存器來點(diǎn)亮LED
    發(fā)表于 11-29 06:39

    如何利用寄存器點(diǎn)亮LED

    GPIO引腳都有哪些功能呢?GPIO可以配置成哪幾種模式?如何利用寄存器點(diǎn)亮LED呢?
    發(fā)表于 11-29 07:56

    認(rèn)識(shí)STM32用寄存器點(diǎn)亮LED

    STM32初學(xué)者,寫博客只是為了記錄學(xué)習(xí),希望能有大神指點(diǎn)一下初學(xué)者入門書有沒有推薦的一開始通過51來認(rèn)識(shí)STM32用寄存器點(diǎn)亮LED51點(diǎn)亮
    發(fā)表于 11-30 07:22

    如何以不同的亮度來點(diǎn)亮LED

    LED的原理是什么?如何以不同的亮度來點(diǎn)亮LED呢?
    發(fā)表于 01-20 06:52

    基于STM32F103C8T8寄存器方式點(diǎn)亮led

    基于STM32F103C8T8寄存器方式點(diǎn)亮led前言一、寄存器配置介紹二、使用寄存器方式
    發(fā)表于 02-10 07:24

    寄存器點(diǎn)亮LED

    寄存器點(diǎn)亮LED1、新建工程文件,選擇STM32F1032、
    發(fā)表于 02-24 07:33

    使用寄存器點(diǎn)亮LED

    stm32是我們會(huì)寄存器點(diǎn)亮LED
    發(fā)表于 12-01 15:30 ?0次下載

    如何使用寄存器點(diǎn)亮LED

    本文檔的主要內(nèi)容詳細(xì)介紹的是如何使用寄存器點(diǎn)亮LED。
    發(fā)表于 04-15 17:00 ?10次下載
    如何使用<b class='flag-5'>寄存器</b><b class='flag-5'>點(diǎn)亮</b><b class='flag-5'>LED</b><b class='flag-5'>燈</b>

    STM8 寄存器點(diǎn)亮LED

    STM8 寄存器點(diǎn)亮LED庫(kù)函數(shù):方便,但效率低,調(diào)用文件多寄存器:高效,芯片資源最大化運(yùn)用,但繁瑣//使用寄存器方式
    發(fā)表于 12-05 12:36 ?3次下載
    STM8 <b class='flag-5'>寄存器</b><b class='flag-5'>點(diǎn)亮</b><b class='flag-5'>LED</b>

    配置STM32寄存器控制GPIO點(diǎn)亮LED

    STM32點(diǎn)亮LED 寄存器方式IO簡(jiǎn)介1、每個(gè)IO可以自由編程,但是IO口寄存器必須按照32位字被訪問。2、每個(gè)IO端口都有7個(gè)寄存器
    發(fā)表于 01-13 16:15 ?3次下載
    配置STM32<b class='flag-5'>寄存器</b><b class='flag-5'>控制</b>GPIO<b class='flag-5'>點(diǎn)亮</b><b class='flag-5'>LED</b>

    【i.MX6ULL】驅(qū)動(dòng)開發(fā)4——點(diǎn)亮LED(寄存器版)

    本篇主要介紹了如何通過操作寄存器來點(diǎn)亮i.MX6ULL開發(fā)板上的led,通過編寫LED對(duì)應(yīng)的驅(qū)動(dòng)
    的頭像 發(fā)表于 05-21 21:26 ?2841次閱讀
    【i.MX6ULL】驅(qū)動(dòng)開發(fā)4——<b class='flag-5'>點(diǎn)亮</b><b class='flag-5'>LED</b>(<b class='flag-5'>寄存器</b>版)