前言
此系列教程针对蓝桥杯比赛。本人才疏学浅,如有不足之处,敬请批评指正。
摘要
本篇文章主要介绍了蓝桥杯嵌入式比赛扩展板上面ADC按键的工作原理与使用方法。
跳线帽与原理图
要想使用ADC按键需要将扩展板连接到主板上,如下图所示,并且还要短路扩展板上AKEY跳线帽。
连接成功后,ADC按键与主控板上的PA5(使用ADC2_IN13)引脚相连,ADC按键共有8个子按键,原理图如下图所示:
从上图可以看出,当没有按键按下时,ADC_KEY的电压为3.3V,当按下不同的按键时,根据串联分压原理,ADC_KEY上会产生不同的电压,根据电压的值,可判断哪个按键被按下。比如按键S1被按下时,ADC_KEY上的电压约为0.2V,按键S4按下时,ADC_KEY上的电压约为1.5V。
在比赛中需要对按键进行消抖,直接读取ADC的范围计算会导致按键多次抖动,造成功能无法实现。在官方例程中,消抖方式过于复杂,于是作者在这里提供一种高效的消抖方式。
官方例程
1、编写ADC采集函数
uint16_t getADC(void)
{
uint16_t adc = 0;
HAL_ADC_Start(&hadc2);
adc = HAL_ADC_GetValue(&hadc2);
return adc;
}
2、官方驱动例程
#include "button.h"
static u16 btn_buff[BTN_BUFF_LEN];
u16 Read_Btn(void)
{
u16 tmp;
u8 i = 0, j = 0;
for(i = 0; i < BTN_BUFF_LEN; i++)
{
btn_buff[i] = getADC();
}
for(i = 0; i <= BTN_BUFF_LEN / 2; i++)
{
for(j = 0; j < BTN_BUFF_LEN - i - 1; j++)
{
if(btn_buff[j + 1] < btn_buff[j])
{
tmp = btn_buff[j + 1];
btn_buff[j + 1] = btn_buff[j];
btn_buff[j] = tmp;
}
}
}
if(BTN_BUFF_LEN % 2 == 0)
{
return(btn_buff[BTN_BUFF_LEN / 2 - 1] + btn_buff[BTN_BUFF_LEN / 2]) / 2;
}
else
{
return(btn_buff[BTN_BUFF_LEN / 2]);
}
}
//
u8 Scan_Btn(void)
{
u16 btn_tmp = 0;
btn_tmp = Read_Btn();
if(btn_tmp < 0x0FFF / 14)
{
return 1;
}
else if((btn_tmp > 0x0FFF / 14) && (btn_tmp < 0x0FFF / 14 * 3))
{
return 2;
}
else if((btn_tmp > 0x0FFF / 14 * 3) && (btn_tmp < 0x0FFF / 14 * 5))
{
return 3;
}
else if((btn_tmp > 0x0FFF / 14 * 5) && (btn_tmp < 0x0FFF / 14 * 7))
{
return 4;
}
else if((btn_tmp > 0x0FFF / 14 * 7) && (btn_tmp < 0x0FFF / 14 * 9))
{
return 5;
}
else if((btn_tmp > 0x0FFF / 14 * 9) && (btn_tmp < 0x0FFF / 14 * 11))
{
return 6;
}
else if((btn_tmp > 0x0FFF / 14 * 11) && (btn_tmp < 0x0FFF / 14 * 13))
{
return 7;
}
else if((btn_tmp > 0x0FFF / 14 * 13) && (btn_tmp < 0x0F6F))
{
return 8;
}
else
{
return 0; //error status & no key
}
}
官方代码比较难理解,而且编写花费时间较多,这里作者采用使用标志位判断的方法同时对多个按键扫描判断,大大减短编写时间
高效代码
1、编写ADC采集函数(同上)
uint16_t getADC(void)
{
uint16_t adc = 0;
HAL_ADC_Start(&hadc2);
adc = HAL_ADC_GetValue(&hadc2);
return adc;
}
2、编写按键扫描函数
int key_scan(void)
{
static int flag=0;
if(getADC()<4000&&flag==0)
{
HAL_Delay(20);
flag=1;
if(getADC() < 10) return 1;
if(getADC() < 800) return 2;
if(getADC() < 1600) return 3;
if(getADC() < 2000) return 4;
if(getADC() < 2700) return 5;
if(getADC() < 3300) return 6;
if(getADC() < 3700) return 7;
if(getADC() < 4000) return 8;
}
else if(flag==1&&getADC()>4000)
flag=0;
return 0;
}
优化后的代码,通过判断按键是否按下,Delay延迟20毫秒,从而消抖。第二次通过ADC的值判断哪个按键按下并返回相应返回值。同时防止了多个按键同时按下造成的干扰,当全部按键松开时,标志位清0,才能进入下一轮判断按键值。在主函数中调用此函数,即可实现消抖后的按键扫描函数,非常方便。
注意:此函数中使用Delay函数来延时消抖,在整个代码中最好仅调用一次此函数(可以用switch判断函数的返回值来使用),调用多次扫描函数会有机率读取不到按键按下。