GPIO是通用輸入輸出接口(General Purpose Input Output)的簡(jiǎn)稱,是微控制器最基本也是最常用的外設(shè),本期內(nèi)容將介紹GPIO的基本原理,然后通過(guò)「點(diǎn)亮LED」與「按鍵控制LED」兩個(gè)小實(shí)驗(yàn)帶領(lǐng)大家了解GPIO基本輸出與輸入功能的使用方法。
系統(tǒng)環(huán)境
Windows 10-64bit
軟件平臺(tái)
NucleiStudio IDE 202102版
硬件需求
RV-STAR開(kāi)發(fā)板
GPIO基本原理
GPIO的全稱是通用輸入輸出接口(General Purpose Input/Output),是很多外設(shè)能夠正常工作的基礎(chǔ),MCU上除了一些特定功能的引腳(如電源引腳)外,其他的引腳基本都可以作為GPIO來(lái)使用。
GD32VF103的GPIO端口以“組”的形式工作,命名方式為Px(x=A, B, C, D, E···),每組配置有16個(gè)引腳。GPIO端口和其他的備用功能(AFs)共用引腳,在特定的封裝下獲得最大的靈活性。
每個(gè)GPIO引腳都可以通過(guò)軟件配置為輸出(推挽或開(kāi)漏)、輸入、外設(shè)備用功能或者模擬模式。每個(gè)GPIO引腳都可以配置為上拉、下拉或浮空。除模擬模式外,所有的GPIO引腳都具備大電流驅(qū)動(dòng)能力。
(標(biāo)準(zhǔn)GPIO端口的基本結(jié)構(gòu))
GPIO具有下列特征:
輸入/輸出方向控制
施密特觸發(fā)器輸入功能使能控制
每個(gè)引腳都具有弱上拉/下拉功能
推挽/開(kāi)漏輸出使能控制
置位/復(fù)位輸出使能
模擬輸入/輸出配置
備用功能輸入/輸出配置
端口鎖定配置
實(shí)驗(yàn)1:點(diǎn)亮LED
RVSTAR有一個(gè)板載的RGB LED,通過(guò)PA1、PA2、PA3三個(gè)引腳控制LED_G、LED_R、LED_B三個(gè)顏色,通過(guò)原理圖可以得知:要點(diǎn)亮LED需要通過(guò)GPIO引腳輸出一個(gè)低電平,當(dāng)然也可以通過(guò)輸出PWM控制三個(gè)顏色LED的亮度,進(jìn)而組合產(chǎn)生不同的顏色。
下面將通過(guò)實(shí)驗(yàn)點(diǎn)亮LED_G,并令其以2秒為間隔閃爍:
(RGB LED原理圖 - 1)
(RGB LED原理圖 - 2)
首先參照之前的教程,使用NucleiStudio IDE或PlatformIO IDE創(chuàng)建工程,在main.c文件內(nèi)編寫(xiě)代碼如下:
/* 實(shí)驗(yàn)1:點(diǎn)亮LED */ #include "nuclei_sdk_hal.h" void led_config(); void led_on(); void led_off(); int main(void) { // 首先對(duì)外設(shè)進(jìn)行初始化操作 led_config(); while (1) { led_on(); // 點(diǎn)亮LED delay_1ms(2000); // 延時(shí)2秒 led_off(); // 熄滅LED delay_1ms(2000); // 延時(shí)2秒 } } void led_config() { // 使能GPIOA端口的外設(shè)時(shí)鐘 rcu_periph_clock_enable(RCU_GPIOA); // 將PA1初始化為推挽輸出模式 gpio_init(GPIOA, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_1); } void led_on() { // 將輸出引腳置位為0,輸出低電平,燈亮 gpio_bit_reset(GPIOA, GPIO_PIN_1); } void led_off() { // 將輸出引腳置位為1,輸出高電平,燈熄 gpio_bit_set(GPIOA, GPIO_PIN_1); }
然后將工程文件進(jìn)行編譯和上傳,將可以觀察到板載的綠色LED以2秒為間隔進(jìn)行閃爍。運(yùn)行結(jié)果如下:
實(shí)驗(yàn)2:按鍵控制LED
實(shí)驗(yàn)1我們使用了GPIO的輸出功能點(diǎn)亮了LED,實(shí)驗(yàn)2將帶領(lǐng)大家使用GPIO的輸入功能:用RVSTAR的板載按鍵控制LED的亮和滅,在使用它之前我們需要了解一點(diǎn)按鍵消抖的知識(shí)。
(按鍵的原理圖)
RVSTAR有一個(gè)板載的按鍵,連接到了MCU的PA1引腳上,按鍵沒(méi)按下時(shí),PA1引腳通過(guò)一個(gè)下拉電阻接地,處于低電平狀態(tài),按鍵按下時(shí)PA1引腳被拉高到3.3V,處于高電平狀態(tài)。由于按鍵是機(jī)械結(jié)構(gòu),在按下和彈起的瞬間會(huì)產(chǎn)生抖動(dòng),即引腳上的電平狀態(tài)不會(huì)被立刻拉高或拉低到穩(wěn)定狀態(tài),因此為了能夠準(zhǔn)確檢測(cè)用戶的按鍵操作,往往需要通過(guò)一定的方法進(jìn)行消抖處理:
常用的按鍵消抖方法有硬件消抖和軟件消抖:硬件消抖是通過(guò)在按鍵兩端增加電容的方式實(shí)現(xiàn)的,成本較高;而軟件消抖是在第一次檢測(cè)到電平變化后延時(shí)一定時(shí)間后再次檢測(cè)電平狀態(tài),如果檢測(cè)到仍處于按下時(shí)的電平狀態(tài),那么說(shuō)明用戶進(jìn)行了完整的按鍵操作,這個(gè)延時(shí)時(shí)間跟具體的硬件有關(guān),經(jīng)測(cè)試,在RVSTAR的按鍵上大約需要是設(shè)置100毫秒的延時(shí)比較合適。
使用NucleiStudio IDE或PlatformIO IDE創(chuàng)建工程,在main.c文件內(nèi)編寫(xiě)代碼如下:
/* 實(shí)驗(yàn)2:按鍵控制LED */ #include "nuclei_sdk_hal.h" void led_config(); void led_on(); void led_off(); void key_config(); bit_status key_get_status(); bit_status led_status = 0; // 用來(lái)記錄led的當(dāng)前狀態(tài) int main(void) { led_config(); key_config(); led_off(); while (1) { // 第一次檢測(cè)按鍵按下 if(key_get_status() == SET) { // 軟件延時(shí)100ms用以消除抖動(dòng) delay_1ms(100); // 再次檢測(cè)按鍵是否按下 if(key_get_status() == SET) { switch (led_status) { case 0: led_on(); break; case 1: led_off(); break; default: break; } led_status = !led_status; // 每次按鍵操作后切換led的狀態(tài) } } } } void led_config() { // 打開(kāi)GPIOA端口的外設(shè)時(shí)鐘 rcu_periph_clock_enable(RCU_GPIOA); // 將PA1初始化為推挽輸出模式 gpio_init(GPIOA, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_1); } void led_on() { // 將輸出引腳置位為0,輸出低電平,燈亮 gpio_bit_reset(GPIOA, GPIO_PIN_1); } void led_off() { // 將輸出引腳置位為1,輸出高電平,燈熄 gpio_bit_set(GPIOA, GPIO_PIN_1); } void key_config() { rcu_periph_clock_enable(RCU_GPIOA); // 開(kāi)啟外設(shè)時(shí)鐘 rcu_periph_clock_enable(RCU_AF); // 開(kāi)啟復(fù)用時(shí)鐘 gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_0); // 將PA0初始化為浮空輸入模式 } bit_status key_get_status() { // 獲得輸入引腳的狀態(tài),其中bit_status是一個(gè)固件庫(kù)定義的枚舉類型 return gpio_input_bit_get(GPIOA, GPIO_PIN_0); }
然后將工程文件進(jìn)行編譯和上傳,將可以觀察到:上電后LED不亮,每次按下按鍵后LED的狀態(tài)會(huì)發(fā)生切換。
運(yùn)行結(jié)果如下: