历史上的今天
今天是:2024年12月23日(星期一)
2021年12月23日 | 51单片机系列学习——逐行扫描的方式实现矩阵按键的仿真
2021-12-23 来源:eefocus
小编今天原本想用proteus7.8做个计算器显示的仿真,结果被矩阵按键这块整好长时间。秃头秃头!!!
某站上普中科技的教学视频里的“矩阵按键”采用的是行列式的扫描方式实现确定按键位置的。但我用那个程序仿真没整出来。分析修改程序等等,弄了好久没整出来。于是我换了一种方式,用视频里介绍的**“逐行扫描”**的方式弄了一下,整出来了!!,先把我的实验过程分享给大家,在来谈谈我的理解。
仿真图如下:

计算器在proteus7.8中搜“KEYPAD”即可
代码如下:
#include #include #define uchar unsigned char #define uint unsigned int #define GPIO_DIG P0 #define GPIO_KEY P1 uchar KeyValue;//设一个最后的传递值(给P0的) void delay(uint x){//简单的延时函数 while(x--); } //采用逐行扫描的方式: //低四位轮流输出低电平来对矩阵键盘进行逐行扫描, //(1)当高四位接收到的数据不全为1的时候,说明有按键按下,然后通过接收到的数据是哪一位为0来判断是哪一个按键被按下。 /******************************************************************************* * 函 数 名 : KeyDown() * 函数功能 : 矩阵按键的扫描,确定按下哪个键 * 输 入 : 无 * 输 出 : 无 *******************************************************************************/ void KeyDown(void){ if((GPIO_KEY&0xf0)!=0xf0){//读取是否有按键按下,符合(1)的说明;补充:P1.0——P1.3是低四位,行表示 KeyValue=~(0xf0|GPIO_KEY); //这步很关键,得到KeyValue(P0)低四位数据,P0.0~P0.3亮的含义:分别表示是第一行到——第四行的某行亮 switch((GPIO_KEY&0xf0)){ //这个'|'要有 case(0X70): KeyValue|=0x10;break; //'4'行 case(0Xb0): KeyValue|=0x20;break; //'3'行 case(0Xd0): KeyValue|=0x40;break; //'2'行 case(0Xe0): KeyValue|=0x80;break; //'1'行 } } else{GPIO_KEY=_crol_(GPIO_KEY,1); } //如果高四位是为1,到下一行去判断 if(GPIO_KEY==0xef){GPIO_KEY=0xfe;} //这句很重要!!!,判断第四次移位是否完成:若低电平移到第五位P1.4,则返回P1.0重新轮询扫描!!! } void main(){ uchar i; GPIO_KEY=0xfe; //设一个行的轮询的初始值,从第一行开始 while(1){ //死循环,不断的查询中 for(i=0;i<4;i++){ //完成一整次轮询 KeyDown(); //调用按键判断函数 delay(1000); GPIO_DIG=KeyValue; //得到按键所在行列的信息 } GPIO_KEY=0xfe; //再赋值准备下次轮询 i=0;//清零,为下次轮询准备 } } 这个程序实现的结果是:随意按计算器上的一个键,通过发光二极管显示出这个键在哪行哪列。P0.0—P0.3分别表示第一行至第四行;P0.4—P0.7分别表示第一列至第四列 下面是按下*按键的显示结果图: 总结:这种“逐行扫描”相当于不间断的扫描每行,监听不同列的变化,若某列发生变化,则将行和列的变化信息返回给P1口,判断后得出结果。 问题分析: 为什么普中的“行列扫描”方式仿真的时候不行呢? 我想应该是按键按下时低电平的时间太短的问题。“行列扫描”方式要求按键按下时的低电平要有一段时间的保持,这样在P1口高低位互调时才能发挥想要的效果。 而仿真中计算器的按键按下去后低电平的时间很短,根本不够这种时间的转换,可能换成16个独立组合的行吧。我下面写了个“行列扫描”的程序验证了我这个想法 仿真图还是原来那个不变,但“行列扫描”的代码如下 #include #define uchar unsigned char #define uint unsigned int #define GPIO_DIG P0 #define GPIO_KEY P1 uchar KeyValue; void delay(uint x){ while(x--); } void KeyDown(void) { GPIO_KEY=0x0f; if(GPIO_KEY!=0x0f)//读取按键是否按下 { //测试行 switch(GPIO_KEY) { case(0X07): KeyValue=0x01;break; case(0X0b): KeyValue=0x02;break; case(0X0d): KeyValue=0x04;break; case(0X0e): KeyValue=0x08;break; } //测试列 GPIO_KEY=0Xf0; //这时候应该还在按下的状态 while((GPIO_KEY==0xf0)==1); //检测按键松手检测 if(GPIO_KEY!=0xf0){ switch(GPIO_KEY) { case(0X70): KeyValue|=0x10;break; case(0Xb0): KeyValue|=0x20;break; case(0Xd0): KeyValue|=0x40;break; case(0Xe0): KeyValue|=0x80;break; } } while(GPIO_KEY!=0xf0); } } void main() { while(1) { KeyDown(); //按键判断函数 delay(10000); GPIO_DIG=KeyValue; // } } 这个行列扫描最后做出的结果是一个按键要按下两次才能在发光二极管处显示出他的位置信息。在仿真中列是P0.4—P0.7,行是P0.0—P0.3 
史海拾趣
|
该例用于令与PORTD口相连的8个发光二极管前4个点亮,后4个熄灭。在调试程序前,应使与PORTD口相连的8位拔码开关拔向相应的位置。 PORTD输出 #include <pic.h> main() { ...… 查看全部问答> |
|
晶体管脉冲数字电路 上册 323 页 4.5M 格式:PDF 目录: 第一部分 分立元件脉冲数字电路 第一章 基础知识 第二章 门电路——脉冲信号的控制 第三章 双稳态触发器——脉冲信号的记忆 第四章 脉冲信号的产生于整形 第五章 脉冲信号的功率 ...… 查看全部问答> |
|
看好您的watchdog 当系统处于一些比较的恶劣环境工控底层采集如果系统的抗干扰没有作好则容易出现死机现象这时硬件电路并没有损坏只是内部程序运行出现错误必须复位才能恢复如果是洗衣机或随身听中的单片机出现死机那么重新开机一次就可以了影响不 ...… 查看全部问答> |
|
网络化存储之中心存储 在网络视频监控系统中,部署得更多的是中心存储。前端设备采集监控点图像并编码压缩处理成数字监控码流,然后通过网络传送到中心业务平台,由中心业务平台将码流分发给网络录像单元进行集中存储。 在很多大型的视频监控联网应 ...… 查看全部问答> |
|
CLK_ICKR=0x08; /* Configure clock prescaler */ CLK_CKDIVR = 0x01; /*分频时钟源 */ /* To select external source by automtic switch */ CLK_ICKR |= 0x10; /* 使能转化 */ CLK_SWR = 0xD2; /* 时 ...… 查看全部问答> |




