首页 > 其他分享 >单片机线反转法实现矩阵键盘

单片机线反转法实现矩阵键盘

时间:2024-11-25 10:34:06浏览次数:7  
标签:输出 val 中断 矩阵 扫描 键盘 单片机 检测 按键

矩阵键盘原理

  • 前文描述的独立按键需要每一个都需要占用一个引脚控制,如果按键数多了,控制将会变得麻烦,并且浪费资源

  • 为此,使用矩阵键盘,每个引脚不连接单独的按键,而是连接一行或一列按键,当按下一个按键时,确定行列相交的坐标即可确定被按下的按键,如下图(最下面一排是独立按键,而上面的就是矩阵按键)

    image

    这样,只占用8个引脚,就实现了对16个按键的控制

  • 为了确定哪一个的按键被按下,就需要确定按键连接到了哪一行、哪一列的端口,而进行检测的方式有多种

轮询方式

  • 行列扫描法

    进行逐行、逐列扫描,确定按下按键的行与列

    1. 首先,把矩阵的行线设置为上拉输入,列线输出高电平

    2. 配置列线轮流输出低电平,然后读取行线输入引脚的电平

      如果没有按键被按下,则行线输入全为高电平;如果有按键按下,则行线输入引脚之一将检测到低电平

    3. 由于列线是轮流输出的,可以确定在输出到哪一列时哪一行出现了低电平,也即确定了按键是哪一行哪一列

    实现简单,但是扫描速度较慢,如果有多个按键同时按下就会出现冲突

  • 线反转法

    其本质同扫描法,都是通过查询来看哪一行那一列的按键被按下,其不同之处在于其原理是将键盘的行线和列线交替设置为输入和输出模式

    1. 首先,把矩阵的行全部置为上拉输入,列线全部输出低电平
    2. 读取每行的电平,哪一行的电平变低,哪一行上就出现了被按下的键
    3. 然后进行线反转:把行置为推挽输出低电平、列置为上拉输入,重复一边读取流程,确定哪一列被按下

    能够检测到所有按键的状态,多个按键按下也不会冲突,但是实现更复杂

  • 关于输出方法
    • 开漏输出不能输出高电平,需要上拉电阻才能输出高电平;但是在输出低电平时相当于接地,能够实现线与功能
    • 推挽输出能够输出真正的高电平;但不能线与,同一行上两个或以上按键按下会造成损坏,使用推挽输出的矩阵键盘电路要在输出引脚接反向二极管进行保护
    • 需要更详细的说明请在本合集查阅GPIO

    事实上,尽管两种输出方式在硬件上有诸多不同,但是在实际使用中都能实现矩阵键盘的功能,可以随便选

借助中断实现按键扫描

  • 上述的查询方式也称随机扫描法,本质就是用循环不停查询有没有按键被按下,占用CPU严重,进入键盘扫描程序后除了读取键盘输入状态外难以再进行其他工作,因此不具备实际价值

    基于上述的原理,借助中断功能,实现实际应用中的按键检测方法

  • 定时扫描法

    同样属于查询方式,本质上是随机扫描的方法(线扫描法或线反转法)+定时器中断监控,每隔一段时间才中断进行扫描,规避了不停查询对CPU的占用

    • 扫描方法同上,唯一的区别是像这样的扫描每隔一段时间(通常是20ms)进行一次,原理类似刷新数码管显示多位数

    定时扫描法占用中断资源少,但是占用CPU资源多,会出现空扫描的情况,当工程复杂度变高时,按键不灵敏

  • 中断监控法

    不再使用定时器中断监控,而是使用按键输入中断,进一步降低了对CPU的占用

    注意,一般这种用法适用于输入引脚来自同一组GPIO端口(因为同一组引脚共用一个中断出口,这样安排节省中断资源)的情况,而定时扫描法则可以是任意的引脚

    1. 首先,将矩阵的行配置为输出低电平,列配置为下降沿中断上拉输入
    2. 当有按键按下时,由于行被拉低、对应列的端口将会检测到下降沿,然后进入该列的中断服务函数
    3. 确定了列之后,在中断服务函数中通过查询来确定行:先把所有行置高,然后依次拉低每一行,检测该列的端口是否变为低电平,如果为低,证明是该行上的按键被按下

    中断法占用中断资源多,但是规避了空扫描的情况,按键更为灵敏

