判断按键值_一个ADC实现多个按键检测

本文介绍了利用ADC实现多按键检测的方法,包括独立按键、矩阵按键和ADC分压键盘的优缺点。重点讲述了ADC分压键盘的工作原理,通过电阻分压和ADC读取电压值来判断不同按键状态。通过实测数据,展示了如何根据ADC值判断按键值,并提供了烧录和调试的步骤。
AI助手已提取文章相关产品:

442700e5238cf5e6c7ab80775e8b93ff.gif

870cd47c511b828fb8af4a66861cf288.png获取按键值的方式

按键作为常用的输入系统,如何准确并高效的获取按键值,是一个经常要面对的问题,常用的按键检测方式有如下几种方式:

1. 独立按键

每个按键的检测占用单片机的一个GPIO引脚,原理图如下图所示:

dd08eefe6ead742d0b79fcaa53833b29.png

图片来源公众号自制核心板原理图

我们以BTN1按键为例,当按键没有按下的时候,网络标号KEY1处的电压被10K的上拉电阻拉至3.3V,PB14(KEY1)引脚设为输入引脚后,程序中读取该引脚的值将为1,当按键按下之后,网络标号KEY1处接地,读取该输入引脚的值将为0,进而通过此电路实现的独立按键,可以区分按键弹起和按下两种不同的状态。

独立按键的每个按键的工作不会影响其他I/O的状态。独立按键缺点是浪费MCU管脚,优点是编程比较简单。

独立按键的实现原理详见我们之前分享的网文:

基于鸿蒙OS的按键驱动

2. 矩阵按键

矩阵按键又称为矩阵键盘或称行列键盘,其实现的原理我们之前分享过如下网文:

矩阵键盘的行列扫描原理详解

这种行列式键盘结构能有效地提高单片机系统中I/O口的利用率。在MCU管脚有限的情况下,矩阵按键大大的节省了I/O资源。

3. ADC分压键盘

利用电阻串联分压的原理实现一个ADC管脚去检测多个按键。

按键被按下之后,与ADC引脚相连的点的电压会随着参与分压的电阻变化而变化,我们只要让每个按键按下之后的电压处于不同的区间,我们理论上就能够将各个按键区分开。

为了避免由于ADC精度、电阻的误差或者温漂等因素造成的按键检测失效,提高按键检测的可靠性,我们可以减少按键数量,适当放宽各个按键检测的电压范围。

经过上面的分析,独立按键的方式是最浪费GPIO口,矩阵按键的效率适中,而ADC分压实现的键盘使用的GPIO引脚最少。

ADC检测按键原理

eb9d0fa076d937038595d91e81b82806.png

如果Vcc = 3.3V ,那么没有按键被按下时,ADC为3.3V,如果有按键被按下:

被按下的按键ADC值

Key1

0 V

Key2

1.65 V

Key3

2.2 V

Key4

2.475 V

Key5

2.64 V

Key6

2.75 V

我们由上可以看到,一串相同电阻(10K)组成的多个按键,相连按键之间的电压差越来越小,不利于继续进行扩展。

e4ac114c0e69ba6c8329b29094ad5b8d.png

为了方便对比,如果 +5V 换成 3.3V ,那么没有按键被按下时,ADC为3.3V,如果有按键被按下:

被按下的按键ADC值

sw1

0 V

sw2

0.163 V

sw3

0.503 V

sw4

0.819 V

sw5

1.157 V

sw6

1.487 V

由上我们看出,这组电阻组成的多个按键检测电路,相邻按键之间的电压差值基本在0.3V左右,可以在此电路基础上继续进行扩展,设计成更多的按键扫描电路。

有了上面的经验,大家算一下下图中,不同按键按下的话,ADC的值应该为多少呢?

3b1cd8912618c7c586fa35842127847b.png

按键原理图

74b4def5421752443d64a1c25ffd0099.png

核心板左下角的按键S2的原理图:

2b4c3490a464563c920450f38170cdb6.png

OLED板上的按键1和按键2的原理图:

8f03ad48c1278369c97dc8040d98e9c2.png

由上面两个原理图可知,三个按键都是与GPIO_05这个引脚相连,GPIO_05引脚还具有ADC功能。

556d1e4fe3ea4989bda8c1280f515bdf.png

根据上面ADC分压的原理我们可知,当三个按键按下时,GPIO_05处的理论电压如下:

被按下的按键理论电压

常态(没有按键按下时)

3.3 V

S2(核心板)

0V

S1(OLED)

(1/(4.7+1))*3.3=0.579 V

S2(OLED)

(2/(4.7+1+1))*3.3=0.985 V

获取ADC值

官方手册ADC功能描述如下:

aed8a977c93dc0a5665c1dcc8ae09355.png

1. 引脚初始化

aadd0525c06fa5a815619a9eb74db337.png

由于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 

 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

b86e37bec1494eb10a6939dc40a4a59e.png

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 

 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_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

b5ef86337e40f11f7873c91aac1d4c22.png

串口打印输出

为了按键能够准确识别,我们首先要知道各个按键被按下时,ADC的值的范围,我们在程序中获取GPIO_05 引脚处的ADC值,利用下面的函数进行打印输出,进而观察各种状态下,ADC的值是多少:

printf("KEY adc value is %f \r\n",key_adc_value);

具体打印输出如下:

1. 常态没有按键按下时,ADC值的范围在 3.262 ~ 3.266之间,串口打印输出如下:

c3e53d992a29e850eccb1c5a9496db5a.png

2. 当按下按键S2(核心板)时,ADC值的范围在 0.214 ~ 0.218之间,串口打印输出如下:

