獲取按鍵值的方式
按鍵作為常用的輸入系統(tǒng),如何準確并高效的獲取按鍵值,是一個經常要面對的問題,常用的按鍵檢測方式有如下幾種方式:
1. 獨立按鍵
每個按鍵的檢測占用單片機的一個GPIO引腳,原理圖如下圖所示:
圖片來源自制核心板原理圖
我們以BTN1按鍵為例,當按鍵沒有按下的時候,網絡標號KEY1處的電壓被10K的上拉電阻拉至3.3V,PB14(KEY1)引腳設為輸入引腳后,程序中讀取該引腳的值將為1,當按鍵按下之后,網絡標號KEY1處接地,讀取該輸入引腳的值將為0,進而通過此電路實現的獨立按鍵,可以區(qū)分按鍵彈起和按下兩種不同的狀態(tài)。
獨立按鍵的每個按鍵的工作不會影響其他I/O的狀態(tài)。獨立按鍵缺點是浪費MCU管腳,優(yōu)點是編程比較簡單。
獨立按鍵的實現原理詳見我們之前分享的網文:基于鴻蒙OS的按鍵驅動
2. 矩陣按鍵
矩陣按鍵又稱為矩陣鍵盤或稱行列鍵盤,其實現的原理我們之前分享過如下網文:
這種行列式鍵盤結構能有效地提高單片機系統(tǒng)中I/O口的利用率。在MCU管腳有限的情況下,矩陣按鍵大大的節(jié)省了I/O資源。
3. ADC分壓鍵盤
利用電阻串聯分壓的原理實現一個ADC管腳去檢測多個按鍵。
按鍵被按下之后,與ADC引腳相連的點的電壓會隨著參與分壓的電阻變化而變化,我們只要讓每個按鍵按下之后的電壓處于不同的區(qū)間,我們理論上就能夠將各個按鍵區(qū)分開。
為了避免由于ADC精度、電阻的誤差或者溫漂等因素造成的按鍵檢測失效,提高按鍵檢測的可靠性,我們可以減少按鍵數量,適當放寬各個按鍵檢測的電壓范圍。
經過上面的分析,獨立按鍵的方式是最浪費GPIO口,矩陣按鍵的效率適中,而ADC分壓實現的鍵盤使用的GPIO引腳最少。
ADC檢測按鍵原理
如果Vcc = 3.3V ,那么沒有按鍵被按下時,ADC為3.3V,如果有按鍵被按下:
我們由上可以看到,一串相同電阻(10K)組成的多個按鍵,相連按鍵之間的電壓差越來越小,不利于繼續(xù)進行擴展。
為了方便對比,如果 +5V 換成 3.3V ,那么沒有按鍵被按下時,ADC為3.3V,如果有按鍵被按下:
由上我們看出,這組電阻組成的多個按鍵檢測電路,相鄰按鍵之間的電壓差值基本在0.3V左右,可以在此電路基礎上繼續(xù)進行擴展,設計成更多的按鍵掃描電路。
有了上面的經驗,大家算一下下圖中,不同按鍵按下的話,ADC的值應該為多少呢?
按鍵原理圖
核心板左下角的按鍵S2的原理圖:
OLED板上的按鍵1和按鍵2的原理圖:
由上面兩個原理圖可知,三個按鍵都是與GPIO_05這個引腳相連,GPIO_05引腳還具有ADC功能。
根據上面ADC分壓的原理我們可知,當三個按鍵按下時,GPIO_05處的理論電壓如下:
獲取ADC值
官方手冊ADC功能描述如下:
1. 引腳初始化
由于GPIO_05默認被復用為串口引腳,我們這里要想使用ADC功能,而上圖表格中沒有對應的ADC復用信號,所以我們只需要將GPIO_05設為普通GPIO輸入引腳即可。初始化代碼如下:
(hi_void)hi_gpio_init();
hi_io_set_func(HI_IO_NAME_GPIO_5, HI_IO_FUNC_GPIO_5_GPIO);
ret = hi_gpio_set_dir(HI_GPIO_IDX_5, HI_GPIO_DIR_IN);
if (ret != HI_ERR_SUCCESS) {
printf("===== ERROR ======gpio -> hi_gpio_set_dir1 ret:%d\r\n", ret);
return;
}
2. 獲取ADC值
這里使用hi_adc_read函數獲取adc的值,為了使得到的數據相對準確,我們對數據進行多次采集,然后將得到的數據緩存到數組中,然后再對數組中的數據進行集中處理。
memset_s(g_adc_buf, sizeof(g_adc_buf), 0x0, sizeof(g_adc_buf));
for (i = 0; i < ADC_TEST_LENGTH; i++) {
ret = hi_adc_read((hi_adc_channel_index)HI_ADC_CHANNEL_2, &data, HI_ADC_EQU_MODEL_1, HI_ADC_CUR_BAIS_DEFAULT, 0);
if (ret != HI_ERR_SUCCESS) {
printf("ADC Read Fail\n");
return;
}
g_adc_buf[i] = data;
}
其中函數hi_adc_read在如下文件中實現:
\vendor\hisi\hi3861\hi3861\platform\drivers\adc\hi_adc.c
3. 對數組中的ADC值進行數據處理,計算方法為取這些數據的和,然后減去其中的最大值和最小值,然后再取平均值。
hi_u32 i;
float vlt_max = 0;
float vlt_min = VLT_MIN;
float vlt_sum = 0;
float vlt_val = 0;
hi_u16 vlt;
for (i = 0; i < data_len; i++) {
vlt = g_adc_buf[i];
float voltage = hi_adc_convert_to_voltage(vlt);
vlt_max = (voltage > vlt_max) ? voltage : vlt_max;
vlt_min = (voltage < vlt_min) ? voltage : vlt_min;
vlt_sum += voltage;
}
vlt_val = (vlt_sum - vlt_min - vlt_max) / (data_len - 2.0);
其中函數hi_adc_convert_to_voltage的實現位于:\vendor\hisi\hi3861\hi3861\platform\drivers\adc\hi_adc.c
串口打印輸出
為了按鍵能夠準確識別,我們首先要知道各個按鍵被按下時,ADC的值的范圍,我們在程序中獲取GPIO_05 引腳處的ADC值,利用下面的函數進行打印輸出,進而觀察各種狀態(tài)下,ADC的值是多少:
printf("KEY adc value is %f \r\n",key_adc_value);
具體打印輸出如下:
1. 常態(tài)沒有按鍵按下時,ADC值的范圍在 3.262 ~ 3.266之間,串口打印輸出如下:
2. 當按下按鍵S2(核心板)時,ADC值的范圍在 0.214 ~ 0.218之間,串口打印輸出如下:
3. 當按下按鍵S1(OLED)時,ADC值的范圍在 0.569 ~ 0.573之間,串口打印輸出如下:
4. 當按下按鍵S2(OLED)時,ADC值的范圍在 0.970 ~ 0.974之間,串口打印輸出如下:
5. 結果匯總
對比串口打印的ADC值和理論計算值,我們可以看出兩者的實際偏差不是很大,而且值相對穩(wěn)定,我們只需要在實際值基礎上增加一個偏差,比如0.15 V,即可區(qū)分出板子上的三個按鍵。
6. 按adc值的范圍區(qū)間,判斷按鍵值
具體判斷的實現如下:
if(vlt_val < 0.3))
{
if(key_flag == 0)
{
key_flag = 1;
key_status = KEY_EVENT_S2_CORE;
}
}
if((vlt_val > 0.4) && (vlt_val < 0.7))
{
if(key_flag == 0)
{
key_flag = 1;
key_status = KEY_EVENT_S1_OLED;
}
}
if((vlt_val > 0.8) && (vlt_val < 1.1))
{
if(key_flag == 0)
{
key_flag = 1;
key_status = KEY_EVENT_S2_OLED;
}
}
if(vlt_val > 3.0)
{
key_flag = 0;
key_status = KEY_EVENT_NONE;
}
7. 編譯腳本文件BUILD.gn
工程中兩個編譯使用的BUILD.gn腳本文件具體實現如下圖所示:
獲得HiBurn軟件
1. 解壓DevEcoDeviceTool-1.0.0.zip
此文件,在下面網文中分享過,可以自提:HarmonyOS智能設備開發(fā)工具—DevEco Device Tool 安裝配置
2. 將解壓后生成的.vsix文件重命名為.zip結尾的任意名稱,比如:DevEcoDeviceTool-1.0.0-temp.zip , 然后解壓此文件。
3. 在 \devicetool-device-1.0.0.0\extension\deveco\tools 文件夾下即有HiBurn.exe 文件。
使用HiBurn燒寫.bin文件至Hi3861
- 雙擊HiBurn.exe文件,在彈出界面中,選擇菜單:Setting-->Com settings ,在彈出窗口中,Baud選擇一個稍微高點的波特率,加快文件傳輸速度;
- 選擇Hi3861核心板對應的串口,點擊“Select file”按鈕,選擇要下載的固件文件:Hi3861_wifiiot_app_allinone.bin,我們打開此文件之后,會發(fā)現下面列表中出現了三個文件,實際上這個.bin文件由列表中的三個文件組成。勾選“Auto burn”復選框,然后選擇“Connect”按鈕,進入如下待下載界面:
- 復位核心板模塊,進入下載模式,下載完成后點擊“Disconnect”按鈕斷開連接。
和DevEco Device Tool方式對比
使用HiBurn燒錄相對于VSCode中使用DevEco Device Tool燒錄而言,好處主要有以下幾點:
1. 不依賴VSCode,所以下面網文的配置過程可以省略了;
HarmonyOS智能設備開發(fā)工具—DevEco Device Tool 安裝配置
2. 下載速度更快,HiBurn.exe最大波特率可以設置到4000000,而DevEco Device Tool最大只能為921600,是它的4.34倍;
HiBurn方式燒錄的缺點主要是:
1. 燒錄完成標志不是很明顯,需要認真觀察;2. 燒錄完成之后需要手動點Disconnect,主動斷開連接,否則將一直占用此串口;如果在未斷開的情況下,再次按了一下RESET按鍵,HiBurn軟件將會再一次對固件進行燒錄。
結果展示
依次按三次Hi3861開發(fā)套件上的三個按鍵S2(CORE)、S1(OLED)、S2(OLED),串口打印輸出如下:
ADC獲取的電壓波動在我們設定的范圍內,所以我們看到能夠正確的識別對應的按鍵。
小結
學習實現的思想,自己可以使用自己的板子實現一下,無論51單片機還是STM32作為主控,實現的原理都是一樣的,文中提供的代碼,除了獲取ADC值的方式不一樣外,其他代碼都是可以通用參考的。