定时扫描按键状态法

  • 按键状态机

    按键一节中,提到为了提高CPU利用率应该尽可能规避使用延时来消抖;

    定时扫描法有一种特殊的消抖方式:在定时中断服务程序中用3位存储单元记录最近三次定时中断检测到的按键状态(没有按键按下为1,有按键为0)111表示没有按键按下;000表示按键稳定闭合

    按键状态的含义如下:

    • 不需要扫描的状态:110:前两次没有检测到按键,最后才检测到,不作处理;001:可能是按键释放过程;011:按键被释放
    • 需要进行按键扫描的状态:100:按下了按键;010:按键在按下途中无意松动;101:受负脉冲干扰,当作111处理;如果按键需要重复输入功能,那就还需要检测000状态
  • 按键状态流程

    综上,利用按键状态的流程是:

    1. 到按键检测的时间,输出全0扫描码,然后读出并记录按键状态
    2. 检测到100,则执行按键扫描;否则检测状态是否为010
    3. 检测到010,则表示受到干扰,重置为000;否则检查状态是否为000
    4. 检测到000,再去判断一次是否到了检测时间,如果到了就执行按键扫描,否则退出;没有检测到000则检测状态是否为101
    5. 检测到101,则表示受到干扰,重置为111;
    6. 退出检测程序

代码实现

  • 定时扫描

    使用线反转-定时扫描法实现矩阵键盘,其他方案不再演示

    //设置定时器,每20ms中断一次进行扫描,这一部分省略,重点看扫描函数,将扫描函数放在定时器的中断服务中即可
    //使用PC0-7作为矩阵键盘的扫描线,使用其他端口同理,修改代码即可
    //此程序以高4位为行,低4位为列
    //在主函数中调用之前的数码管显示函数,显示按下的键值
    #define KeyPort_in PC_IDR
    #define KeyPort_out PC_ODR
    unsigned int keybefore = 0;
    //准备一个变量存放之前的键值,避免刷新重置了按键值,这是为了让数码管保持显示键值
    //如果用作输入,可以直接判断0xFF为无效输入,或者使用标志位来判断是否更新键值
    
    unsigned int KeyScan(unsigned int *keybefore)
    {
    	u8 val=0xFF;//定义一个存放键值的变量
    	PC_DDR=0xF0;
    	PC_CR1=0xFF;
    	PC_CR2=0x00;//设置端口高四位推挽低速率输出,低四位为上拉输入
    	KeyPort_out=0x0F;//行线输出低电平,列线在上拉作用下为高电平
    	if(KeyPort_in!=0x0F)//检测有按键按下
    	{
    		switch(KeyPort_in)
    		{
    			case 0x0E:val=0; break;//0000 1110 第0列被按下
    			case 0x0D:val=1; break;//以此类推,第1列按下
    			case 0x0B:val=2; break;
    			case 0x07:val=3; break;
    			default:val=0xFF;break;//非正常单列按下的情况
    		}
    	}
    	PC_DDR=0x0F;//配置线反转:高四位上拉输入,第四位推挽输出
    	PC_CR1=0xFF;
    	PC_CR2=0x00;
    	KeyPort_out=0xF0;
    	if(KeyPort_in!=0xF0)
    	{
    		switch(KeyPort_in)
    		{
    			case 0xE0:val+=0; break;
    			case 0xD0:val+=4; break;
    			case 0xB0:val+=8; break;
    			case 0x70:val+=12; break;
    			default:val=0xFF;break;
    		}
    	}
    	if(val != 0xFF)
        {
    		*keybefore=val;
        }
        else
        {
    		val=*keybefore;
        }
    	return val;
    }
    

标签:输出,val,中断,矩阵,扫描,键盘,单片机,检测,按键
From: https://www.cnblogs.com/untit1ed/p/18567087