5d3992ec3816d8c8dc0870f1e6dd8353.png

3. 当按下按键S1(OLED)时,ADC值的范围在 0.569 ~ 0.573之间,串口打印输出如下:

21d0caa2b21fd32028ee05f77a8c727b.png

4. 当按下按键S2(OLED)时,ADC值的范围在 0.970 ~ 0.974之间,串口打印输出如下:

bf947e378d245f725903eb008576235a.png

5. 结果汇总

被按下的按键理论电压实际电压

常态(没有按键按下时)

3.3 V

3.266 V

S2(核心板)

0V

0.214 V

S1(OLED)

(1/(4.7+1))*3.3=0.579 V

0.573 V

S2(OLED)

(2/(4.7+1+1))*3.3=0.985 V

0.973 V

对比串口打印的ADC值和理论计算值,我们可以看出两者的实际偏差不是很大,而且值相对稳定,我们只需要在实际值基础上增加一个偏差,比如0.15 V,即可区分出板子上的三个按键。

被按下的按键理论电压实际电压判断区间

常态(没有按键按下时)

3.3 V

3.266 V

vlt_val > 3 V

S2(核心板)

0V

0.214 V

vlt_val < 0.3 V

S1(OLED)

0.579 V

0.573 V

0.4 V < vlt_val < 0.7 V

S2(OLED)

0.985 V

0.973 V

0.8 V < vlt_val < 1.1 V

6. 按adc值的范围区间,判断按键值

具体判断的实现如下:

if(vlt_val 

{

 if(key_flag == 0)

 {

  key_flag = 1;

  key_status = KEY_EVENT_S2_CORE;

 }

}

if((vlt_val > 0.4) && (vlt_val 

{

 if(key_flag == 0)

 {

  key_flag = 1;

  key_status = KEY_EVENT_S1_OLED;

 }

}

if((vlt_val > 0.8) && (vlt_val 

{

 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脚本文件具体实现如下图所示:

d4d025413922e6daf5260d26308da217.png870cd47c511b828fb8af4a66861cf288.png获得HiBurn软件

1. 解压DevEcoDeviceTool-1.0.0.zip

aae265a191f3c51efe49c31760064c3c.png

此文件,在下面网文中分享过,可以自提:

HarmonyOS智能设备开发工具—DevEco Device Tool 安装配置

2. 将解压后生成的.vsix文件重命名为.zip结尾的任意名称,比如:DevEcoDeviceTool-1.0.0-temp.zip , 然后解压此文件。

87fbe9ff7a7abfee252ce63e022a03f9.png

3. 在 \devicetool-device-1.0.0.0\extension\deveco\tools 文件夹下即有HiBurn.exe 文件。

916107ef98372c8a7b4e4c8f4a56e40c.png

使用HiBurn烧写.bin文件至Hi3861

双击HiBurn.exe文件,在弹出界面中,选择菜单:Setting-->Com settings ,在弹出窗口中,Baud选择一个稍微高点的波特率,加快文件传输速度;

9f1ac58c59f38dbcb1d5de3588a077ac.png

选择Hi3861核心板对应的串口,点击“Select file”按钮,选择要下载的固件文件:Hi3861_wifiiot_app_allinone.bin,我们打开此文件之后,会发现下面列表中出现了三个文件,实际上这个.bin文件由列表中的三个文件组成。勾选“Auto burn”复选框,然后选择“Connect”按钮,进入如下待下载界面:

e6c14419168683c601557224d001624b.png

复位核心板模块,进入下载模式,下载完成后点击“Disconnect”按钮断开连接。

e80fd1c4346415db6765019f55a1895f.png

和DevEco Device Tool方式对比

使用HiBurn烧录相对于VSCode中使用DevEco Device Tool烧录而言,好处主要有以下几点:

1. 不依赖VSCode,所以下面网文的配置过程可以省略了;

HarmonyOS智能设备开发工具—DevEco Device Tool 安装配置

2. 下载速度更快,HiBurn.exe最大波特率可以设置到4000000,而DevEco Device Tool最大只能为921600,是它的4.34倍;

51cb935f603b357e92b477350502c799.png

HiBurn方式烧录的缺点主要是:

1. 烧录完成标志不是很明显,需要认真观察;

2. 烧录完成之后需要手动点Disconnect,主动断开连接,否则将一直占用此串口;如果在未断开的情况下,再次按了一下RESET按键,HiBurn软件将会再一次对固件进行烧录。

结果展示

依次按三次Hi3861开发套件上的三个按键S2(CORE)、S1(OLED)、S2(OLED),串口打印输出如下:

21c16436e9b17878519f3c4e6a376555.png

ADC获取的电压波动在我们设定的范围内,所以我们看到能够正确的识别对应的按键。

870cd47c511b828fb8af4a66861cf288.png小结

学习实现的思想,自己可以使用自己的板子实现一下,无论51单片机还是STM32作为主控,实现的原理都是一样的,文中提供的代码,除了获取ADC值的方式不一样外,其他代码都是可以通用参考的。

0c38c4e873b8088205dd669fc4126598.gif关注公众号『翻滚吧工程师』,专注于运营嵌入式技术交流学习社群,倾力引入打造嵌入式实战课程,旨在赋能在读大学生、应届毕业生、初入社会就业者、初中级嵌入式工程师及电子爱好者的高端电子技术学习生态圈。0c38c4e873b8088205dd669fc4126598.gif

e42140dbb1c1c0feb1da925fd18f5e01.png

觉得内容不错的话,点个在看呗

4de4b81d07a19031f121201a42a4002d.gif

您可能感兴趣的与本文相关内容

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值