背光燈代碼(近光燈代碼)
前沿拓展:
1)實驗平臺:ALIENTEK NANO STM32F411 V1開發板
2)摘自《正點原子STM32F4 開發指南(HAL 庫版》關注官方微信號公眾號,獲取更多資料:正點原子
第六章 跑馬燈實驗
STM32 最簡單的外設莫過于 IO 口的高低電平控制了,本章將通過一個經典的跑馬燈程序,
帶大家開啟 STM32F4 之旅,通過本章的學習,你將了解到 STM32F4 的 IO 口作為輸出使用的
方法。在本章中,我們將通過代碼控制 ALIENTEK NANO STM32F411 開發板上的兩個 LED:
DS0 和 DS1 交替閃爍,實現類似跑馬燈的效果。 本章分為如下四個小節:
6.1,STM32F4 IO 口簡介
6.2,硬件設計
6.3,軟件設計
6.4,仿真與下載
6.5 STM32CubeMX 配置 IO 口
6.1 STM32F4 IO 簡介
本章將要實現的是控制 ALIENTEK NANO STM32F4 V1 開發板上的兩個 LED 實現一個類
似跑馬燈的效果,該實驗的關鍵在于如何控制 STM32 的 IO 口輸出。了解了 STM32F4 的 IO 口
如何輸出的,就可以實現跑馬燈了。通過這一章的學習,你將初步掌握 STM32F4 基本 IO 口的
使用,而這是邁向 STM32F4 的第一步。
這一章節因為是第一個實驗章節,所以我們在這一章將講解一些知識為后面的實驗做鋪墊。
為了小節標號與后面實驗章節一樣,這里我們不另起一節來講。
在講解 STM32F4 的 GPIO 之前,首先打開我們光盤的第一個 HAL 庫版本實驗工程跑馬燈
實 驗 工 程 ( 光 盤 目 錄 為 : “ 4 , 程 序 源 碼 \ 標 準 例 程 -HAL 庫 函 數 版 本 \ 實 驗 1 跑 馬 燈
/USER/LED.uvprojx”),可以看到我們的實驗工程目錄:
圖 6.1.1 跑馬燈實驗目錄結構
接下來我們逐一講解一下我們的工程目錄下面的組以及重要文件。
1
組HALLIB下面存放的是ST官方提供的HAL庫文件,每一個源文件stm32f4xx_hal_ppp.c
都對應一個頭文件 stm32f4xx_hal_ppp.h。分組內的源文件我們可以根據工程需要添加和
刪除。這里對于跑馬燈實驗,我們需要添加 9 個源文件。
2
組 CORE 下面存放的是固件庫必須的核心頭文件和啟動文件。這里面的文件用戶不需要
修改。大家可以根據自己的芯片型號選擇對應的啟動文件。
3
組 SYSTEM 是 ALIENTEK 提供的共用代碼,這些代碼在第五章都有詳細講解。
4
組 HARDWARE 下面存放的是每個實驗的外設驅動代碼,他的實現是通過調用 HALLIB
下面的 HAL 庫文件函數實現的,比如 led.c 中函數調用 stm32f4xx_hal_gpio.c 內定義的函
數對 led 進行初始化,這里面的函數是講解的重點。后面的實驗中可以看到會引入多個
源文件。
5
組 USER 下面存放的主要是用戶代碼。但是 system_stm32f4xx.c 文件用戶不需要修改,
同時 stm32f4xx_it.c 里面存放的是中斷服務函數,這兩個文件的作用在 3.3 節有講解。
main.c 函數主要存放的是主函數了。
工程分組的情況我們就講解到這里,接下來我們就要進入我們跑馬燈實驗的講解部分了。
這里需要說明一下,我們在講解 HAL 庫之前會首先對重要寄存器進行一個講解,這樣是為了
大家對寄存器有個初步的了解。大家學習 HAL 庫,并不需要記住每個寄存器的作用,而只是
通過了解寄存器來對外設一些功能有基本的了解,這樣對以后的學習也很有幫助。
相對于 STM32F1 來說,STM32F4 的 GPIO 設置顯得更為復雜,也更加靈活,尤其是復用
功能部分,比 STM32F1 改進了很多,使用起來更加方便。
STM32F4 每組通用 I/O 端口包括 4 個 32 位配置寄存器(MODER、OTYPER、OSPEEDR
和 PUPDR)、2 個 32 位數據寄存器(IDR 和 ODR)、1 個 32 位置位/復位寄存器 (BSRR)、
1 個 32 位鎖定寄存器 (LCKR) 和 2 個 32 位復用功能選擇寄存器(AFRH 和 AFRL)等。
這樣,STM32F4 每組 IO 有 10 個 32 位寄存器控制,其中常用的有 4 個配置寄存器+2 個數
據寄存器+2 個復用功能選擇寄存器,共 8 個,如果在使用的時候,每次都直接操作寄存器配置
IO,代碼會比較多,也不容易記住,所以我們在講解寄存器的同時會講解是用庫函數配置 IO
的方法。
同 STM32F1 一樣,STM32F4 的 IO 可以由軟件配置成如下 8 種模式中的任何一種:
1、輸入浮空
2、輸入上拉
3、輸入下拉
4、模擬輸入
5、開漏輸出
6、推挽輸出
7、推挽式復用功能
8、開漏復用功能
關于這些模式的介紹及應用場景,我們這里就不詳細介紹了,感興趣的朋友,可以看看這
個帖子了解下:http://www.openedv.com/posts/list/32730.htm 。接下來我們詳細介紹 IO 配置常
用的 8 個寄存器: MODER、OTYPER、OSPEEDR、PUPDR、ODR、IDR 、AFRH 和 AFRL。
同時講解對應的 HAL 庫配置方法。
首先看 MODER 寄存器,該寄存器是 GPIO 端口模式控制寄存器,用于控制 GPIOx
(STM32F4 最多有 9 組 IO,分別用大寫字母表示,即 x=A/B/C/D/E/F/G/H/I,下同)的工作模
式,該寄存器各位描述如表表 6.1.2 所示:
表 6.1.2 GPIOx MODER 寄存器各位描述
該寄存器各位在復位后,一般都是 0(個別不是 0,比如 JTAG 占用的幾個 IO 口),也就
是默認條件下一般是輸入狀態的。每組 IO 下有 16 個 IO 口,該寄存器共 32 位,每 2 個位控制
1 個 IO,不同設置所對應的模式見表 6.1.1 描述。
然后看 OTYPER 寄存器,該寄存器用于控制 GPIOx 的輸出類型,該寄存器各位描述見表
表 6.1.3 所示:
表 6.1.3 GPIOx OTYPER 寄存器各位描述
該寄存器僅用于輸出模式,在輸入模式(MODER[1:0]=00/11 時)下不起作用。該寄存器
低 16 位有效,每一個位控制一個 IO 口。設置為 0 是推挽輸出,設置為 1 是開漏輸出。復位后,
該寄存器值均為 0,也就是在輸出模式下 IO 口默認為推挽輸出。
然后看 OSPEEDR 寄存器,該寄存器用于控制 GPIOx 的輸出速度,該寄存器各位描述見表
表 6.1.4 所示:
該寄存器也僅用于輸出模式,在輸入模式(MODER[1:0]=00/11 時)下不起作用。該寄存
器每 2 個位控制一個 IO 口,復位后,該寄存器值一般為 0。
然后看 PUPDR 寄存器,該寄存器用于控制 GPIOx 的上拉/下拉,該寄存器各位描述見表表
6.1.5 所示:
表 6.1.5 GPIOx PUPDR 寄存器各位描述
該寄存器每 2 個位控制一個 IO 口,用于設置上下拉,這里提醒大家,STM32F1 是通過 ODR
寄存器控制上下拉的,而 STM32F4 則由單獨的寄存器 PUPDR 控制上下拉,使用起來更加靈活。
復位后,該寄存器值一般為 0。
前面,我們講解了 4 個重要的配置寄存器。顧名思義,配置寄存器就是用來配置 GPIO 的
相關模式和狀態,接下來我們講解怎么在 HAL 庫中初始化 GPIO 配置。
GPIO 相 關 的 函 數 和 定 義 分 布 在 HAL 庫 文 件 stm32f4xx_hal_gpio.c 和 頭 文 件
stm32f4xx_hal_gpio.h 文件中。
在 HAL 庫中,操作四個配置寄存器初始化 GPIO 是通過 HAL_GPIO_Init 函數完成:
void HAL_GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_Init);
該函數有兩個參數,第一個參數是用來指定需要初始化的 GPIO 對應的 GPIO 組,取值范
圍為 GPIOA~GPIOK。第二個參數為初始化參數結構體指針,結構體類型為 GPIO_InitTypeDef。
下面我們看看這個結構體的定義。首先我們打開我們光盤的跑馬燈實驗,然后找到 HALLIB 組
下面的 stm32f4xx_hal_gpio.c 文件,定位到 HAL_GPIO_Init 函數體處,雙擊入口參數類型
GPIO_InitTypeDef 后右鍵選擇“Go to definition of …”可以查看結構體的定義如下:
typedef struct
{
uint32_t Pin;
//指定 IO 口
uint32_t Mode;
//模式設置
uint32_t Pull;
//上下拉設置
uint32_t Speed;
//速度設置
uint32_t Alternate;//復用映射配置
}GPIO_InitTypeDef;
結構體有 5 個成員變量,關于怎么來確定這 5 個成員變量的取值范圍,請參考 4.7 小節內
容。下面我們通過一個 GPIO 初始化實例來講解這個結構體的成員變量的含義。
初始化 GPIO 的常用格式是:
GPIO_InitTypeDef GPIO_Initure;
GPIO_Initure.Pin=GPIO_PIN_0;
//PB0
GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP; //推挽輸出
GPIO_Initure.Pull=GPIO_PULLUP;
//上拉
GPIO_Initure.Speed=GPIO_SPEED_HIGH;
//高速
HAL_GPIO_Init(GPIOB,&GPIO_Initure);
上面代碼的意思是設置 PB0 端口為推挽輸出模式,輸出速度為高速,上拉。
從上面初始化代碼可以看出,結構體 GPIO_Initure 的第一個成員變量 Pin 用來設置是要初
始化哪個或者哪些 IO 口。第二個成員變量 Mode 是用來設置對應 IO 端口的輸出輸入端口模式,
這個變量實際配置的是我們前面講解的 GPIOx 的 MODER 寄存器。第三個成員變量 Pull 是用
來設置上拉還是下拉,配置的是 GPIOx PUPDR 寄存器。第四個成員變量 Speed 用來設置輸出
速度,配置的是 GPIOx OSPEEDR 寄存器。第五個成員變量 Alternate,我們在 4.4 小節引腳復
用器和映射已經講解,它是用來設置引腳的復用映射的。
這些入口參數的取值范圍怎么定位,怎么快速定位到這些入口參數取值范圍的枚舉類型,
在我們上面章節 4.7 的“快速組織代碼”章節有講解,不明白的朋友可以翻回去看一下,這里
我們就不重復講解,在后面的實驗中,我們也不會再重復講解定位每個參數取值范圍的方法。
看完了 GPIO 的參數配置寄存器,接下來我們看看 GPIO 輸入輸出電平控制相關的寄存器。
首先我們看 ODR 寄存器,該寄存器用于控制 GPIOx 的輸出電平,該寄存器各位描述見表
6.1.6 所示:
表 6.1.6 GPIOx ODR 寄存器各位描述
該寄存器用于設置某個 IO 輸出低電平(ODRy=0)還是高電平(ODRy=1),該寄存器也僅在輸
出模式下有效,在輸入模式(MODER[1:0]=00/11 時)下不起作用。該寄存器在 HAL 庫中使用
不多,操作這個寄存器的庫函數主要是 HAL_GPIO_TogglePin 函數:
void HAL_GPIO_TogglePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
該函數是通過操作 ODR 寄存器,達到取反 IO 口輸出電平的功能。
接下來我們看看另一個非常重要的寄存器 BSRR,它叫置位/復位寄存器。該寄存器和 ODR
寄存器具有類似的作用,都可以用來設置 GPIO 端口的輸出位是 1 還是 0。寄存器描述如下:
表 6.1.7 BSRR 寄存器各位描述
對于低 16 位(0-15),我們往相應的位寫 1,那么對應的 IO 口會輸出高電平,往相應的
位寫 0,對 IO 口沒有任何影響。高 16 位(16-31)作用剛好相反,對相應的位寫 1 會輸出低電
平,寫 0 沒有任何影響。也就是說,對于 BSRR 寄存器,你寫 0 的話,對 IO 口電平是沒有任
何影響的。我們要設置某個 IO 口電平,只需要相關位設置為 1 即可。而 ODR 寄存器,我們要
設置某個 IO 口電平,我們首先需要讀出來 ODR 寄存器的值,然后對整個 ODR 寄存器重新賦
值來達到設置某個或者某些 IO 口的目的,而 BSRR 寄存器,我們就不需要先讀,而是直接設
置即可,這在多任務實時操作系統中作用很大。
BSRR 寄存器使用方法如下:
GPIOA->BSRR=1<<1;
//設置 GPIOA.1 為高電平
GPIOA->BSRR=1<<(16+1)//設置 GPIOA.1 為低電平;
庫函數操作 BSRR 寄存器來設置 IO 電平的函數為:
void HAL_GPIO_WritePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin,
GPIO_PinState PinState);
該函數用來設置一組 IO 口中的一個或者多個 IO 口的電平狀態。比如我們要設置 GPIOB.5 輸出
高,方法為:
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_5,GPIO_PIN_SET); //GPIOB.5 輸出高
設置 GPIOB.5 輸出低電平,方法為:
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_5, GPIO_PIN_RESET); //GPIOB.5 輸出低
接下來我們看看 IDR 寄存器,該寄存器用于讀取 GPIOx 的輸入數據,該寄存器各位描述
見表 6.1.8 所示:
表 6.1.8 GPIOx IDR 寄存器各位描述
該寄存器用于讀取某個 IO 的電平,如果對應的位為 0(IDRy=0),則說明該 IO 輸入的是低
電平,如果是 1(IDRy=1),則表示輸入的是高電平。HAL 庫操作該寄存器讀取 IO 輸入數據相
關函數:
GPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
該函數用來讀取一組 IO 下一個或者多個 IO 口電平狀態。比如我們要讀取 GPIOF.5 的輸入電平,
方法為:
HAL_GPIO_ReadPin(GPIOF, GPIO_PIN_5);//讀取 PF5 的輸入電平
該函數返回值就是 IO 口電平狀態。
最后我們來看看 2 個 32 位復用功能選擇寄存器(AFRH 和 AFRL),這兩個寄存器是用
來設置 IO 口的復用功能的。實際上,在我們調用函數 HAL_GPIO_Init 的時候,如果我們設置
了初始化結構體成員變量 Mode 為復用模式,同時設置了 Alternate 的值,那么會在該函數內部
自動設置這兩個寄存器的值,達到設置端口復用映射的目的。關于這兩個寄存器的詳細配置以
及相關庫函數的使用,在我們前面 4.4 小節 IO 引腳復用和映射有詳細講解,這里我們只是簡
要說明一下。
GPIO 相關的函數我們先講解到這里。雖然 IO 操作步驟很簡單,這里我們還是做個概括性
的總結,操作步驟為:
1) 使能 IO 口時鐘,調用函數為__HAL_RCC_GPIOX_CLK_ENABLE(其中 X=A~K)。
2) 初始化 IO 參數。調用函數 HAL_GPIO_Init();
3) 操作 IO 輸入輸出。操作 IO 的方法就是上面我們講解的方法。
上面我們講解了 STM32F4 IO 口的基本知識以及 HAL 庫操作 GPIO 的一些函數方法,下面
我們來講解我們的跑馬燈實驗的硬件和軟件設計。
6.2 硬件設計
本章用到的硬件只有 LED(DS0 和 DS1)。其電路在 ALIENTEK NANO STM32F411 開發
板上默認是已經連接好了的。DS0 接 PC0,DS1 接 PC1。所以在硬件上不需要動任何東西。其
連接原理圖如圖 6.2.1 下:
圖 6.2.1 LED 與 STM32F1 連接原理圖
6.3 軟件設計
這是我們學習的一個實驗,所以我會手把手教大家怎么從我們前面講解的 Template 工程模
板一步一步加入 HAL 庫以及 led 相關的驅動函數到我們工程,使之跟我們光盤的跑馬燈實驗工
程一模一樣。首先大家打開我們 3.3 小節新建的 HAL 庫工程模板。如果你還沒有新建,也可以
直接打開我們光盤已經新建好了的工程模板,路徑為:“\4,程序源碼\標準例程-HAL 庫函數
版本\實驗 0-1 Template 工程模板-新建工程章節使用”(注意:是直接點擊工程下面的 USER
目錄下面的 Template.uvprojx)。
大家可以看到,我們模板里面的 HALLIB 分組下面,我們引入了所有的 HAL 庫源文件和
對應頭文件,如下圖 6.3.1:
圖 6.3.1 Template 模板工程結構
實際上,這些大家可以根據工程需要添加,比如跑馬燈實驗并沒有用到 ADC,我們可以在
工程中刪除文件 stm32f4xx_hal_adc.c,這樣可以大大減少工程編譯時間。跑馬燈實驗我們一共
使用到 HAL 庫 9 個源文件,具體那 9 個請直接參考我們跑馬燈實驗工程,其他不用的源文件
大家可以直接在工程中刪除。在工程的 Manage Project Items 頁面,選擇要刪除文件所在的分組,
然后選中文件點擊刪除按鈕即可。具體操作方法如下圖 6.3.2 所示:
圖 6.3.2 刪除工程分組中的文件
接下來我們進入我們工程的目錄,在工程根目錄文件夾下面新建一個 HARDWARE 的文
件夾,用來存儲以后與硬件相關的代碼。然后在 HARDWARE 文件夾新建一個 LED 文件夾,
用來存放與 LED 相關的代碼。如圖 6.3.3 所示:
圖 6.3.3 新建 HARDWARE 文件夾
接下來,我們回到們的工程(如果是使用的上面新建的工程模板,那么就是
Template.uvproj,大家可以將其重命名為 LED.uvproj),按
按鈕新建一個文件,然后按
保存在 HARDWARE->LED 文件夾下面,保存為 led.c,操作步驟如下圖 6.3.4 和 6.3.5:
圖 6.3.4 新建文件
圖 6.3.5 保存 led.c
然后在 led.c 文件中輸入如下代碼(代碼大家可以直接打開我們光盤的實驗 1 跑馬燈實驗,
從 led.c 文件內復制過來),輸入后保存即可:
//LED IO 初始化
void LED_Init(void)
{
GPIO_InitTypeDef GPIO_Initure;
__HAL_RCC_GPIOC_CLK_ENABLE();
//開啟 GPIOC 時鐘
GPIO_Initure.Pin=GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3|
GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7;//PC0~7
GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP;//推挽輸出
GPIO_Initure.Pull=GPIO_PULLUP;
//上拉
GPIO_Initure.Speed=GPIO_SPEED_HIGH;
//高速
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3|
GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7,
GPIO_PIN_SET); //PC0~7 置 1,默認初始化后燈滅
HAL_GPIO_Init(GPIOC,&GPIO_Initure);
}
該代碼里面就包含了一個函數 void LED_Init(void),該函數通過調用 HAL_GPIO_Init 實驗
配置 PC0~PC7 為推挽輸出。關于函數 HAL_GPIO_Init 的使用方法在 6.1 小節有詳細講解。這
里需要注意的是:在配置 STM32 外設的時候,任何時候都要先使能該外設的時鐘。使能 GPIOC
時鐘方法為:
__HAL_RCC_GPIOC_CLK_ENABLE(); //使能 GPIOC 時鐘
在設置完時鐘以后,先調用 HAL_GPIO_WritePin 控制 LED0~LED7 輸出 1(LED 全滅),
然后調用 HAL_GPIO_Init 函數完成對 PC0~PC7 的初始化配置。至此,LED 的初始化完畢。這
樣就完成了對這八個 IO 口的初始化。這段代碼的具體含義,大家可以看前面 6.1 小節,我們有
詳細的講解。
保存 led.c 代碼,然后我們按同樣的方法,新建一個 led.h 文件,也保存在 LED 文件夾下面。
在 led.h 中輸入如下代碼:
#ifndef _LED_H
#define _LED_H
#include "sys.h"
#define LED0 PCout(0)
//LED0
#define LED1 PCout(1)
//LED1
#define LED2 PCout(2)
//LED2
#define LED3 PCout(3)
//LED3
#define LED4 PCout(4)
//LED4
#define LED5 PCout(5)
//LED5
#define LED6 PCout(6)
//LED6
#define LED7 PCout(7)
//LED7
void LED_Init(void);
#endif
這段代碼里面最關鍵就是 8 個宏定義:
#define LED0 PCout(0)
//LED0
#define LED1 PCout(1)
//LED1
#define LED2 PCout(2)
//LED2
#define LED3 PCout(3)
//LED3
#define LED4 PCout(4)
//LED4
#define LED5 PCout(5)
//LED5
#define LED6 PCout(6)
//LED6
#define LED7 PCout(7)
//LED7
這里使用的是位帶操作來實現操作某個 IO 口,關于位帶操作前面第五章 5.2.1 已經有詳細
介紹,這里不再多說。需要說明的是,這里同樣可以使用 HAL 庫操作來實現 IO 口操作。如下:
HAL_GPIO_WritePin(GPIOC,GPIO_Pin_0,GPIO_PIN_SET);//PC0=1,等同 LED0=1;
HAL_GPIO_ReadPin(GPIOC,GPIO_Pin_0);
//讀取 PC0 的輸入電平
有興趣的朋友不妨修改我們的位帶操作為庫函數直接操作,這樣也有利于學習。
將 led.h 也保存一下。接著,我們在 Manage Project Itms 管理界面新建一個 HARDWARE
的組,并把 led.c 加入到這個組里面,如圖 6.3.6 所示:
圖 6.3.6 給工程新增 HARDWARE 組
單擊 OK,回到工程,然后你會發現在 Project Workspace 里面多了一個 HARDWARE 組,
在該組下面有一個 led.c 文件。如圖 6.3.7 所示:
圖 6.3.7 工程主界面
然后用之前介紹的方法(在 3.3 節介紹的)將 led.h 頭文件的路徑加入到工程里面,然后點
擊 OK 回到主界面,如下圖 6.3.8 所示
圖 6.3.8 添加 LED 目錄到 PATH
回到主界面后,修改 main.c 文件內容如下(具體內容請參考跑馬燈實驗 main.c 文件):
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
int main(void)
{
HAL_Init();
//初始化 HAL 庫
Stm32_Clock_Init(96,4,2,4);
//設置時鐘,96Mhz
delay_init(96);
//初始化延時函數
LED_Init();
//初始化 LED
while(1)
{
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_0,GPIO_PIN_RESET);//LED0 亮
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_1,GPIO_PIN_SET);//LED1 滅
delay_ms(500);
//延時 500ms
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_0,GPIO_PIN_SET);//LED0 滅
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_1,GPIO_PIN_RESET);//LED1 亮
delay_ms(500);
//延時 500ms
}
}
代碼包含了#include“led.h”這句,使得 LED0、LED1、LED_Init 等能在 main()函數里被
調用。main()函數非常簡單,先調用 HAL_Init 函數初始化 HAL 庫,然后調用 Stm32_Clock_Init
進行時鐘系統配置,然后調用 delay_init()函數進行延時初始化。接著就是調用 LED_Init()來初
始化 PC0~PC7 為推挽輸出模式,最后在 while 死循環里面實現 LED0 和 LED1 交替閃爍,間隔
為 500ms。
上面是通過庫函數來實現的 IO 操作,我們也可以修改 main()函數,直接通過位帶操作達到
同樣的效果,大家不妨試試,位帶操作的代碼如下:
int main(void)
{
HAL_Init();
//初始化 HAL 庫
Stm32_Clock_Init(96,4,2,4);
//設置時鐘,96Mhz
delay_init(96);
//初始化延時函數
LED_Init();
//初始化 LED
while(1)
{
LED0=0;
//LED0 亮
LED1=1;
//LED1 滅
delay_ms(500);
LED0=1;
//LED0 滅
LED1=0;
//LED1 亮
delay_ms(500);
}
}
當然我們也可以通過直接操作相關寄存器的方法來設置 IO,我們只需要將主函數修改如下
內容:
int main(void)
{
HAL_Init();
//初始化 HAL 庫
Stm32_Clock_Init(96,4,2,4);
//設置時鐘,96Mhz
delay_init(96);
//初始化延時函數
LED_Init();
//初始化 LED
while(1)
{
GPIOC->BSRR=GPIO_PIN_0<<16; //LED0 亮
GPIOC->BSRR=GPIO_PIN_1;
//LED1 滅
delay_ms(500);
GPIOC->BSRR=GPIO_PIN_0;
//LED0 滅
GPIOC->BSRR=GPIO_PIN_1<<16; //LED1 亮
delay_ms(500);
}
}
將主函數替換為上面代碼,然后重新執行,可以看到,結果跟庫函數操作和位帶操作一樣
的效果。大家可以對比一下。這個代碼在我們跑馬燈實驗的 main 文件有注釋,大家可以替換試
試。然后編譯工程,得到的結果如圖 6.3.9 所示:
圖 6.3.9 編譯結果
可以看到沒有錯誤,也沒有警告。從編譯信息可以看到,我們的代碼占用 FLASH 大小為:
5376 字節(4910+466),所用的 SRAM 大小為 1928(1900+28)。
這里我們解釋一下,編譯結果里面的幾個數據的意義:
Code:表示程序所占用 FLASH 的大小(FLASH)。
RO-data:即 Read Only-data,表示程序定義的常量(FLASH)。
RW-data:即 Read Write-date,表示已被初始化的變量(SRAM)。
ZI-data:即 Zero Init-data,表示未被初始化的變量(SRAM)
有了這個就可知道你當前使用的 flash 和 sram 大小了,所以,一定要注意的是程序大小不
是.hex 文件的大小,而是編譯后的 Code 和 RO-data 之和。
接下來,我們下載到 NANO STM32F4 開發板看看實際運行的結果。
6.4 下載驗證
運行結果如圖 6.4.1 所示:
圖 6.4.4 執行結果
在工程中我們另外添加了實現流水燈代碼,DS0~DS7 輪流點亮,只需將代碼屏蔽去掉,重
新編譯一下下載到開發板就可以看到實現效果了,這里我們就不作貼圖了。
至此,我們的第一章的學習就結束了,本章作為 STM32F4 的入門第一個例子,詳細介紹
了 STM32F4 的 IO 口的使用及注意事項。希望大家好好理解一下。
6.5 STM32CubuMX 配置 IO 口
在講解完使用 HAL 庫操作 GPIO 口之后,本小節我們教大家怎么使用 STM32CubeMX 圖
形化配置工具配置 GPIO 初始化過程。關于 STM32CubeMX 工具的入門使用在前面 4.8 小節我
們有手把手教大家入門該工具,本小節我們就不重復講解入門部分,我們直接講解在
STM3232CubeMX 工具中怎么來配置 GPIO 口的相關參數。
首先大家打開 STM32CubeMX 工具,參考 4.8 小節內容進行 RCC 相關配置。這里大家也
可以直接打開 4.8 小節的 STM32CubeMX 工程直接在工程上面修改,該工程保存的光盤目錄為:
“4,程序源碼\標準例程-HAL 庫函數版本\實驗 0-3 Template 工程模板-使用 STM32CubeMX 配
置”。
這里大家會發現,我們在 4.8 小節實際上已經講解了 GPIO 的配置,并且同樣是以 PC0 和
PC1 為例。這里我們將詳細解析在 STM32CubeMX 中配置 IO 口詳細參數的過程。使用
STM32CubeMX 配置 GPIO 口的步驟如下:
第一步,打開 STM32CubeMX 工具,在引腳圖中選擇要配置的 IO 口。這里我們選擇 PC0
為例,在彈出的下拉菜單中選擇要配置的 IO 口模式,如下圖 6.5.1 所示:
圖 6.5.1 選擇 IO 口模式
從上圖可以看出,這里我們除了配置 IO 口為輸入輸出之外,還可以選擇 IO 口的復用功能
或者作為外部中斷引腳功能,比如我們要選擇 IO 口復用為 ADC1 的通道 10 引腳,那么我們只
需要選選項 ADC1_IN10 即可。對于本章跑馬燈實驗,PC0 是作為輸出,所以我們選 GPIO_Output
即可。
第二步,進入 Configuration->GPIO,在彈出的界面配置 IO 口的詳細參數。如下圖 6.5.2 所
示:
圖 6.5.3 配置 IO 口詳細參數
在 IO 口詳細參數配置界面,點擊我們要配置的 IO 口,會在窗口下方顯示該 IO 口配置的
詳細參數表,下面我們依次來解釋這些配置項的含義:
1、選項 GPIO output level 用來設置 IO 口初始化電平狀態為 High(高電平)還是 Low(低電
平)。本實驗我們設置為默認輸出高 High。
2、選項 GPIO mode 用來設置輸出模式為 Output Push Pull(推挽)還是 Output Open Drain(開
漏)。本實驗我么設置為推挽輸出 Output Push Pull。
3、選項 GPIO Pull-up/Pull-down 用來設置 IO 口是上拉/下拉/沒有上下拉。本實驗我們設置
為上拉(Pull-up)。
4、選項 Mzximum ouput speed 用來設置輸出速度為高速(Hign)/快速(Fast)/中速(Medium)/低
速(Low)。本實驗我們設置為高速 High。
5、選項 User Label 是用來設置初始化的 IO 口 Pin 值為我們自定義的宏,一般情況我們可以
不用設置,有興趣的同學可以自由設置后查看生成后的代碼就很容易明白其含義。
配置完 PC0 后,PC1 配置方法和參數都一模一樣,這樣我們就不重復配置。
然后我們參考 4.8 小節方法,生成工程源碼。接下來打開工程的 main.c 文件可以看到,該
文件內部有 STM32CubeMX 生成了函數 MX_GPIO_Init,內容如下:
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOD_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_0|GPIO_PIN_1, GPIO_PIN_SET);
/*Configure GPIO pins : PC0 PC1 */
GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
}
該函數的作用跟前面講解的跑馬燈實驗中 LED_Init 函數作用一模一樣,有興趣的同學可以
直接修改跑馬燈實驗工程源碼,把 LED_Init 函數內容修改為 MX_GPIO_Init 內容,大家會發現
實驗效果一模一樣。
一般情況下,STM32CubeMX 的主要作用是配置時鐘系統和外設初始化函數。所以我們對
外設進行配置之后,生成外設初始化代碼,然后把該代碼應用到我們工程即可。關于本章中使
用 STM32CubeMX 配置
拓展知識:
上一篇:背光燈代碼(背光燈電路圖)
- 1海信42k11p怎么折開(海信42K11P:全方位展示超清畫質)
- 2電視頻道沒了怎么恢復(快速解決方法)
- 3Fardior燃氣灶售后維修電話號碼查詢(Fardior燃氣灶售后維修電話查詢)
- 4艾木歐防盜門沒電打不開怎么辦(艾木歐防盜門沒電無法啟動?解決方法總結)
- 5ENS指紋鎖售后熱線(ENS指紋鎖售后熱線-專業解決您的問題)
- 6打電話顯示關機是什么原因(如何解決手機無法接通問題)。
- 7v500hk1 cs5故障維修(v500hk1 cs5故障維修指南)
- 8創維液晶電視的遙控器怎么調試(創維電視遙控器調試指南)
- 9林內空氣能售后服務官網熱線(林內空氣能售后服務官網熱線)
- 10朝友精工保險柜24小時售后電話(朝友精工保險柜24小時售后電話 - 完善24小時保
-
美的中央空調24小時服務熱線電話(為什么美的空調制熱就關機美的空調制熱為何
2024-09-12
-
開利空調全國服務熱線(中央開利空調內機制冷噪音如何有效降噪)
2024-09-12
-
天津斯麥格SMEG冰箱售后故障報修中心(冰箱冷藏傳感器)
2024-09-12
-
開利空調24小時熱線(開利空調常見故障及維修方法你知道如何自行解決嗎?)
2024-09-12
-
三菱中央空調廠家售后電話24小時人工電話(三菱空調開不到是怎么回事排除故障
2024-09-12