基于學習STM32有一段時間了,特意寫下一篇關于一個簡單的跑馬燈
的例程,梳理思路,也希望我自己的理解能幫到一些學習STM32的初學者
//======================================================//
首先,GPIO的配置種類有8種。分別為模擬輸入、浮空輸入,上拉輸入、下拉輸入、開漏輸出、推挽輸出、復用開漏輸出、復用推挽輸出。
下面將以實例的方式講解GPIO的設置及實現過程。
事例1:跑馬燈實驗
跑馬燈實驗的功能:LED燈進行有規律閃爍。(下面的LED燈的數量都為2個,所以關于寄存器的配置也將以兩組的方式進行講解)
首先要知道普通的IO就兩種功能一個為輸入,一個為輸出。然后再以輸入和輸出細分為以哪種模式輸出、以哪種模式輸入。要設置IO的模式這時就要使用到寄存器進行設置,STM32的IO端口一般由7個寄存器來進行控制。
分別為
(1)配置模式的2個32位的端口配置寄存器 CRL 和 CRH;
(2)2 個 32 位的數據寄存器 IDR 和 ODR;
(3)1 個 32 位的置位/復位寄存器BSRR;
(4)1個 16 位的復位寄存器 BRR;
(5)1 個 32 位的鎖存寄存器 LCKR;
而我們常用的 IO 端口寄存器只有 4 個:CRL、CRH、IDR、ODR。
首先,一般一個程序的開始都會從入口main函數開始執行,而一個功能的實現之前都需要做一些準備工作,當然跑馬燈也不例外,在程序執行前,IO需要初始化,而初始化要做的就是對程序需要用到的GPIO的寄存器進行配置。然后設定輸出設備的初始狀態,即跑馬燈的初始狀態。一般程序在執行前,輸出設備都會是處于關閉狀態。最后增加延時函數,讓LED燈在亮與滅之間有一段時間的狀態保留,不然時間過快,人類的視覺根本捕抓它的狀態變化。
下面來講一下實現跑馬燈效果的IO要怎么配置。首先先說一下使用LED來進行跑馬功能的話只需要用到RCC-》APB2ENR、GPIOX-》CRL、GPIOX-》ODR三個寄存器(GPIOX中的X表示為GPIO的組別,例如GPIOB表示在GPIO的B組上,因為一般單片機上的GPIO一般都會有很多組的,這樣也只是為了區分這些IO罷了)
CRL 和 CRH 控制著每個 IO 口的模式及輸出速率。
這里需要注意的是在配置GPIO前,都需要先使能該GPIO的時鐘!(可能有人會問“為什么一定要是使能時鐘呢?”答案是:GPIO也是外設的一種,然后外設是需要提供時鐘信號工作,以便于設置GPIO的數據傳輸速度的高速/低速輸出,所以有關數據的傳輸都是在時鐘信號的基礎上的。51單片的IO口也有時鐘,只是為了方便,默認開啟的,ST的為了更好的控制功耗,電路上做的可以選擇開關時鐘,降低功耗。補充網友的答案:“寄存器是基于觸發器的,觸發器的賦值是一定需要時鐘的,而寄存器的時鐘是由總線時鐘提供的,就是說沒有總線時鐘的話,你給寄存器值它是不會讀入的”)
然后設置兩個LED的GPIO的模式,因為LED是輸出設備,所以GPIO將設置成輸出模式,其中配置模式要用到的寄存器為配置寄存器CRL和CRH。其中CRH為高位寄存器,CRL為低位寄存器。(有人可能有疑問為什么用的是32位的寄存器為什么還要為兩個寄存器來管理呢?難道是32位還不夠配置嗎?答案是:是的,不夠用。配置寄存器對一個GPIO的配置要用4個位來完成。一組GPIO有16個引腳,一個引腳要4位的話,那么16個引腳就要16*4=64,那么就要2個32位的寄存器來實現,所以就干脆把高八位給一個寄存器,低八位給另外一個寄存器,這就出現了CRL和CRH。也許有人還會有疑問說為什么一定要用4位來對一個引腳的配置呢?答案是肯定的,因為前面說了,對GPIO的配置首先配置為輸入模式或者輸出模式,然后再對輸入、輸出配置為哪種輸出,哪種輸入,是推挽輸出呢,還是開漏輸入呢,這都是需要至少2個位來進行配置,而且輸入、輸出模式各有4種模式,共8中,這樣要以最少的資源來實現的話,用00、01、10、11這種2個位來實現是最省資源的,所以2*2=4,所以對于1個GPIO的模式的配置至少也就要4位了。)
接著就是查看LED的GPIO的引腳接在IC哪個引腳上。怎么查看LED的引腳到底接在哪呢?這個要看開發板的原理圖,不同的板子來說或者對于不同的商家來說在GPIO的引腳接線上會有不同,以我的開發板的原理圖可以發現LED燈的GPIO分別接在了GPIOB的pin5和GPIOE的pin5上,根據電路性質,一般會將LED設置為推挽輸出模式(可能這時就會有人問了,為什么就是推挽呢?為什么不是開漏呢?我的理解是:這是有電路性質決定的,推挽顧名思義就是灌電流與拉電流都可以輸出,通俗地講就是輸出高低電平。而開漏是一直輸出低電平,當你要輸出高電平的時候需要加上拉)
通過查閱寄存器的數據手冊可知,00位通用推挽模式,那么
//======================================================//
GPIOB-》CRL |= 3 《《 20;//設置模數數據傳輸速率
GPIOB-》CRL &=~(3 《《 22);//設置GPIO模式
//======================================================//
這樣就把GPIOB組的pin5設置成了通用推挽模式,前面說了一個引腳需要4個位來配置,查看寄存器數據手冊可看到,前面2個位是設置通用推挽模式的,后面2個位是基于這種模式的數據傳輸速率,在這里我們懸著的是“最大速度50MHz”,而GPIOB-》CRL|=3《《20;就是設置數據傳輸速率為最大速度50MHz,GPIOB-》CRL&=~(3《《22);為設置GPIOB的pin5為通用推挽模式。
最后就是設置LED的初始狀態了,再說之前先說一下ODR寄存器。
ODR是一個端口輸出數據寄存器,也只用了低16位。該寄存器為可讀寫,從該寄存器讀出來的數據可以用于判斷當前IO 口的輸出狀態。而向該寄存器寫數據,則可以控制某個 IO 口的輸出電平。
所以在配置LED初始化的時候就需要調用這個寄存器設置LED的初始狀態。
//======================================================//
GPIOE-》ODR|=1《《5;//設置LED的初始化狀態為1(1為到電平,亮滅有其電路決定,我的開發板由于接了上拉,使得低電平才是有效的,即0為LED燈亮,1為LED燈滅)
//======================================================//
這樣初始化函數就完成了。
具體初始化代碼如下:
//=======================led.c===============================//
#include “stm32f10x.h”
#include “led.h”
void led_Init(void)
{
RCC -》APB2ENR |= 1 《《 3;//使能 PORTB 時鐘
RCC -》APB2ENR |= 1 《《 6;//使能 PORTE 時鐘
GPIOB -》CRL |= 3 《《 20;
GPIOB -》CRL &=~ (3 《《 22);//PB.5 推挽輸出
GPIOB -》ODR |= 1 《《 5;//PB.5 輸出高
GPIOE -》CRL |= 3 《《 20;
GPIOE -》CRL &= ~(3 《《 22);//PE.5 推挽輸出
GPIOE -》ODR |= 1 《《 5;//PE.5 輸出高
}
//======================================================//
其頭文件如下:
//=========================led.h=============================//
#ifndef __LED_H_
#define __LED_H_
extern void led_Init(void);
#endif
//======================================================//
接下來說一下初始化好了,主函數要怎么寫。
第一需要的是點亮LED的語句,在初始化中有提到,設置LED初始化狀態即:GPIOB -》ODR |= 1 《《 5;//PB.5 輸出高
那么同時也能使用這句來進行LED的亮滅控制。代碼如下:
//==========================main.c============================//
#include “stm32f10x.h”
#include “led.h”
int main(void)
{
int i=0;
led_Init();//LED初始化
while(1)
{
GPIOB -》ODR &= ~ (1 《《 5);//PB.5輸出低電平,即點亮LED
GPIOE -》ODR &= ~(1 《《 5);//PB.5輸出低電平,即點亮LED
for(i=0;i《1000000;i++);//延時
GPIOB -》ODR |= 1 《《 5;//PE.5輸出高電平,即滅掉LED
GPIOE -》ODR |= 1 《《 5;//PB.5輸出高電平,即滅掉LED
for(i=0;i《1000000;i++);//延時
}
}
//======================================================//
整個跑馬燈的工程就只需這三個文件,就能簡單實現跑馬的功能,如果你想要延時的時間是規律的,那么你就要去使用定時器了。因為定時器定時的時間是準時的,軟件延時第一消耗CPU的資源,然后時間也不夠精確,所以一般在對時間要求沒有很精確的要求是才會使用軟件延時的做法。
評論
查看更多