C51单片机用IO口做为几个按键的控制,现在想用4X4键盘控制,请问下面显示程序应该怎么改啊?折磨死了

下面的程序 是用4个键来控制12864的菜单上下选择并确认,这种方法很简单,只要判断高低状态就可以了,但是现在想用4*4的矩阵键盘来控制,。矩阵键盘接在P2口上。矩阵键盘是通过定时器中断来获得键值的。原来的程序如下,请问各位大侠们怎么改啊。急啊!!!

while(ok) //OK为P1.1口,控制确认键
{
if(up==0) //up=P1.2,向上
{
select--;
if(select==-1)
select=3;
while(!up);//等待松手
}
if(down==0) //up=P1.2,向上
{
select++;
if(select==4)
select=0;
while(!down);//等待松手
}
menu_page(select);//反白选择
while(ok&up&down); //如果没有按键则等待
}
while(!ok); //等待松手
switch(select)
{
case 0: set_temp();break;//设置温度
case 1: set_humi();break;//设置湿度
case 2: set_temp2();break;//设置土温
case 3: set_humi2();break;//设置土湿
default:break;
}
delay
我改了一下程序,大概实现了用矩阵键盘控制液晶菜单,但现在还有个问题,就是在等待松手的时候我得按两次才能转到下一项菜单,第一次是退出等待的循环,第二次才是正常进入菜单,请问这个问题怎么处理呢。
if(key==0xee) //为向上按键
{
select--;
if(select==-1)
select=3;
while((P2&0xf0)!=0xf0); //等待松手,我感觉就是这里有问题,我得按两次才能转到下一项菜
单,第一次是退出等待的循环,
第二次才是正常进入菜单,请问这个问题怎么处理呢。
}
if(key==0xde)//为向上按键
{ // key_flag=0;
select++;
if(select==4)
select=0;
while((P2&0xf0)!=0xf0);//等待松手,这里也是同样问题
}

4X4太浪费单片机IO了,我为你介绍5个IO控制25按键的电路,如下文:

本文以循序渐进的思路,引导大家思考如何用最少的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个。

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

温馨提示:答案为网友推荐,仅供参考
第1个回答  推荐于2016-05-02
// 4*4矩阵键盘
/********************************************************
连接:
------------------------------------
P1.0 P1.1 P1.2 P1.3
p1.4 S1 S5 S9 S13
P1.5 S2 S6 S10 S14
P1.6 S3 S7 S11 S15
P1.7 S4 S8 S12 S16
------------------------------------
实现原理:
当高电平端口与低电平端口短接时,高电平端口会被拉成低电平
------------------------
算法分析:
1,检查是否有键按下:
P1=f0h (即0-3置1,4-7置0)
检查P1口是否是0F0H
是,则无键按下
否,则有键按下
2,扫描按下的键值:
循环(依次将4至7口单独置0)
检查0-3口是否有低电平端
确定被按下的键
返回键值
3,键盘防抖:
抖动原因:键按下时,会产生电压的波动,持续约10MS
去抖方法:10MS扫描一次,使前后两次均有键按下
********************************************************/
#include<ytc51.h>
uchar jps,ks; //键盘缓存
/*键盘扫描程序1,检查是否有按键*/
uchar keyfun()
{
uchar key_c;
P2 = P2 & 0x03;
P2 = P2 | 0x3c;
key_c = P2;
if((key_c & 0xfc) == 0x3c) return (0);
else return(1);
}
/*键盘扫描程序2,确定按键数值*/
uchar keyscan()
{
uchar i,k;
P2 = P2 & 0x03;
P2 = P2 | 0xbc;
if((P2 & 0x3c) != 0x3c)
{
i = 0;
k = (~P2) & 0x3c;
}
else
{
P2 = P2 & 0x03;
P2 = P2 | 0x7c;
if((P2 & 0x3c) != 0x3c)
{
i = 1;
k = (~P2) & 0x3c;
}
}
k = k>>3;
if( k==4 ) k=3;
k=i*4+k+1;
return(k);
}
/**********************************************************************
函数功能: 定时器中断函数(扫描键盘)(10ms 16位定时)
入口参数: 无
出口参数: 无
***********************************************************************/
void Time0_Func() interrupt 3 /*当定时器中断时执行此函数*/
{
TH1=(0xffff-9259)/256; /*T0初始化*/
TL1=(0xffff-9259)%256;
WR = 1;
if((ks == 0) && ( keyfun() ))
{
jps = keyscan();
}
ks = keyfun();
}

/**********************************************************************
函数功能: 上电初始化函数
入口参数: 无
出口参数: 无
***********************************************************************/
void Power_Up(void)
{
TMOD = 0x10;/*Time0/1为16计数器*/
TH1=(0xffff-9216)/256;/*10ms*/
TL1=(0xffff-9216)%256;/*10ms*/
TR1=1;
SCON = 0x00;//串口工作模式设置
IE=0x88; /*EA=1 ET1=1*/
P0=0xff;
P2=0xff;
}追问

这些东西我都 有,现在就是实现不了我那个用IO口控制上下选择并按确定进入的功能。

本回答被提问者采纳
相似回答