单片机汇编矩阵键盘实验(扫描法)

单片机汇编矩阵键盘实验(扫描法),第1张

关于扫描按键的原理,可以看下面这篇文章。

本文以循序渐进的思路,引导大家思考如何用最少的IO驱动更多的按键,并依次给出5种方案原理图提供参考。在实际项目中我们经常会遇到有按键输入的需求,但有的时候为了节省资源成本,我们都会选择在不增加硬件的情况下使用最少的控制器IO驱动更多的按键,那么具体是怎么做的呢,下面我们就以用5个IO引脚为例,讲下怎么设计可以实现更多的按键?共有5种设计思路,下面依次介绍。

思路一

首先通常想到的可能是下面这样的设计:

上图形式的按键就是我们通常说的行列式按键,它的驱动思路是这样的:

1. 对IO1、2、3配置为推挽输出,依次只让其中一个输出为0其他输出为1。

2. 对IO4、5进行读 *** 作,根据读出的结果判断哪个按键按下

例如:配置IO1、2、3为011,读IO4、5,若IO4为0则SW14按下,若IO5为0则SW15按下;

依次的配置IO1、2、3为101,读IO4、5,若IO4为0则SW24按下,若IO5为0则SW25按下;

依次的配置IO1、2、3为110,读IO4、5,若IO4为0则SW34按下,若IO5为0则SW35按下;

思路二

但是我们在不知道行列式按键之前我们肯定是依次将IO口接一个按键到GND或者到VCC,然后去读IO口去判断哪个按键按下,这也是最简单的方法,但是很浪费IO口,下面这种就结合了这种简单方法和行列式的思路,实现了又多增加3个按键,如下图:

这里我们的思路是先依次读IO1、2、3的电平来识别S1、2、3,哪个按键按下,其后的流程和思路一是一样的,这样就可以识别11个按键了。

思路三

按照扫描的思想,某一时刻设置一个IO口为0,其他IO口读,如果有IO口读到0,则有对应按键按下。比如IO1为0,然后读到IO5也为0,那么K15就是按下的。对照这样的思路,我们可以有下面的设计:

这个电路按键识别思路是这样的:

1. 只配置IO1为0,其他IO读,若IO5读到0,则K15按下,若IO4读到0,则K14按下,依次识别K13,K12;

2. 只配置IO2为0,其他IO读,若IO5读到0,则K25按下,若IO4读到0,则K24按下,依次识别K23;

3. 只配置IO3为0,其他IO读,若IO5读到0,则K35按下,若IO4读到0,则K34按下;

4. 只配置IO4为0,其他IO读,若IO5读到0,则K45按下;

思路四

对于思路3我们发现,如果只配置IO5为0,其他IO读,若IO1读到0,则K15按下,若IO2读到0,则K25按下,依次可识别K35和K45。这样就存在重复,那么有么有好的方法,解决这样的重复呢?我们发现,若配置IO1为0,K15按下,电流流向IO1的,若配置IO5为0,同样K15按下,电流是流向IO5的。这样我们就可以通过区分电流的流向来避免重复。于是就有了下图的设计:

这样就可以避免重复,IO5为0时,按K15,IO1是读不到0的。那么怎样设计,IO5为0时对应一个按键按下IO1为0呢?如是就有人想到下面的设计:

这个电路按键识别思路是这样的:

1. 只配置IO1为0,其他IO读,若IO5读到0,则K51按下,若IO4读到0,则K41按下,依次识别K31,K21;

2. 只配置IO2为0,其他IO读,若IO5读到0,则K52按下,若IO4读到0,则K42按下,依次识别K32,K21';

3. 只配置IO3为0,其他IO读,若IO5读到0,则K53按下,若IO4读到0,则K43按下,依次识别K32’,K31';

4. 只配置IO4为0,其他IO读,若IO5读到0,则K54按下,若IO4读到0,则K43’按下,依次识别K42’,K41';

5. 只配置IO5为0,其他IO读,若IO4读到0,则K54’按下,若IO3读到0,则K53’按下,依次识别K52’,K51'。

思路五

很多人可能认为思路四已经识别20个按键了,但是真的就没有其他方法了吗?不要忘了,我们还没有将思路二你介绍的那种最简单的方法结合进去,于是又可以多5个按键,如下图:

这样我们可以先识别K01、K02、K03、K04、K05,若没有按键按下然后再和思路四的设计一样去识别其他按键。但这样存在一个问题,如果IO1配置为0,IO5读到0,那么怎么知道是K51按下还是K05按下呢,这里只需要在程序里做下判断,先判断下是不是K05按下,若不是就是K51,因为按键K01、K02、K03、K04、K05在5个IO口都为读取的情况下,就可以识别,不需要扫描识别处理,相当于这5个按键优先级高与其他按键。

总结

综合上述,5个IO口最多可以识别25个按键,思路五程序上处理比较麻烦,若实际中只按思路四设计,也可识别20个按键,那么如果有N个IO口可识别多少按键呢?这里给出如下公式:

假设有N个IO口按照思路三可以识别N*(N-1)/2个;

按照思路四可识别N*(N-1)个;

