標(biāo)題:
求助單片機(jī)矩陣按鍵的問(wèn)題,已經(jīng)調(diào)試了好多天了,謝謝
[打印本頁(yè)]
作者:
guanyi12340
時(shí)間:
2018-5-2 21:48
標(biāo)題:
求助單片機(jī)矩陣按鍵的問(wèn)題,已經(jīng)調(diào)試了好多天了,謝謝
我已經(jīng)調(diào)試了好多天了,因?yàn)榘滋焐习啵砩喜庞袝r(shí)間,但是連續(xù)4,5個(gè)晚上都發(fā)現(xiàn)不了原因,目前已經(jīng)可以做到加法了,但是我只要一按鍵,比如按1,按一下馬上彈起,就會(huì)有N個(gè)1出現(xiàn)在8位數(shù)碼管上,出現(xiàn)多少根據(jù)按的時(shí)間決定,求好心人幫幫我。。我仿佛是知道因?yàn)槌绦蛴涗浟宋叶啻芜M(jìn)行了按1的操作,可是我在按鍵檢測(cè)的時(shí)候用了if(keysta
[j]==0),相當(dāng)于按鍵彈起的時(shí)候才顯示1。我用的兩個(gè)
74HC573接的8位數(shù)碼管,DUAN WEI兩個(gè)IO扣控制鎖存器的
,拜謝了。。
拜謝了。。
單片機(jī)源程序:
#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; //定義段選開(kāi)關(guān)
sbit WEI=P2^1; //定義位選開(kāi)關(guān)
unsigned char ledbuff[8]={ //數(shù)碼管顯示緩沖區(qū)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
unsigned char duanma[]={ //定義單個(gè)數(shù)碼管段位,顯示0-F
0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71
};
unsigned char weima[]={ //定義單個(gè)數(shù)碼管位,顯示第幾個(gè)數(shù)碼管
0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe
};
unsigned char keysta[4][4]={ //定義矩陣按鍵的當(dāng)前狀態(tài)
{1,1,1,1},
{1,1,1,1},
{1,1,1,1},
{1,1,1,1}
};
unsigned char code keycodemap[4][4]={ //矩陣鍵盤標(biāo)準(zhǔn)鍵碼映射表
{0x31,0x32,0x33,0x26}, //數(shù)字鍵1、數(shù)字鍵2、數(shù)字鍵3、加號(hào)
{0x34,0x35,0x36,0x25}, //數(shù)字鍵4、數(shù)字鍵5、數(shù)字鍵6、減號(hào)
{0x37,0x38,0x39,0x28}, //數(shù)字鍵7、數(shù)字鍵8、數(shù)字鍵9、乘號(hào)
{0x30,0x1b,0x0d,0x27} //數(shù)字鍵0、ESC鍵、 等號(hào)、 除號(hào)
};
void keydriver();
unsigned char o=0;
unsigned char cnt=0;
void main()
{
TMOD=0x01; //計(jì)時(shí)器模式選擇為01,16位計(jì)時(shí)器
TH0=0xfc; //為T0賦初值0xFC67,定時(shí)1ms
TL0=0x67;
TR0=1; //打開(kāi)計(jì)時(shí)器
EA=1; //打開(kāi)中斷總開(kāi)關(guān)
ET0=1; //打開(kāi)中斷T0
ledbuff[0]=duanma[0];
while(1)
{
keydriver(); //調(diào)用按鍵驅(qū)動(dòng)函數(shù)
}
}
void shownumber(unsigned long num) /* 將一個(gè)無(wú)符號(hào)長(zhǎng)整型的數(shù)字顯示到數(shù)碼管上,num-待顯示數(shù)字 */
{
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轉(zhuǎn)換為空格,遇到非0則退出循環(huán)
{
if(buf[i]==0x00)
{
ledbuff[i]=0x00;
}
else
break;
}
for(;i>=0;i--) //剩余低位都如實(shí)轉(zhuǎn)換為數(shù)碼管顯示字符
{
ledbuff[i]=duanma[buf[i]];
}
}
void keyaction(unsigned char keycode)
{
static unsigned long result=0; //用于保存運(yùn)算結(jié)果
static unsigned long addend=0; //用于保存輸入的加數(shù)
if((keycode>=0x30)&&(keycode<=0x39)) //輸入0-9的數(shù)字
{
addend=(addend*10)+(keycode-0x30); //整體十進(jìn)制左移,新數(shù)字進(jìn)入個(gè)位
shownumber(addend); //運(yùn)算結(jié)果顯示到數(shù)碼管
}
else if(keycode==0x26) //按下加號(hào)
{
result+=addend;
addend=0;
shownumber(result);
}
else if(keycode==0x0d) //按下等號(hào)
{
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++) //循環(huán)檢測(cè)4*4的矩陣按鍵
{
for(j=0;j<4;j++)
{
if(keysta[i][j]!=backup[i][j]) //檢測(cè)按鍵動(dòng)作
{ //按鍵按下時(shí)執(zhí)行動(dòng)作
if(keysta[i][j]==0)
{
keyaction(keycodemap[i][j]); //調(diào)用按鍵動(dòng)作函數(shù)
}
backup[i][j]=keysta[i][j]; //刷新前一次的備份值
}
}
}
}
void keyscan() //鍵盤消抖,檢測(cè)鍵盤是否按下
{
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; //消抖功能,對(duì)第一列鍵盤將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) //對(duì)鍵盤進(jìn)行行掃描
{
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() //鍵盤顯示函數(shù)
{
static unsigned char i = 0; //動(dòng)態(tài)掃描的索引
P0 = 0xFF; //顯示消隱
switch(i)
{
case 0:
WEI=1;P0=weima[0];WEI=0;DUAN=1;P0=ledbuff[0];i++;DUAN=0;break; //顯示個(gè)位
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 //定時(shí)中斷檢測(cè)鍵盤,刷新數(shù)碼管
{
TH0=0xfc;
TL0=0x67;
keyscan(); //調(diào)用按鍵掃描函數(shù)
ledscan(); //調(diào)用數(shù)碼管顯示掃描函數(shù)
}
復(fù)制代碼
作者:
HC6800-ES-V2.0
時(shí)間:
2018-5-3 08:25
根據(jù)你所說(shuō)的:
可是我在按鍵檢測(cè)的時(shí)候用了if(keysta[j]==0),相當(dāng)于按鍵彈起的時(shí)候才顯示1。
這個(gè)是沒(méi)有用的。
試想:在按鍵的抖動(dòng)時(shí),是不是會(huì)有很多次的等于零,而你的程序卻判斷有零就顯示,這與沒(méi)有消抖是一回事嘛。
所以,我的建議是:先消抖,就是延時(shí)啊,按下看時(shí)10ms左右,松開(kāi)也延時(shí)10ms左右。要先消抖,穩(wěn)定后才用你的判斷是否顯示。
這個(gè)應(yīng)該是很基礎(chǔ)的了,你不會(huì)沒(méi)有例子吧?!
給你一個(gè):
/*******************************************************************************
* 函 數(shù) 名 : KeyDown
* 函數(shù)功能 : 檢測(cè)有按鍵按下并讀取鍵值
* 輸 入 : 無(wú)
* 輸 出 : 無(wú)
*******************************************************************************/
void KeyDown(void)
{
char a=0;
GPIO_KEY=0x0f;
if(GPIO_KEY!=0x0f)//讀取按鍵是否按下
{
Delay10ms();//延時(shí)10ms進(jìn)行消抖
if(GPIO_KEY!=0x0f)//再次檢測(cè)鍵盤是否按下
{
//測(cè)試列
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;
}
//測(cè)試行
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)) //檢測(cè)按鍵松手檢測(cè)
{
Delay10ms();
a++;
}
}
}
}
這個(gè)例子程序,會(huì)返回按下鍵的值——從而可以判斷按下的是哪個(gè)鍵,你可以再根據(jù)返回的鍵值進(jìn)行你程序需要的操作,比你的程序好多了,特別是消抖。
作者:
wulin
時(shí)間:
2018-5-3 09:12
樓主的按鍵掃描程序缺少自鎖語(yǔ)句,導(dǎo)致長(zhǎng)按時(shí)重復(fù)響應(yīng),推薦一款精簡(jiǎn)的4*4按鍵掃描程序和按鍵服務(wù)程序參考。
#define value 10 //中斷周期1ms 消抖延時(shí) 10
unsigned char KeySec=0; //定義鍵值全局變量
/***********************************************************/
void keyscan() //按鍵掃描程序(放在1ms中斷中)
{
static bit sign=0; //按鍵自鎖標(biāo)志
static unsigned char count=0;//消抖計(jì)數(shù)變量
unsigned char num=0; //臨時(shí)變量
P3=0xf0; //賦值P3 1111 0000
if(P3!=0xf0) //檢測(cè)有按鍵按下
{
count++; //消抖計(jì)數(shù)
if((count>=value)&&(sign==0))
{
sign=1; //按鍵自鎖標(biāo)志置1,防止長(zhǎng)按重復(fù)響應(yīng)
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; //按鍵自鎖標(biāo)志清0
count=0; //消抖計(jì)數(shù)清0
}
}
void key_service() //按鍵服務(wù)程序,放在主循環(huán)中
{
switch(KeySec)
{
case 1: //事例1號(hào)鍵觸發(fā)
//任務(wù)1
KeySec=0; //鍵值清零,避免重復(fù)觸發(fā)
break; //跳出當(dāng)前程序
case 2: //事例2號(hào)鍵觸發(fā)
//任務(wù)2
KeySec=0; //鍵值清零,避免重復(fù)觸發(fā)
break; //跳出當(dāng)前程序
//......
//......
case 16: //事例16號(hào)鍵觸發(fā)
//任務(wù)16
KeySec=0; //鍵值清零,避免重復(fù)觸發(fā)
break; //跳出當(dāng)前程序
}
}
作者:
wulin
時(shí)間:
2018-5-3 10:16
我用的兩個(gè)74HC573接的8位數(shù)碼管,DUAN WEI兩個(gè)IO扣控制鎖存器的
這是用兩個(gè)74HC573接的8位共陰數(shù)碼管動(dòng)態(tài)顯示程序
void ledscan()//鍵盤顯示函數(shù)
{
static unsigned char i=0;//靜態(tài)變量
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
時(shí)間:
2018-5-3 12:00
彈起判斷應(yīng)該放在按鍵執(zhí)行后
作者:
guanyi12340
時(shí)間:
2018-5-3 22:14
謝謝各位大佬了,今天翹班研究這個(gè)程序,發(fā)現(xiàn)132.void keydriver()函數(shù)里面backup[4][4]沒(méi)有定義靜態(tài),前面加個(gè)static一下就好了~唉~~~思維啊,思維啊~~板凳哥這個(gè)程序我仔細(xì)研究了下,確實(shí)比我的好多了~~拜謝
作者:
xiaoyu.
時(shí)間:
2018-5-18 15:19
51單片機(jī)獨(dú)立按鍵
#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.torrancerestoration.com/bbs/)
Powered by Discuz! X3.1