目录
一、原理图
根据原理图(第十四届官方资料包,第十五届的原理图展现形式略有更改,但原理用法一样)
蓝桥杯单片机矩阵按键原理是一种常见的按键输入方式,通常用于单片机系统中。它通过将按键排列成矩阵的形式,以节省 I/O 资源,从而实现多个按键共用少量引脚的目的。
以下是矩阵键盘的基本原理:
按键排列成矩阵形式:按键按行列排列成矩阵,每个按键对应矩阵中的一个元素。例如,4x4 的矩阵可以支持最多 16 个按键。
行列扫描:按键矩阵通过单片机的 GPIO 引脚连接。在读取按键输入之前,单片机首先将矩阵的每一行(或每一列)依次设置为输出,而其他行(列)则设置为输入。然后,单片机逐行(或逐列)地扫描,检测是否有按键被按下。
按键状态检测:当某一行(或列)被设置为输出时,如果此行(或列)上有按键按下,那么对应的输入引脚将被拉低(或拉高),单片机可以通过读取输入引脚的状态来检测按键是否被按下。
消除冲突:由于按键矩阵的扫描方式,可能会出现多个按键同时被按下的情况,称为按键冲突。为了解决这个问题,通常采用软件或硬件的方式进行消抖和冲突解析。
按键编码:一旦检测到有按键被按下,单片机就可以根据按键所在的行列位置来编码按键的唯一标识,以便后续的处理和响应。
二、按键单击
( 图片来源于B站小蜜蜂老师)
对于键盘,我们可以逐行扫描,然后读取列的状态信号。如果R3行输出低电平,那么黄色按键如果有按下动作的话,那读取C2列信号也应该为低电平,而该行上其他没有按下动作的按键的列信号则为高电平。因此,我们可以得到矩阵键盘的基本扫描步骤:
(1)先将要扫描的那一行设置为低电平:R1=0,(即随后在列上若读取到低电平则可视为按 键按下),把其他设置为高电平:R2=R3=R4=1。
(2)将每一列设置为高电平:C1=C2=C3=C4=1。
(3)开始扫描,依次判断C1~C4是否能读取低电平,循环往复。
(4)当如图黄色部分按下时,读取到C2=0,即可得知R3C2键按下。
1.定义引脚
#include <reg52.h> //引入头文件
sfr P4=P4^4; //定义P4,在<reg52.h>头文件中P4并未定义,需要手动定义一下
//若为#include <STC15F2K60S2.H>则无需定义
sbit R1=P3^0; //R1、C1为自己定义的符号,也可用其他
sbit R2=P3^1; //R为行,C为列
sbit R3=P3^2;
sbit R4=P3^3;
sbit R1=P4^4;
sbit R1=P4^2;
sbit R1=P3^5;
sbit R1=P3^4;
2.(示例)假设S7按下
void ScanKeys() //定义无返回值的按键函数
{
R1=0;R2=R3=R4=1; //设置第一行输出为低电平0,其余行输出高电平1
C1=C2=C3=C4=1; //初始化所有列
if(C1==0) //若扫描得到第一列输出低电平
{
Delay(100); //消抖
if(C1==0) //如果消抖后依旧得到第一列为高电平
{
##要执行的代码
}
while(C1==0); //等待按键松开
}
}
3.消抖
按键的消抖是指在物理按键被按下或释放时,由于机械性质导致的电气信号的不稳定性,可能会产生的多次触发问题。当按键被按下或释放时,金属接点会快速接通或断开,但在这个过程中可能会出现弹跳或震动,导致接触不稳定,电气信号也会反复变化,从而使得单片机或电路系统误认为按键被多次按下或释放。
解决办法有:
硬件消抖:在电路设计中,通过添加外部电容、电阻或使用特殊的按键组件,来减少按键接触时的震动和弹跳,从而降低按键信号的不稳定性。
软件消抖:在单片机程序中通过软件算法来处理按键信号。软件消抖通常包括两种基本方法:
- 延时检测:在检测到按键状态变化后,延时一段时间(称为消抖时间),然后再次检测按键状态。如果在延时时间内按键状态保持不变,则确认按键有效,否则继续等待。
- 状态机检测:利用状态机来跟踪按键状态变化的过程,包括按键的按下、保持、释放等状态,通过状态的切换来判断按键的有效触发。
通常,我们采用延时检测,跳过其反馈不稳定部分的检测。
void Delay(unsigned int t) //通常延时100us即可
{
while(t--);
}
除了自己写的延时代码外,也可以引入头函数,利用软件来生成延时函数。
#include "intrins.h"
(此处不作具体展示)
三、按键双击
双击的原理其实很好理解,在按下后(检测到按键信号)在短时间内再次检测到低电平。
此处需要利用定时器来解决。
unsigned int num=0; //按键次数
unsigned char count; //定时器计数
bit F=0; //按键按下标志位
void InitT0()
{
TMOD=0x01;
TH0=(65536-10000)/256;
TL0=(65536-10000)%256;
ET0=1;
TR0=1;
EA=1; //打开定时器
}
void SevericeT0() interrupt 1 //利用定时器0
{
TH0=(65536-10000)/256; //手动重装
TL0=(65536-10000)%256;
if(F==1)
{
count++;
}
}
void ScanKeys()
{
R1=0;R2=R3=R4=1;
C1=C2=C3=C4=1;
if(C1==0)
{
Delay(100);
if(C1==0)
{
count=0; //每次按下清除定时器计数
F=1; //开始计时
num++; //按下次数+1
}
while(C1==0);
}
if(count>50) //如果间隔大于0.5s则结束计数
{
F=0; //关闭计时
count=0; //重置计数
}
if(num==1)
{
##单击代码
num=0; //重置按键数
}
else if(num==2)
{
##双击代码
num=0;
}
}
以上为个人的理解与代码,精彩内容持续呈现中~~~