3.1實(shí)驗(yàn)內(nèi)容
通過本實(shí)驗(yàn)主要學(xué)習(xí)以下內(nèi)容:
- GPIO輸入功能原理;
- 按鍵查詢輸入檢測(cè)原理;
3.2實(shí)驗(yàn)原理
3.2.1GPIO輸入功能原理
GD32F303系列MCU GPIO輸入配置結(jié)構(gòu)如下圖所示,輸入可配置上下拉電阻,通過施密特觸發(fā)器后可通過備用功能輸入或者通過輸入狀態(tài)寄存器進(jìn)行讀取。
輸入狀態(tài)寄存器為GPIOx_ISTAT,其狀態(tài)位定義如下圖所示,每個(gè)控制位對(duì)應(yīng)相應(yīng)引腳的輸入電平狀態(tài)。
GPIO引腳輸入電平判斷閾值如下圖所示,當(dāng)輸入電平小于0.3VDD時(shí),可被內(nèi)部有效識(shí)別為低電平;當(dāng)輸入電平大于0.7VDD時(shí),可被內(nèi)部有效識(shí)別為高電平。
3.3硬件設(shè)計(jì)
GD32F303紅楓派開發(fā)板具有四個(gè)按鍵,對(duì)應(yīng)電路圖如下圖所示,該四個(gè)按鍵均具有上拉限流電阻,對(duì)引腳防護(hù)電阻以及對(duì)地消抖電容。在按鍵未按下時(shí),對(duì)應(yīng)GPIO引腳的電平為高電平,按下引腳后,對(duì)應(yīng)GPIO引腳的電平為低電平,通過讀取按鍵對(duì)應(yīng)GPIO引腳的電平狀態(tài)可檢測(cè)對(duì)應(yīng)按鍵是否被按下。
注意:機(jī)械按鍵在按下或者松開時(shí)具有抖動(dòng),建議可增加硬件消抖或者軟件消抖,以避免按鍵檢測(cè)被多次觸發(fā)。 |
3.4代碼解析
本例程實(shí)現(xiàn)通過查詢的方式可查詢按鍵按下的時(shí)間,進(jìn)而可實(shí)現(xiàn)短時(shí)間按下和長時(shí)間按下的檢測(cè)。
主函數(shù)代碼如下,首先進(jìn)行延遲初始化/按鍵初始化/LED初始化/串口初始化,并打印Example of key scan detection.之后進(jìn)入主循環(huán),通過key_scan函數(shù)實(shí)現(xiàn)對(duì)按鍵的掃描并檢測(cè)按鍵按下時(shí)間。
C int main(void) { //系統(tǒng)延時(shí)初始化 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); //按鍵掃描結(jié)果檢查:檢測(cè)任意按鍵和多按鍵組合按下時(shí)間,所有按鍵彈起后有效 if(SET==key_scan(1)) { //檢測(cè)按鍵組合按下時(shí)長 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; } //檢測(cè)任意按鍵按下時(shí)長 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"); } } //按鍵掃描結(jié)果檢查:檢測(cè)任意按鍵有按下 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); } } } |
按鍵初始化函數(shù)如下,通過KEY_DEF定義相關(guān)按鍵參數(shù),之后調(diào)用bsp_key_init對(duì)按鍵進(jìn)行分別初始化。
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中斷模式,默認(rèn)狀態(tài)高 KEY_DEF(KEY1,E,3,IN_PU,SET,NULL); // PE3定義為KEY1非中斷模式,默認(rèn)狀態(tài)高 KEY_DEF(KEY2,E,4,IN_PU,SET,NULL); // PE4定義為KEY2非中斷模式,默認(rèn)狀態(tài)高 KEY_DEF(WKUP,A,0,IN_PU,SET,NULL); // PA0定義為KEY2非中斷模式,默認(rèn)狀態(tài)高 |
通過key_scan進(jìn)行按鍵掃描,實(shí)現(xiàn)對(duì)按鍵按下時(shí)間長度范圍的檢測(cè)。
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) //持續(xù)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實(shí)驗(yàn)結(jié)果
將本例程燒錄到紅楓派開發(fā)板中,連接USB串口通過Type C接口,上電后打開串口調(diào)試助手,先按下復(fù)位按鍵,讓系統(tǒng)復(fù)位運(yùn)行。
首先在串口調(diào)試助手上打印:Example of key scan detection.
之后按下任意按鍵,松開后將會(huì)打印按鍵按下的時(shí)間范圍。
具體現(xiàn)象如下所示。
本教程由GD32 MCU方案商聚沃科技原創(chuàng)發(fā)布,了解更多GD32 MCU教程,關(guān)注聚沃科技官網(wǎng)
-
單片機(jī)
+關(guān)注
關(guān)注
6037文章
44558瀏覽量
635298 -
嵌入式
+關(guān)注
關(guān)注
5082文章
19126瀏覽量
305195 -
開發(fā)板
+關(guān)注
關(guān)注
25文章
5050瀏覽量
97471 -
GPIO
+關(guān)注
關(guān)注
16文章
1204瀏覽量
52098
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論