![wKgaomZVdiiAfR9BAB3mDFhHnZc972.png](https://file1.elecfans.com/web2/M00/EA/B7/wKgaomZVdiiAfR9BAB3mDFhHnZc972.png)
3.1實驗內容
通過本實驗主要學習以下內容:
- GPIO輸入功能原理;
- 按鍵查詢輸入檢測原理;
3.2實驗原理
3.2.1GPIO輸入功能原理
GD32F303系列MCU GPIO輸入配置結構如下圖所示,輸入可配置上下拉電阻,通過施密特觸發器后可通過備用功能輸入或者通過輸入狀態寄存器進行讀取。
![wKgZomZX3JGAdK5HAADPIZJd4gI263.png](https://file1.elecfans.com/web2/M00/EA/54/wKgZomZX3JGAdK5HAADPIZJd4gI263.png)
輸入狀態寄存器為GPIOx_ISTAT,其狀態位定義如下圖所示,每個控制位對應相應引腳的輸入電平狀態。
![wKgZomZX3KaAKvvqAAGLa0IjgTQ084.png](https://file1.elecfans.com/web2/M00/EA/54/wKgZomZX3KaAKvvqAAGLa0IjgTQ084.png)
GPIO引腳輸入電平判斷閾值如下圖所示,當輸入電平小于0.3VDD時,可被內部有效識別為低電平;當輸入電平大于0.7VDD時,可被內部有效識別為高電平。
![wKgZomZX3LGASiI1AAGjTlTXPNA045.png](https://file1.elecfans.com/web2/M00/EA/54/wKgZomZX3LGASiI1AAGjTlTXPNA045.png)
3.3硬件設計
GD32F303紅楓派開發板具有四個按鍵,對應電路圖如下圖所示,該四個按鍵均具有上拉限流電阻,對引腳防護電阻以及對地消抖電容。在按鍵未按下時,對應GPIO引腳的電平為高電平,按下引腳后,對應GPIO引腳的電平為低電平,通過讀取按鍵對應GPIO引腳的電平狀態可檢測對應按鍵是否被按下。
![wKgZomZX3MSAK3pWAAGJFdLauno447.png](https://file1.elecfans.com/web2/M00/EA/54/wKgZomZX3MSAK3pWAAGJFdLauno447.png)
![wKgZomZX3b2AFHHxAAGFPZspFEc711.png](https://file1.elecfans.com/web2/M00/EA/54/wKgZomZX3b2AFHHxAAGFPZspFEc711.png)
注意:機械按鍵在按下或者松開時具有抖動,建議可增加硬件消抖或者軟件消抖,以避免按鍵檢測被多次觸發。 |
3.4代碼解析
本例程實現通過查詢的方式可查詢按鍵按下的時間,進而可實現短時間按下和長時間按下的檢測。
主函數代碼如下,首先進行延遲初始化/按鍵初始化/LED初始化/串口初始化,并打印Example of key scan detection.之后進入主循環,通過key_scan函數實現對按鍵的掃描并檢測按鍵按下時間。
C int main(void) { //系統延時初始化 driver_init(); //按鍵組初始化 bsp_key_group_init(); //LED組初始化 bsp_led_group_init(); //板載UART初始化 bsp_uart_init(&BOARD_UART); delay_ms(1000); printf("Example of key scan detection.\r\n"); while (1) { delay_ms(1); //按鍵掃描結果檢查:檢測任意按鍵和多按鍵組合按下時間,所有按鍵彈起后有效 if(SET==key_scan(1)) { //檢測按鍵組合按下時長 if(KEY1.press_timerms >= PRESS_3000MS && KEY2.press_timerms >= PRESS_3000MS && WKUP.press_timerms >= PRESS_3000MS) { printf("KEY0/KEY1/KEY2 pressed together for more than 3000ms.\r\n"); KEY1.press_timerms=PRESS_NONE;; KEY2.press_timerms=PRESS_NONE; WKUP.press_timerms=PRESS_NONE; } else if(KEY1.press_timerms >= PRESS_50MS && KEY2.press_timerms >= PRESS_50MS && WKUP.press_timerms >= PRESS_50MS) { printf("KEY0/KEY1/KEY2 pressed together for more than 50ms.\r\n"); KEY1.press_timerms=PRESS_NONE;; KEY2.press_timerms=PRESS_NONE; WKUP.press_timerms=PRESS_NONE; } //檢測任意按鍵按下時長 if(KEY0.press_timerms >= PRESS_200MS && KEY0.press_timerms < PRESS_5000MS) { KEY0.press_timerms=PRESS_NONE; printf("KEY0 press more than 200ms, less than 5000ms .\r\n"); } else if(KEY0.press_timerms >= PRESS_5000MS) { KEY0.press_timerms=PRESS_NONE; printf("KEY0 press more than 5000ms.\r\n"); } else if(KEY0.press_timerms >= PRESS_DOWN) { KEY0.press_timerms=PRESS_NONE; printf("KEY0 press briefly.\r\n"); } if(KEY1.press_timerms >= PRESS_200MS && KEY1.press_timerms < PRESS_5000MS) { KEY1.press_timerms=PRESS_NONE; printf("KEY1 press more than 200ms, less than 5000ms .\r\n"); } else if(KEY1.press_timerms >= PRESS_5000MS) { KEY1.press_timerms=PRESS_NONE; printf("KEY1 press more than 5000ms.\r\n"); } else if(KEY1.press_timerms >= PRESS_DOWN) { KEY1.press_timerms=PRESS_NONE; printf("KEY1 press briefly.\r\n"); } if(KEY2.press_timerms >= PRESS_200MS && KEY2.press_timerms < PRESS_5000MS) { KEY2.press_timerms=PRESS_NONE; printf("KEY2 press more than 200ms, less than 5000ms .\r\n"); } else if(KEY2.press_timerms >= PRESS_5000MS) { KEY2.press_timerms=PRESS_NONE; printf("KEY2 press more than 5000ms.\r\n"); } else if(KEY2.press_timerms >= PRESS_DOWN) { KEY2.press_timerms=PRESS_NONE; printf("KEY2 press briefly.\r\n"); } if(WKUP.press_timerms >= PRESS_200MS && WKUP.press_timerms < PRESS_5000MS) { WKUP.press_timerms=PRESS_NONE; printf("WKUP press more than 200ms, less than 5000ms .\r\n"); } else if(WKUP.press_timerms >= PRESS_5000MS) { WKUP.press_timerms=PRESS_NONE; printf("WKUP press more than 5000ms.\r\n"); } else if(WKUP.press_timerms >= PRESS_DOWN) { WKUP.press_timerms=PRESS_NONE; printf("WKUP press briefly.\r\n"); } } //按鍵掃描結果檢查:檢測任意按鍵有按下 if(KEY0.press_timerms == PRESS_DOWN) { KEY0.press_timerms=PRESS_NONE; bsp_led_toggle(&LED0); } else if(KEY1.press_timerms == PRESS_DOWN) { KEY1.press_timerms=PRESS_NONE; bsp_led_toggle(&LED0); } else if(KEY2.press_timerms == PRESS_DOWN) { KEY2.press_timerms=PRESS_NONE; bsp_led_toggle(&LED0); } else if(WKUP.press_timerms == PRESS_DOWN) { WKUP.press_timerms=PRESS_NONE; bsp_led_toggle(&LED0); } else { bsp_led_off(&LED0); } //直接讀取按鍵有按下 if(bsp_key_state_get(&KEY0)==SET) { bsp_led_toggle(&LED1); } else if(bsp_key_state_get(&KEY1)==SET) { bsp_led_toggle(&LED1); } else if(bsp_key_state_get(&KEY2)==SET) { bsp_led_toggle(&LED1); } else if(bsp_key_state_get(&WKUP)==SET) { bsp_led_toggle(&LED1); } else { bsp_led_off(&LED1); } } } |
按鍵初始化函數如下,通過KEY_DEF定義相關按鍵參數,之后調用bsp_key_init對按鍵進行分別初始化。
C void bsp_key_group_init(void) { uint8_t i; for(i=0;i { bsp_key_init(((typdef_bsp_key *)KEY_INIT_GROUP[i])); } } KEY_DEF(KEY0,E,2,IN_PU,SET,NULL); // PE2定義為KEY0中斷模式,默認狀態高 KEY_DEF(KEY1,E,3,IN_PU,SET,NULL); // PE3定義為KEY1非中斷模式,默認狀態高 KEY_DEF(KEY2,E,4,IN_PU,SET,NULL); // PE4定義為KEY2非中斷模式,默認狀態高 KEY_DEF(WKUP,A,0,IN_PU,SET,NULL); // PA0定義為KEY2非中斷模式,默認狀態高 |
通過key_scan進行按鍵掃描,實現對按鍵按下時間長度范圍的檢測。
C bit_status key_scan(uint16_t scan_ms_cycle) { uint8_t i; bit_status press_flag=RESET; for(i=0;i { // ((typdef_bsp_key *)KEY_INIT_GROUP[i])->press_timerms=press_none; if(bsp_key_state_get((typdef_bsp_key *)KEY_INIT_GROUP[i])==SET && ((typdef_bsp_key *)KEY_INIT_GROUP[i])->press_cycle_count<0xffff){ ((typdef_bsp_key *)KEY_INIT_GROUP[i])->press_timerms =PRESS_DOWN; ((typdef_bsp_key *)KEY_INIT_GROUP[i])->press_cycle_count+=scan_ms_cycle; } } for(i=0;i { if(bsp_key_state_get((typdef_bsp_key *)KEY_INIT_GROUP[i])==SET && ((typdef_bsp_key *)KEY_INIT_GROUP[i])->press_cycle_count < 0xffff) //持續60s被按下按鍵可能損壞 ??????? { return press_flag; } } for(i=0;i { if(((typdef_bsp_key *)KEY_INIT_GROUP[i])->press_cycle_count>PRESS_50MS) { press_flag=SET; if(((typdef_bsp_key *)KEY_INIT_GROUP[i])->press_cycle_count > PRESS_5000MS){ ((typdef_bsp_key *)KEY_INIT_GROUP[i])->press_timerms=PRESS_5000MS; } else if(((typdef_bsp_key *)KEY_INIT_GROUP[i])->press_cycle_count>PRESS_4000MS){ ((typdef_bsp_key *)KEY_INIT_GROUP[i])->press_timerms=PRESS_4000MS; } else if(((typdef_bsp_key *)KEY_INIT_GROUP[i])->press_cycle_count>PRESS_3000MS){ ((typdef_bsp_key *)KEY_INIT_GROUP[i])->press_timerms=PRESS_3000MS; } else if(((typdef_bsp_key *)KEY_INIT_GROUP[i])->press_cycle_count>PRESS_2000MS){ ((typdef_bsp_key *)KEY_INIT_GROUP[i])->press_timerms=PRESS_2000MS; } else if(((typdef_bsp_key *)KEY_INIT_GROUP[i])->press_cycle_count>PRESS_1000MS){ ((typdef_bsp_key *)KEY_INIT_GROUP[i])->press_timerms=PRESS_1000MS; } else if(((typdef_bsp_key *)KEY_INIT_GROUP[i])->press_cycle_count>PRESS_500MS){ ((typdef_bsp_key *)KEY_INIT_GROUP[i])->press_timerms=PRESS_500MS; } else if(((typdef_bsp_key *)KEY_INIT_GROUP[i])->press_cycle_count>PRESS_200MS){ ((typdef_bsp_key *)KEY_INIT_GROUP[i])->press_timerms=PRESS_200MS; } else{ ((typdef_bsp_key *)KEY_INIT_GROUP[i])->press_timerms=PRESS_50MS; } } if(bsp_key_state_get((typdef_bsp_key *)KEY_INIT_GROUP[i])==RESET){ ((typdef_bsp_key *)KEY_INIT_GROUP[i])->press_cycle_count=0; } } return press_flag; } |
3.5實驗結果
將本例程燒錄到紅楓派開發板中,連接USB串口通過Type C接口,上電后打開串口調試助手,先按下復位按鍵,讓系統復位運行。
首先在串口調試助手上打?。篍xample of key scan detection.
之后按下任意按鍵,松開后將會打印按鍵按下的時間范圍。
具體現象如下所示。
![wKgZomZX3f2ACnYwAAC_A1OSc68148.png](https://file1.elecfans.com/web2/M00/EA/54/wKgZomZX3f2ACnYwAAC_A1OSc68148.png)
-
單片機
+關注
關注
6043文章
44622瀏覽量
638522 -
嵌入式
+關注
關注
5092文章
19177瀏覽量
307650 -
開發板
+關注
關注
25文章
5121瀏覽量
98191 -
GPIO
+關注
關注
16文章
1216瀏覽量
52377
發布評論請先 登錄
相關推薦
STM32CUBEMX開發GD32F303(6)----GPIO輸入函數說明
![STM32CUBEMX<b class='flag-5'>開發</b><b class='flag-5'>GD32F303</b>(6)----<b class='flag-5'>GPIO</b>輸入函數說明](https://file.elecfans.com/web2/M00/7D/B1/pYYBAGN9lquADVPRAAdK0uCRbS8927.jpg)
【星空派GD32F303開發板試用體驗】開發記錄匯總
【星空派GD32F303開發板試用體驗】開箱+環境搭建
【星空派GD32F303開發板試用體驗】開箱+環境搭建
【星空派GD32F303開發板試用體驗】+板卡概覽
GD32F303固件庫開發
![<b class='flag-5'>GD32F303</b>固件庫<b class='flag-5'>開發</b>](https://file.elecfans.com/web2/M00/7E/B7/poYBAGOG-mGAZl3hABOR8D6E0tU278.png)
【GD32F303紅楓派開發板使用手冊】第二講 GPIO-流水燈實驗
![【<b class='flag-5'>GD32F303</b><b class='flag-5'>紅楓</b><b class='flag-5'>派</b><b class='flag-5'>開發板</b><b class='flag-5'>使用手冊</b>】第二<b class='flag-5'>講</b> <b class='flag-5'>GPIO-</b>流水燈<b class='flag-5'>實驗</b>](https://file1.elecfans.com/web2/M00/EA/0A/wKgZomZWjIGAa8HvAAAfwpvxoD4203.png)
【GD32F303紅楓派開發板使用手冊】第五講 FMC-片內Flash擦寫讀實驗
![【<b class='flag-5'>GD32F303</b><b class='flag-5'>紅楓</b><b class='flag-5'>派</b><b class='flag-5'>開發板</b><b class='flag-5'>使用手冊</b>】第五<b class='flag-5'>講</b> FMC-片內Flash擦寫讀<b class='flag-5'>實驗</b>](https://file1.elecfans.com/web2/M00/EB/E3/wKgaomZb036AbrwmAAAy6saV5XI905.png)
【GD32F303紅楓派開發板使用手冊】第十六講 USART-DMA串口收發實驗
![【<b class='flag-5'>GD32F303</b><b class='flag-5'>紅楓</b><b class='flag-5'>派</b><b class='flag-5'>開發板</b><b class='flag-5'>使用手冊</b>】第十六<b class='flag-5'>講</b> USART-DMA串口收發<b class='flag-5'>實驗</b>](https://file1.elecfans.com/web2/M00/EF/11/wKgaomZs9FuAR6kDAAAeVi2N6To941.png)
【GD32F303紅楓派開發板使用手冊】第二十講 SPI-SPI NAND FLASH讀寫實驗
![【<b class='flag-5'>GD32F303</b><b class='flag-5'>紅楓</b><b class='flag-5'>派</b><b class='flag-5'>開發板</b><b class='flag-5'>使用手冊</b>】第二十<b class='flag-5'>講</b> SPI-SPI NAND FLASH讀寫<b class='flag-5'>實驗</b>](https://file1.elecfans.com/web2/M00/F1/AD/wKgaomZzisiAamI-AABGtAQwDgo073.png)
評論