1. 按键的分类
在嵌入式系统中,按键是最常见的人机交互接口之一。根据按键数量和硬件资源限制,可分为独立按键和矩阵按键两种类型。本文将从原理、硬件设计、软件实现、优缺点及应用场景等方面进行详细对比,并着重介绍如何使用一个GPIO即可实现矩阵键盘的功能。
着重介绍内容在3.2.3小节和第五章,文末提供本例程仿真与程序源码,不足之处还请指正!
2. 核心原理
2.1 独立按键
结构:每个按键独立连接一个IO口,采用共阴极或共阳极设计(习惯使用共阴)。
工作原理:
1. 未按键时,IO口通过上拉电阻保持高电平。
2. 按键按下时,IO口电平被拉低,触发中断或轮询检测。
2.2 矩阵按键
结构:由行线(Row)和列线(Column)交叉形成按键矩阵(如4x4=16键)。
工作原理:
1. 逐行置低电平,其余行置高。
2. 检测列线电平,若某列变低,则对应行和列的交点为按下的按键。
3. 硬件设计对比
3.1 独立按键电路
按键内部结构图
按键识别过程(按下>松开)
优点:接线简单,扫描程序相对简单,适合按键数≤8的场景。
缺点:存在机械抖动,在按下瞬间不稳定,需使用软件优化扫描程序,每个按键均需一个GPIO,实时系统中频繁的按键中断可能会出现失效,延迟响应等问题。
3.2独立按键的优化
独立按键在系统中使用的频率是远远大于矩阵键盘的,因此它的缺点我们无法忽略,所以给大家提供一个新思路,如何避开机械抖动与响应滞后的问题。
3.2.1外部中断
相信大家对外部中断都不陌生吧。外部中断是单片机的一种硬件机制,允许外部设备(如按键、传感器)通过特定引脚触发中断,暂停当前任务,优先执行中断服务程序(ISR)。
3.2.2外部中断的优势
实时性:快速响应外部事件(如紧急停止)。
低功耗:无需轮询,CPU空闲时可进入睡眠模式。
高效性:中断触发时才执行任务,减少CPU资源占用。
3.2.3外部中断的使用
仅需将按键接入外部中断引脚,在程序中配置中断即可使用。
示例代码:(STC89Cxx为例)
外部中断初始化配置
// 配置外部中断0为下降沿触发
IT0 = 1; // 触发方式选择(0:电平触发,1:下降沿触发)
EX0 = 1; // 使能外部中断0
EA = 1; // 总中断使能
//外部中断0服务程序
void INT0_ISR() interrupt 0
{
delay_ms(10); // 消抖
if(KEY == 0)
{
LED = !LED; // 切换LED状态
}
}
如此便可利用外部中断的特性,及时响应按键的处理。
3.2.3进一步的优化
对于STC89Cxx的单片机来讲,仅提供两个外部中断源(INT0 INT1)来说,对于多数人来说是远远不够的!所以请看下图!
仅需增加一个与门电路即可实现多个按键共用一个外部中断!
原理:当有按键按下的时候同时会触发外部中断的电平反转,进而触发外部中断源
注意:按键接法需与外部中断触发方式对应,图中按键共阴接法,外部中断下降沿触发。
附:与门真值表方便大家理解其工作原理,以二输入为例(有输入为0时,输出即为0产生下降沿,否则输出为1)
3.3 矩阵按键电路
优点:16键仅需8个IO口,节省资源。
缺点:扫描程序复杂,对新手不友好,同时相对于STC89C52来说,8个IO口的占用也是比较痛苦的
4. 软件实现对比
4.1 独立按键代码示例
// 检测按键是否按下(带消抖)
sbit KEY_PIN = P3^0;
void check_key()
{
if(KEY_PIN == 0)
{
delay_ms(10); // 消抖
if(KEY_PIN == 0)
{
// 执行按键功能
}
}while(KEY_PIN==0); //松手检测
}
4.2 矩阵按键代码示例
// 4x4矩阵键盘扫描
unsigned char Keyboard_Scan()
{
unsigned char row, col;
for(row=0; row<4; row++)
{
P1 = ~(1 << row); // 逐行置低
_nop_(); _nop_(); // 消抖
if(P1 & 0x10) col = 0;
else if(P1 & 0x20) col = 1;
else if(P1 & 0x40) col = 2;
else if(P1 & 0x80) col = 3;
else continue;
while(P1 & 0xF0); // 等待释放
return row*4 + col + 1; // 生成键值
}
return 0;
}
5.如何使用一个GPIO实现矩阵键盘
5.1实现原理图(该图来自官方手册,下文对应程序是根据介绍自行编写)
仿真排版后的仿真图(仿真中STC系列的单片机只有这款本身有ADC功能,如果你使用的单片机本身无ADC采集功能,也可使用外挂ADC,新手推荐ADC0832、PCF8591,精度8位)
各器件说明:
C1:滤波,避免抖动
R1:限流,防止电流过大
R2:下拉,无按键触发时提供一个稳定的采集值(官方取值200K,仿真时无法将电压下拉到很低,ADC值处于矩阵按键覆盖范围,对判断带来不便,因此降低阻值将电压值拉低到矩阵键值外。实际使用现场调试)
R3~R18:为每个按键提供一个分压值(最大电压值不得超过ADC输入最大值,可根据不同工作电压自行调整)
5.2原理
16个按键通过电阻分压使得每个按键触发后,接入ADC端口的电压值均不同,通过ADC采集后依次区分键值。
优点:仅需一个GPIO即可实现矩阵的功能,且无需消抖处理,响应速度极快,无任何迟滞。
缺点:需使用ADC功能,如本身无ADC功能需自行外挂ADC。程序处理略显麻烦,且需根据实时系统校准ADC键值。
5.3主要程序
ADC采集:
.c文件
.h文件
矩阵扫描:
.c文件
.h文件
5.4仿真结果
按键1触发效果
按键5触发效果
6.总结
以上程序已在Proteus中测试验证成功,合理增键按键,可有效降低GPIO的使用率,提高程序效率,如果使用的单片机为3.3V供电,请将按键输入电压改为3.3V,以防损坏ADC。
如需完整工程链接,请关注点赞评论获取
如有不足,请指出!