按照思路5可以识别N*(N-1)+N个。

最后再说下,如果实际设计时,还是按思路四设计好,软件也没那么麻烦。如果是你的话你会选择哪种方法呢?你还有没有其他的设计方法呢?

代码很好写,但是关键是你的数码管属于硬件

也就是说,至少要知道 *** 作你数码管的API才行啊。

或者说要怎样传送数据给你的数码管,你的数码管需要接受怎样的数据。

键盘扫描很简单,给你个代码。

要求引用头文件

#include <iostream>

using namespace std

#include <conio.h>//kbhit API头文件

#include <time.h>

#include <windows.h>

#define ESC 0x1b

void loop()

{

int i

if( kbhit() ) //判断是否有键盘按键按下。

{

char ch

ch = getch() //获取按下的键值

if( ESC == ch )//判断是否是你要的键,我以ESC为例

{

cout<<"ESC"<<endl

system("pause")

}

}

while( !kbhit() )//没有按键是的 *** 作

{

balabalabala.......

}

}

int main()

{

loop()

}

我这有个AVR的矩阵键盘的识别程序、其中PORTA就相当于51里的P0一样的端口的表示、PINA也是指的PORTA口、和PORTA的区别是PINA只能读!其他都一样的和51

/********************************************************

实验七: 矩阵式键盘实验

说明: 按按键K1-K16 数码管显示0-F的键码

注意: K17-K19为独立按键,使用这个程序是没有反应的

CPU型号: ATMEGA128A

晶振频率: 8MHZ

日期:2011-3-12

联系方法: MCU.2000@163.com

********************************************************/

#include <iom128v.h>

#include <macros.h>

#define uchar unsigned char

#define uint unsigned int

void Delayus(uint US) //微秒延时子程序

void Delayms(uint MS) //毫秒延时子程序

uchar key_scan(void)

void init_io(void)

//共阳数码管数字码

uchar led_discode[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,

0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e,0xff}

uchar key_val=0

//主函数

void main (viod)

{

uchar key_io

init_io()

while(1)

{

PORTD=0XF0

Delayms(5)

key_io=PIND &0xf0

if(key_io !=0xf0)

{

PORTD=0XF0

Delayms(1)

key_io=PIND &0xf0

if(key_io !=0xf0)

{

key_val=key_scan()

key_val |= key_io

}

switch(key_val)

{

case 0xee: key_val=0x00 break//按键K1

case 0xde: key_val=0x01 break//按键K2

case 0xbe: key_val=0x02 break//按键K3

case 0x7e: key_val=0x03 break//按键K4

case 0xed: key_val=0x04 break//按键K5

case 0xdd: key_val=0x05 break//按键K6

case 0xbd: key_val=0x06 break//按键K7

case 0x7d: key_val=0x07 break//按键K8

case 0xeb: key_val=0x08 break//按键K9

case 0xdb: key_val=0x09 break//按键K10

case 0xbb: key_val=0x0a break//按键K11

case 0x7b: key_val=0x0b break//按键K12

case 0xe7: key_val=0x0c break//按键K13

case 0xd7: key_val=0x0d break//按键K14

case 0xb7: key_val=0x0e break//按键K15

case 0x77: key_val=0x0f break //按键K16

} // switch(key_val)

} // if(key_io !=0xf0)

PORTD=0XF0

//等待松开按键

key_io=PIND &0xf0

while(key_io !=0xf0)

{

key_io=PIND &0xf0

}

PORTC=led_discode[key_val]//显示按键码

}// while(1)

}

void init_io(void)

{

DDRA=0XFF;//设置A口味输出

PORTA=0XFF

DDRB=0XFf;//设置B口味输出

PORTB=0XFF //数码管位控制

DDRC=0XFF //数码管段控制

PORTC=0X00

DDRD=0X0F //键盘接口

PORTD=0XF0

DDRF=0X0E

PORTF=0X0E

PORTF&=0XF7//锁存关闭LED显示

DDRB |=0X10 //PB4设为输出

PORTB|=0X10 //关闭PB4外接的LED

}

uchar key_scan(void)

{

uchar m,temp=0xf7

for(m=0m<4m++)

{

PORTD=temp | 0xf0

Delayms(1)

if((PIND &0XF0)!=0XF0)

return(temp &0x0f)

temp>>=1

}

}

/****************************************************

函数名称: Delayus

功能: 延时指定微秒(8M晶振)

参数: US--延时的微秒数(大约,不是很精确,MS越大越准确)

返回值 : 无

/****************************************************/

void Delayus(uint US)

{

uint i

US=US*5/4

for( i=0i<USi++)

}

/****************************************************

函数名称: Delayms

功能: 延时指定毫秒(8M晶振)

参数: MS--延时的毫秒数

返回值 : 无

通过软件仿真反复实验得到的数值

/****************************************************/

void Delayms(uint MS)

{

uint i,j

for( i=0i<MSi++)

for(j=0j<1141j++)

}


欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/yw/11788762.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-05-18
下一篇2023-05-18

发表评论

登录后才能评论

评论列表(0条)

    保存