嵌入式接口之GPIO驱动LED的实验(附完整代码和工程以及详细的调试过程)
目錄
- 前言
- 環(huán)境配置
- 實驗內(nèi)容
- 實驗講解
- 題目分析
- 實現(xiàn)方式
- 文件概覽
- sw_delay.c
- key_driver.c
- 時鐘使能
- GPIO初始化
- key_driver.c代碼
- led_driver.c
- GPIO_SetBits、GPIO_ResetBits
- led_driver.c代碼
- main.c
- 仿真調(diào)試
- 設置仿真調(diào)試
- 編譯
- 調(diào)試
- 總結(jié)
前言
由于期末考試需要考實驗代碼,為了自己能夠印象深刻,考試能夠順利通過,特意寫個博客記錄一下實驗的過程以及其中一些細節(jié)。下面將通過一個例題一步一步進行講解。
環(huán)境配置
軟件配置:Keil uVision5
開發(fā)板芯片型號:STM32F103ZE
實驗內(nèi)容
基于C語言的GPIO操作
已知:戰(zhàn)艦開發(fā)板連接按鍵(輸入設備)KEY0、KEY1、KEY2,和發(fā)光二極管(輸出設備)LED0、LED2.
要求:用戶任意按下某個按鍵,開發(fā)板根據(jù)用戶按下的不同的按鍵,采用不同的方式使二極管閃爍。
硬件電路如下:
實驗講解
題目分析
由于實驗要求需要我們進行輸入輸出操作,那么就需要使用到GPIO,需要電亮二極管,因為硬件的響應速度是十分迅速的,如果僅僅在程序中輸出一下高電平,那現(xiàn)實中LED只是在極短的時間閃一下,以至于我們根本觀察不到它亮過,因此這里需要使用延時,由于我們只需要看到燈亮燈滅的效果即可,那么使用軟件延時即可,即用while循環(huán)來達到延時的效果,雖然精度和效率都不高,但是實現(xiàn)起來是十分方便的,也符合我們的實驗要求。
由于LED0和LED1分別接在PB5和PE5上,因此我們只需要操控GPIOB和GPIOE的Pin5的輸出即可實現(xiàn)實驗需要的效果了。
實現(xiàn)方式
下面的實驗將使用CMSIS標準庫版。CMSIS全稱Cortex MicroController Software Interface Standard由ARM 與芯片廠商建立的軟件接口標準。芯片商意法半導體公司(ST公司)推出的STM32 標準庫函數(shù)就是遵循CMSIS標準。
文件概覽
因為配置文件比較多,但是配置起來還是比較簡單的,就是c語言開頭導入配置文件即可,因此以下的代碼內(nèi)容可運行默認的前提是已經(jīng)配置好了需要的頭文件。
整個實驗的工程目錄如上圖所示,這個工程我會原封不動的傳到資源中去。因為這是我們老師給我們的工程模板,因此會比較規(guī)范,其中需要我們編寫代碼的文件只有sw_delay.c、key_driver.c、led_driver.c、main.c這四個文件。
其中
sw_delay.c需要寫入軟件延時的函數(shù),是我們能夠清晰的看到LED燈亮和燈滅的實驗效果。
key_driver.c需要對應GPIO輸入腳的初始化,以達到按下按鍵能夠?qū)崿F(xiàn)燈亮燈滅的控制效果。
led_driver.c需要寫入對應GPIO驅(qū)動LED的函數(shù)以及初始化。
main,c則是將上述三個文件的函數(shù)整合,完成整個實驗的內(nèi)容。
sw_delay.c
這里使用軟件延時,while循環(huán)指定次數(shù)達到延時的效果。
#include "sw_delay.h" void SoftwareDelay(uint32_t time ) {while(time>0){time--;} }key_driver.c
時鐘使能
在使用一個外設前,必須先配置和激活啟動該外設的時鐘,如GPIO端口B,那么就要激活GPIOB的時鐘。只有啟動了時鐘外設才變得可用,而不需要使用的外設無需使能時鐘,這樣做的好處是可以降低STM32芯片的內(nèi)部功耗。
外設也區(qū)分高速外設和低速外設,這就需要對應不同工作頻率的時鐘來使能。
可見GPIO屬于高速外設,需要使用APB2來連接使能。
然后我們可以參考STM32固件庫使用手冊,查看對應時鐘使能函數(shù)的用法:
GPIO初始化
GPIO一共有16個引腳,8種工作模式,3種最大翻轉(zhuǎn)速度(2MHz、10MHz、50MHz)。
上拉輸入是指在沒有信號輸入的情況下可以穩(wěn)定在高電平。
工作模式可以參考:深刻理解GPIO(上拉輸入、下拉輸入、模擬輸入、浮空輸入,開漏輸出,推挽輸出的區(qū)別,以STM32為例)感覺講的十分不錯和詳細。
庫函數(shù)中已經(jīng)封裝好了GPIO的初始化結(jié)構(gòu)體
其中三個參數(shù)的取值分別如下:
因此我們能夠?qū)PIO進行快速的初始化:
key_driver.c代碼
最終我們的key_driver.c如下所示:
#include "stm32f10x_conf.h" void SoftwareDelay(uint32_t time ); void KEY_GPIO_Config(void) { GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOE, ENABLE);GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;GPIO_Init(GPIOE, &GPIO_InitStructure); }使能GPIOE,然后使用GPIOE的2、3、4號引腳上拉輸入作為我們控制LED的開關。
led_driver.c
GPIO_SetBits、GPIO_ResetBits
此函數(shù)能夠設置GPIO引腳的電平。
此函數(shù)能夠重置GPIO引腳的電平。
led_driver.c代碼
由于PB5和PE5分別連接著LED0和LED1,因此我們設置PB5和PE5為推挽輸出用于控制LED燈的亮滅,然后通過對PE2、3、4引腳的輸入來控制PB5和PE5的狀態(tài)(高電平或者低電平)從而控制LED0和LED1的狀態(tài),達到我們需要的效果。
#include "stm32f10x_conf.h" void LED_GPIO_Config(void) { GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOE,ENABLE);GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;//推挽輸出GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStructure);GPIO_SetBits(GPIOB, GPIO_Pin_5);GPIO_Init(GPIOE, &GPIO_InitStructure);GPIO_SetBits(GPIOE, GPIO_Pin_5); } void LED0_LightUp(void)//點亮LED0 {GPIO_ResetBits(GPIOB, GPIO_Pin_5); } void LED1_LightUp(void)//點亮LED1 {GPIO_ResetBits(GPIOE, GPIO_Pin_5); }void LED0_Flash(void){//LED0閃爍4次uint8_t i;for(i=1; i<=4; i++){GPIO_ResetBits(GPIOB, GPIO_Pin_5);SoftwareDelay(100000);GPIO_SetBits(GPIOB, GPIO_Pin_5);SoftwareDelay(100000);} }void LED1_Flash(void){uint8_t i;for(i=1; i<=4; i++){GPIO_ResetBits(GPIOE, GPIO_Pin_5);SoftwareDelay(100000);GPIO_SetBits(GPIOE, GPIO_Pin_5);SoftwareDelay(100000);} }void LED01_Flash(void){uint8_t i;for(i=1; i<=4; i++){GPIO_ResetBits(GPIOB, GPIO_Pin_5);GPIO_ResetBits(GPIOE, GPIO_Pin_5);SoftwareDelay(100000);GPIO_SetBits(GPIOB, GPIO_Pin_5);GPIO_SetBits(GPIOE, GPIO_Pin_5);SoftwareDelay(100000);} }main.c
main函數(shù)只需要將整體架構(gòu)拼接起來就可以了。整體思路就是,初始化LED0和LED1都是熄滅狀態(tài),按下KEY0、1、2兩個LED都會一直亮;按下KEY1、2 LED0閃爍;按下KEY0、2 LED1閃爍; 按下KEY0、1 LED01一起閃爍。
#include"stm32f10x_conf.h" void LED_GPIO_Config(void);//LED GPIO口配置函數(shù)申明 void LED0_LightUp(void);//LED0亮 void LED1_LightUp(void);//LED1滅 void LED0_Flash(void); void LED1_Flash(void); void LED01_Flash(void); #define KEY0 GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_4)//讀取鍵0 #define KEY1 GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_3)//讀取鍵1 #define KEY2 GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_2)//讀取鍵2void KEY_GPIO_Config(void);//KRY GPIO初始化申明int main(void) { KEY_GPIO_Config();LED_GPIO_Config();while(1){if((KEY0 == 1)&&(KEY1 == 1)&&(KEY2 == 1)){LED0_LightUp();//LED0點亮LED1_LightUp();//LED1點亮}if((KEY0 == 0)&&(KEY1 == 1)&&(KEY2 == 1)){LED0_Flash;//LED0閃爍}if((KEY0 == 1)&&(KEY1 == 0)&&(KEY2 == 1)){LED1_Flash();//LED1閃爍}if((KEY0 == 1)&&(KEY1 == 1)&&(KEY2 == 0)){LED01_Flash();//LED01一起閃爍}}}仿真調(diào)試
設置仿真調(diào)試
點擊魔術(shù)棒
然后Debug選擇Use Simulator即可。
編譯
點擊編譯之后即可開始調(diào)試。
調(diào)試
點擊調(diào)試按鈕進入調(diào)試界面
首先可以在main函數(shù)中設置幾個斷點如下所示:
然后需要打開GPIOB和GPIOE的對應詳細信息的界面:
打開之后如下所示,因為還沒初始化,所以看不到初始化后的結(jié)果
然后點擊左上角運行到斷點處,運行完初始化函數(shù)就能夠看到GPIOE和GPIOB的設置發(fā)生了變化:PB5和PE5是推挽輸出,PE2、3、4是上拉輸入。
當將PE4、3(分別對應的是KEY0、1)點擊模擬開關按下時,程序能夠運行到LED01閃爍的代碼語句中,此時PE5和PB5都會發(fā)生較快的閃動信號,模擬LED的閃亮,由于閃動太快整個過程可能不足一秒鐘,因此可以再增加一些延時,但是還是看的出來信號在閃動的。
總結(jié)
寫了一遍,確實也遇到了一些問題,讓我發(fā)現(xiàn)原來老師以前的代碼有些可能并不是必要的,并且理解了初始化以及LED被控制的操作,讓我更加熟悉了整個流程。畢竟學習,不能學了就忘,總得留下點東西才好。
總結(jié)
以上是生活随笔為你收集整理的嵌入式接口之GPIO驱动LED的实验(附完整代码和工程以及详细的调试过程)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 利用RemoteJoy进行usb视频输出
- 下一篇: 怎么用spss做冗余分析_【攻略】手把手