标题:
求助单片机矩阵按键的问题,已经调试了好多天了,谢谢
[打印本页]
作者:
guanyi12340
时间:
2018-5-2 21:48
标题:
求助单片机矩阵按键的问题,已经调试了好多天了,谢谢
我已经调试了好多天了,因为白天上班,晚上才有时间,但是连续4,5个晚上都发现不了原因,目前已经可以做到加法了,但是我只要一按键,比如按1,按一下马上弹起,就会有N个1出现在8位数码管上,出现多少根据按的时间决定,求好心人帮帮我。。我仿佛是知道因为程序记录了我多次进行了按1的操作,可是我在按键检测的时候用了if(keysta
[j]==0),相当于按键弹起的时候才显示1。我用的两个
74HC573接的8位数码管,DUAN WEI两个IO扣控制锁存器的
,拜谢了。。
拜谢了。。
单片机源程序:
#include<reg52.h>
sbit L0=P1^0; //定义L0-L7小灯IO口
sbit L1=P1^1;
sbit L2=P1^2;
sbit L3=P1^3;
sbit L4=P1^4;
sbit L5=P1^5;
sbit L6=P1^6;
sbit L7=P1^7;
sbit o4=P3^0; //定义矩阵键盘IO口
sbit o1=P3^1;
sbit o2=P3^2;
sbit o3=P3^3;
sbit i1=P3^4;
sbit i2=P3^5;
sbit i3=P3^6;
sbit i4=P3^7;
sbit DUAN=P2^0; //定义段选开关
sbit WEI=P2^1; //定义位选开关
unsigned char ledbuff[8]={ //数码管显示缓冲区
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
unsigned char duanma[]={ //定义单个数码管段位,显示0-F
0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71
};
unsigned char weima[]={ //定义单个数码管位,显示第几个数码管
0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe
};
unsigned char keysta[4][4]={ //定义矩阵按键的当前状态
{1,1,1,1},
{1,1,1,1},
{1,1,1,1},
{1,1,1,1}
};
unsigned char code keycodemap[4][4]={ //矩阵键盘标准键码映射表
{0x31,0x32,0x33,0x26}, //数字键1、数字键2、数字键3、加号
{0x34,0x35,0x36,0x25}, //数字键4、数字键5、数字键6、减号
{0x37,0x38,0x39,0x28}, //数字键7、数字键8、数字键9、乘号
{0x30,0x1b,0x0d,0x27} //数字键0、ESC键、 等号、 除号
};
void keydriver();
unsigned char o=0;
unsigned char cnt=0;
void main()
{
TMOD=0x01; //计时器模式选择为01,16位计时器
TH0=0xfc; //为T0赋初值0xFC67,定时1ms
TL0=0x67;
TR0=1; //打开计时器
EA=1; //打开中断总开关
ET0=1; //打开中断T0
ledbuff[0]=duanma[0];
while(1)
{
keydriver(); //调用按键驱动函数
}
}
void shownumber(unsigned long num) /* 将一个无符号长整型的数字显示到数码管上,num-待显示数字 */
{
signed char i;
unsigned char buf[8];
for(i=0;i<8;i++)
{
buf[i]=num%10;
num=num/10;
}
L1=1;
for(i=7;i>=1;i--) //从最高位起,遇到0转换为空格,遇到非0则退出循环
{
if(buf[i]==0x00)
{
ledbuff[i]=0x00;
}
else
break;
}
for(;i>=0;i--) //剩余低位都如实转换为数码管显示字符
{
ledbuff[i]=duanma[buf[i]];
}
}
void keyaction(unsigned char keycode)
{
static unsigned long result=0; //用于保存运算结果
static unsigned long addend=0; //用于保存输入的加数
if((keycode>=0x30)&&(keycode<=0x39)) //输入0-9的数字
{
addend=(addend*10)+(keycode-0x30); //整体十进制左移,新数字进入个位
shownumber(addend); //运算结果显示到数码管
}
else if(keycode==0x26) //按下加号
{
result+=addend;
addend=0;
shownumber(result);
}
else if(keycode==0x0d) //按下等号
{
result+=addend;
addend=0;
shownumber(result);
}
else if(keycode==0x1b) //按下ESC
{
addend=0;
result=0;
shownumber(addend);
}
}
void keydriver()
{
unsigned char i,j;
unsigned char backup[4][4]={ //按键值备份,保存前一次的值
{1,1,1,1},
{1,1,1,1},
{1,1,1,1},
{1,1,1,1}
};
for(i=0;i<4;i++) //循环检测4*4的矩阵按键
{
for(j=0;j<4;j++)
{
if(keysta[i][j]!=backup[i][j]) //检测按键动作
{ //按键按下时执行动作
if(keysta[i][j]==0)
{
keyaction(keycodemap[i][j]); //调用按键动作函数
}
backup[i][j]=keysta[i][j]; //刷新前一次的备份值
}
}
}
}
void keyscan() //键盘消抖,检测键盘是否按下
{
static unsigned char keyout=0;
unsigned char j;
static unsigned char keybuf[4][4]={
{0xff,0xff,0xff,0xff},
{0xff,0xff,0xff,0xff},
{0xff,0xff,0xff,0xff},
{0xff,0xff,0xff,0xff}
};
keybuf[keyout][0]=(keybuf[keyout][0]<<1)|i1; //消抖功能,对第一列键盘将keybuf[][]赋值为1111 1111或者0000 0000
keybuf[keyout][1]=(keybuf[keyout][1]<<1)|i2;
keybuf[keyout][2]=(keybuf[keyout][2]<<1)|i3;
keybuf[keyout][3]=(keybuf[keyout][3]<<1)|i4;
for(j=0;j<4;j++)
{
if((keybuf[keyout][j])==0x00) //如果keybuf为0000 0000 则视为按下按键
{
keysta[keyout][j]=0;
}
else if((keybuf[keyout][j])==0xff) //如果keybuf为1111 1111 则视为弹起按键
{
keysta[keyout][j]=1;
}
}
switch(keyout) //对键盘进行行扫描
{
case 0:o4=1;o1=0;break;
case 1:o1=1;o2=0;break;
case 2:o2=1;o3=0;break;
case 3:o3=1;o4=0;break;
default:break;
}
keyout++;
keyout=keyout&0x03; //keyout到4清0
}
void ledscan() //键盘显示函数
{
static unsigned char i = 0; //动态扫描的索引
P0 = 0xFF; //显示消隐
switch(i)
{
case 0:
WEI=1;P0=weima[0];WEI=0;DUAN=1;P0=ledbuff[0];i++;DUAN=0;break; //显示个位
case 1:
WEI=1;P0=weima[1];WEI=0;DUAN=1;P0=ledbuff[1];i++;DUAN=0;break; //显示十位
case 2:
WEI=1;P0=weima[2];WEI=0;DUAN=1;P0=ledbuff[2];i++;DUAN=0;break; //显示百位
case 3:
WEI=1;P0=weima[3];WEI=0;DUAN=1;P0=ledbuff[3];i++;DUAN=0;break;
case 4:
WEI=1;P0=weima[4];WEI=0;DUAN=1;P0=ledbuff[4];i++;DUAN=0;break;
case 5:
WEI=1;P0=weima[5];WEI=0;DUAN=1;P0=ledbuff[5];i++;DUAN=0;break;
case 6:
WEI=1;P0=weima[6];WEI=0;DUAN=1;P0=ledbuff[6];i++;DUAN=0;break;
case 7:
WEI=1;P0=weima[7];WEI=0;DUAN=1;P0=ledbuff[7];i++;DUAN=0;break;
default:i=0;break;
}
}
void interrupttimer0() interrupt 1 //定时中断检测键盘,刷新数码管
{
TH0=0xfc;
TL0=0x67;
keyscan(); //调用按键扫描函数
ledscan(); //调用数码管显示扫描函数
}
复制代码
作者:
HC6800-ES-V2.0
时间:
2018-5-3 08:25
根据你所说的:
可是我在按键检测的时候用了if(keysta[j]==0),相当于按键弹起的时候才显示1。
这个是没有用的。
试想:在按键的抖动时,是不是会有很多次的等于零,而你的程序却判断有零就显示,这与没有消抖是一回事嘛。
所以,我的建议是:先消抖,就是延时啊,按下看时10ms左右,松开也延时10ms左右。要先消抖,稳定后才用你的判断是否显示。
这个应该是很基础的了,你不会没有例子吧?!
给你一个:
/*******************************************************************************
* 函 数 名 : KeyDown
* 函数功能 : 检测有按键按下并读取键值
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void KeyDown(void)
{
char a=0;
GPIO_KEY=0x0f;
if(GPIO_KEY!=0x0f)//读取按键是否按下
{
Delay10ms();//延时10ms进行消抖
if(GPIO_KEY!=0x0f)//再次检测键盘是否按下
{
//测试列
GPIO_KEY=0X0F;
switch(GPIO_KEY)
{
case(0X07): KeyValue=0;break;
case(0X0b): KeyValue=1;break;
case(0X0d): KeyValue=2;break;
case(0X0e): KeyValue=3;break;
}
//测试行
GPIO_KEY=0XF0;
switch(GPIO_KEY)
{
case(0X70): KeyValue=KeyValue;break;
case(0Xb0): KeyValue=KeyValue+4;break;
case(0Xd0): KeyValue=KeyValue+8;break;
case(0Xe0): KeyValue=KeyValue+12;break;
}
while((a<50)&&(GPIO_KEY!=0xf0)) //检测按键松手检测
{
Delay10ms();
a++;
}
}
}
}
这个例子程序,会返回按下键的值——从而可以判断按下的是哪个键,你可以再根据返回的键值进行你程序需要的操作,比你的程序好多了,特别是消抖。
作者:
wulin
时间:
2018-5-3 09:12
楼主的按键扫描程序缺少自锁语句,导致长按时重复响应,推荐一款精简的4*4按键扫描程序和按键服务程序参考。
#define value 10 //中断周期1ms 消抖延时 10
unsigned char KeySec=0; //定义键值全局变量
/***********************************************************/
void keyscan() //按键扫描程序(放在1ms中断中)
{
static bit sign=0; //按键自锁标志
static unsigned char count=0;//消抖计数变量
unsigned char num=0; //临时变量
P3=0xf0; //赋值P3 1111 0000
if(P3!=0xf0) //检测有按键按下
{
count++; //消抖计数
if((count>=value)&&(sign==0))
{
sign=1; //按键自锁标志置1,防止长按重复响应
num=P3; //保存P3值xxxx 0000,x为0或1
num|=0x0f; //保存num按位或0x0f值xxxx 1111
P3=num; //赋值P3 xxxx 1111
num=P3; //保存P3值xxxx xxxx
switch(num)
{
case 0xee: KeySec= 1; break;
case 0xde: KeySec= 2; break;
case 0xbe: KeySec= 3; break;
case 0x7e: KeySec= 4; break;
case 0xed: KeySec= 5; break;
case 0xdd: KeySec= 6; break;
case 0xbd: KeySec= 7; break;
case 0x7d: KeySec= 8; break;
case 0xeb: KeySec= 9; break;
case 0xdb: KeySec=10; break;
case 0xbb: KeySec=11; break;
case 0x7b: KeySec=12; break;
case 0xe7: KeySec=13; break;
case 0xd7: KeySec=14; break;
case 0xb7: KeySec=15; break;
case 0x77: KeySec=16; break;
}
}
}
else //按键抬起
{
sign=0; //按键自锁标志清0
count=0; //消抖计数清0
}
}
void key_service() //按键服务程序,放在主循环中
{
switch(KeySec)
{
case 1: //事例1号键触发
//任务1
KeySec=0; //键值清零,避免重复触发
break; //跳出当前程序
case 2: //事例2号键触发
//任务2
KeySec=0; //键值清零,避免重复触发
break; //跳出当前程序
//......
//......
case 16: //事例16号键触发
//任务16
KeySec=0; //键值清零,避免重复触发
break; //跳出当前程序
}
}
作者:
wulin
时间:
2018-5-3 10:16
我用的两个74HC573接的8位数码管,DUAN WEI两个IO扣控制锁存器的
这是用两个74HC573接的8位共阴数码管动态显示程序
void ledscan()//键盘显示函数
{
static unsigned char i=0;//静态变量
P0=0x00; //消隐
DUAN=1;
DUAN=0;
P0=weima
; //位码
WEI=1;
WEI=0;
P0=ledbuff
; //段码
DUAN=1;
DUAN=0;
i++;
if(i>=8)
i=0;
}
作者:
wen-zi
时间:
2018-5-3 12:00
弹起判断应该放在按键执行后
作者:
guanyi12340
时间:
2018-5-3 22:14
谢谢各位大佬了,今天翘班研究这个程序,发现132.void keydriver()函数里面backup[4][4]没有定义静态,前面加个static一下就好了~唉~~~思维啊,思维啊~~板凳哥这个程序我仔细研究了下,确实比我的好多了~~拜谢
作者:
xiaoyu.
时间:
2018-5-18 15:19
51单片机独立按键
#include<reg52.h>
#define uint unsigned int
#define uchar unsigned char
sbit dula=P2^6;
sbit wela=P2^7;
sbit K1=P3^4;
sbit K2=P3^5;
sbit K3=P3^6;
sbit K4=P3^7;
uchar code table[]={
0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71};
uint aa;
uchar num1,num2,shi1,ge1,shi2,ge2;
void delay(uint z)
{
uint x,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}
void display(uchar num1,uchar num2)
{
shi1=num1/10;
ge1=num1%10;
shi2=num2/10;
ge2=num2%10;
dula=1;
P0=table[shi1];
dula=0;
P0=0xff;
wela=1;
P0=0xfe;
wela=0;
delay(1);
dula=1;
P0=table[ge1];
dula=0;
P0=0xff;
wela=1;
P0=0xfd;
wela=0;
delay(1);
dula=1;
P0=table[shi2];
dula=0;
P0=0xff;
wela=1;
P0=0xfb;
wela=0;
delay(1);
dula=1;
P0=table[ge2];
dula=0;
P0=0xff;
wela=1;
P0=0xf7;
wela=0;
delay(1);
}
void key()
{
if(K1==0)
{
delay(5);
if(K1==0)
{
TR0=0;
while(!K1);
}
}
if(K2==0)
{
delay(5);
if(K2==0)
{
if(num1==0)
{
num1=60;
}
num1--;
while(!K2);
}
}
if(K3==0)
{
delay(5);
if(K3==0)
{
num1++;
if(num1>=60)
{
num1=num1-60;
}
while(!K3);
}
}
if(K4==0)
{
delay(5);
if(K4==0)
{
TR0=1;
while(!K4);
}
}
}
void inint()
{
TMOD=0x01;
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;
EA=1;
ET0=1;
TR0=1;
}
void main()
{
inint();
while(1)
{
key();
display(num1,num2);
}
}
void zhongduan()interrupt 1
{
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;
aa++;
if(aa==20)
{
aa=0;
num2++;
if(num2==60)
{
num2=0;
num1++;
if(num1==60)
num1=0;
}
}
}
欢迎光临 (http://www.51hei.com/bbs/)
Powered by Discuz! X3.1