相关文章

  • USB键盘无法识别的解决方法
        键盘作为电脑输入的核心设备,其稳定性和可靠性对于我们的工作和娱乐至关重要。然而,在使用过程中,我们可能会遇到USB键盘无法被电脑识别的问题,这不仅影响效率,也可能带来不便。无论是由于硬件故障、驱动问题还是系统设置,解决这一问题都需要一定的技术知识和操作步骤。......
  • 多维数组与特殊矩阵:存储与压缩
    多维数组与特殊矩阵:存储与压缩一、多维数组的存储(一)基本概念多维数组是线性表的推广,例如二维数组可以看作是元素为一维数组的线性表,三维数组可以看作是元素为二维数组的线性表,以此类推。在内存中,多维数组需要按照一定的顺序进行存储,常见的存储方式有行优先存储和列优先存......
  • 【单片机基础】如何选择合适的低功耗单片机
    选择合适的低功耗单片机需要综合考虑多个因素,包括功耗、性能、外设接口、开发工具、成本和生态系统等。以下是一个详细的步骤和建议,帮助你选择合适的低功耗单片机:1.明确应用需求功耗要求:确定系统的功耗要求,特别是运行模式和睡眠模式下的功耗。性能需求:确定单片机需要支持的......
  • 关于电机(马达)在高速运转的时候可能影响单片机电路的原因和解决方法
    问题:我买了一个马达,然后写了用开关来调节PWM占空比然后给TB6612输入PWM来改变马达转速的代码,每按一次按键PWM+10%,不接马达的时候能正常加,一连上马达时,加到20%马达刚好转起来后我的PWM占空比就迅速疯狂加10然后到100爆了后然后回到0,马达转动还会影响我的外部中断?可能原因:有可......
  • 基于51单片机温湿度、烟雾浓度、人体检测报警
    基于51单片机智能环境监测(仿真+程序+原理图+设计报告)功能介绍具体功能:1.使用DHT11检测温湿度,MQ-2与ADC0832模数转换器检测烟雾,HC-SR501检测人体;2.LCD1602显示温湿度、烟雾信息;3.按键设定温湿度上下限、烟雾上限值,打开/关闭人体检测;4.超过设定范围发生对应的声光报警;5.......
  • 矩阵连乘问题
    矩阵连乘问题是一个经典的优化问题,可以通过动态规划方法有效解决。其目标是确定矩阵连乘的最佳顺序,以最小化计算所需的标量乘法次数。问题描述给定一系列矩阵(A_1,A_2,\ldots,A_n),每个矩阵(A_i)的维度为(p_{i-1}\timesp_i)。我们希望找到一种括号化方式,使得连乘......
  • 矩阵消元 elimination
    矩阵消元elimination​ 我们考虑一个方程组:\[\left\{\begin{matrix}x&+2y&+z&=&2\\3x&+8y&+z&=&12\\&4y&+z&=&2\end{matrix}\right.\]同之前一样,考虑\(A\symbfitx=b\)形式,得到:\[A=\begin{bmatrix}1&2&......
  • 盛世公司客服系统hj8828,vipS针对嵌入式STM32单片机的开发环境配置
    针对嵌入式【hj8828.vip】STM32单片机的开发环境配置薇【Lgj88288】,以下分别针对Windows和Mac系统提供详细的教学步骤。一、Windows系统配置教学选择开发软件Windows系统上有多种工具组合可供选择,包括单纯使用Keil进行库函数、HAL库以及寄存器的开发,也可以通过STM32CubeMX配......
  • 【041】基于51单片机篮球计分器【Proteus仿真+Keil程序+报告+原理图】
    ☆、设计硬件组成:51单片机最小系统+4*4矩阵键盘+LCD1602液晶显示+按键设置+蜂鸣器。1、本设计采用STC89C51/52、AT89C51/52、AT89S51/52作为主控芯片,以LCD1602液晶显示屏显示信息;2、采用4*4矩阵键盘进行人机交互,方便快捷;3、具有比赛加减分,比赛节数设置,比赛时间倒计时,24......
  • 关于在矩阵中枚举点的 dp
    关于在矩阵中枚举点的dpJOISC2018Day1camp简要题意:在矩阵中放一个点,每个点所在的行与列至多有一个别的点,且若有点,两个点的方向要相对,而若无点,则可任意指向四个方向。考虑dp。首先是70......