⑴ 單片機匯編矩陣鍵盤實驗(掃描法)
關於掃描按鍵的原理,可以看下面這篇文章。
本文以循序漸進的思路,引導大家思考如何用最少的IO驅動更多的按鍵,並依次給出5種方案原理圖提供參考。在實際項目中我們經常會遇到有按鍵輸入的需求,但有的時候為了節省資源成本,我們都會選擇在不增加硬體的情況下使用最少的控制器IO驅動更多的按鍵,那麼具體是怎麼做的呢,下面我們就以用5個IO引腳為例,講下怎麼設計可以實現更多的按鍵?共有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個。
最後再說下,如果實際設計時,還是按思路四設計好,軟體也沒那麼麻煩。如果是你的話你會選擇哪種方法呢?你還有沒有其他的設計方法呢?
⑵ C51 4*4鍵盤掃描程序(c語言)
|代碼
字元
代碼
字元
代碼
字元
代碼
字元
代碼
字元
32
52
4
72
H
92
\
112
p
33
!
53
5
73
I
93
]
113
q
34
」
54
6
74
J
94
^
114
r
35
#
55
7
75
K
95
_
115
s
36
$
56
8
76
L
96
`
116
t
37
%
57
9
77
M
97
a
117
u
38
&
58
:
78
N
98
b
118
v
39
』
59
;
79
O
99
c
119
w
40
(
60
<
80
P
100
d
120
x
41
)
61
=
81
Q
101
e
121
y
42
*
62
>
82
R
102
f
122
z
43
+
63
?
83
S
103
g
123
{
44
,
64
@
84
T
104
h
124
|
45
-
65
A
85
U
105
i
125
}
46
.
66
B
86
V
106
j
126
~版
47
/
67
C
87
W
107
k
48
0
68
D
88
X
108
l
49
1
69
E
89
Y
109
m
50
2
70
F
90
Z
110
n
51
3
71
G
91
[
111
o
對照相應的ASCII碼輸出權就可以了
⑶ 鍵盤掃描程序的調試方法是什麼
逐行掃描法。改進後鍵盤掃描 接下來我們介紹一種代碼效率極高的鍵盤掃描方法。鍵盤介面電路同樣採用獨立式,假設有8個按鍵,所有按鍵公共端接地,鍵盤掃描口為P0.7~P0.0。
⑷ 急求一個由89C51單片機的代碼!要求用4*4矩陣鍵盤控制LED矩陣輸出0~9的數字!
/*
分別按下4×4鍵盤的按鍵,顯示0~16鍵值
*/
#include<reg51.h>
sbit speaker=P3^;
/////////////////鍵盤
sbit v1=P2^0;
sbit v2=P2^1;
sbit v3=P2^2;
sbit v4=P2^3;
sbit h1=P2^4;
sbit h2=P2^5;
sbit h3=P2^6;
sbit h4=P2^7;
/////////////////顯示
sbit shu1=P1^3;/*第1位數碼管共陰端*/
sbit shu2=P1^2;/*第2位數碼管共陰端*/
sbit shu3=P1^1;/*第3位數碼管共陰端*/
sbit shu4=P1^0;/*第4位數碼管共陰端*/
////////////////
void delayms(unsigned int i);
unsigned char yima[]={0xeb,0x88,0xb3,0xba,0xd8,0x7a,0x7b,0xa8,0xfb,0xfa};/*解碼表,此表數據和硬體相關*/
unsigned int b=0;/*要顯示的數據*/
unsigned int b_count=0;/*掃描次數*/
void delayms(unsigned int i);
unsigned int keyboar();
unsigned int b;
void t0()interrupt 1 using 1 /*中斷程序負責顯示b的值 */
{
unsigned char a1=0,a2=0,a3=0,a4=0;
static int k=0;
/*數碼管掃描顯示*/
a1=b/1000;/*取b的千位*/
a2=b%1000/100;/*取b的百位*/
a3=b%100/10;/*取b的十位*/
a4=b%10;/*取b的個位*/
if(k==0){shu4=1;shu1=0;shu2=0;shu3=0;P0=yima[a1];}
else if(k==1){shu4=0;shu1=1;shu2=0;shu3=0;P0=yima[a4];}
else if(k==2){shu4=0;shu1=0;shu2=1;shu3=0;P0=yima[a3];}
else if(k==3){shu4=0;shu1=0;shu2=0;shu3=1;P0=yima[a2];}
k++;
if(k>3)k=0;
TH0=240;
}
main()
{
EA=1;/*開全局中斷 */
TR0=1;/*定時器0開始計數 */
ET0=1;/*定時器0開中斷 */
TMOD=0X01;/*定時器0工作在方式1:16位計數模式 */
while(1)
{
b= keyboar(); /*把按鍵的代表的值給b */
}
}
void delayms(unsigned int i)
{
unsigned int j;
for(;i>0;i--)
for(j=100;j>0;j--);
}
//////////////////////////////////////////////////////////////////////////////////
//掃描法:逐行掃描查詢 一般用在按鍵比較少的場合
int keyscan()
{
unsigned char k k_temp;
P1=0xf0; //低位置0,准備查詢按鍵
k=P1; //取得當前P1口狀態
if(k!=0xf0) //如果有變化則表示有按鍵按下
{
delay(10); //延遲 消抖
k_temp=p1;
if(k==k_temp) //確實有鍵按下
{
k=0xfe;
do //循環掃描每一行
{
p1=k;
if(k!=p1)
{
switch(P1) //判斷按鍵 並返回鍵值
{
//第1行
case 0x7e:{return 0; break;}
case 0xbe:{return 1; break;}
case 0xde:{return 2; break;}
case 0xee:{return 3; break;}
//第2行
case 0x7d:{return 4; break;}
case 0xbd:{return 5; break;}
case 0xdd:{return 6; break;}
case 0xed:{return 7; break;}
//第3行
case 0x7b:{return 8; break;}
case 0xbb:{return 9; break;}
case 0xdb:{return 10;break;}
case 0xeb:{return 11;break;}
//第4行
case 0x77:{return 12;break;}
case 0xb7:{return 13;break;}
case 0xd7:{return 14;break;}
case 0xe7:{return 15;break;}
}
}
k=_crol_(k,1); //移位 進入下一行掃描
}
while(k!=0xef); //超過列范圍 退出掃描
}
}
}
////////////////////////////////////////////////////////////////////////////////
//線反轉法 :只需2步便可獲得按鍵位置,最常用
unsigned int keyboar()/*線反轉法 */
{
static unsigned int a=0;
unsigned char a1=0,b1=0;
/*行線為輸入線,列線為輸出線 */
v1=v2=v3=v4=0;
h1=h2=h3=h4=1;
if(P2<0xf0)/*檢查行是否有按鍵按下 */
{
delayms(10);
if(P2<0xf0)
{
/*行線為輸入線,列線為輸出線 */
v1=v2=v3=v4=0;
h1=h2=h3=h4=1;
a1=P2;
/*行線為輸出線,列線為輸入線 */
h1=h2=h3=h4=0;
v1=v2=v3=v4=1;
b1=P2;
a=a1|b1;
}
}
if (a==0xe7) { return 7; }
else if(a==0xeb) { return 8; }
else if(a==0xed) { return 9; }
else if(a==0xee) { return 13;}
else if(a==0xd7) {return 4; }
else if(a==0xdb) {return 5; }
else if(a==0xdd) {return 6; }
else if(a==0xde) {return 12;}
else if(a==0xb7) {return 1; }
else if(a==0xbb) {return 2; }
else if(a==0xbd) {return 3; }
else if(a==0xbe) {return 11;}
else if(a==0x77) {return 0; }
else if(a==0x7b) {return 15;}
else if(a==0x7d) {return 16;}
else if(a==0x7e) {return 10;}
else return 17;
}
/*******************************************
流水燈寫法1
while(1)
{
a=0x01; //賦初值00000001
for(i=0;i<8;i++) //循環8次
{
P0=a;
delay(500);
a=a<<1; //左移1位
}
}
流水燈寫法2:
a=0x01; //賦初值00000001
while(1)
{
P0=a; //先點亮第1個led
delay(500);
a=_crol_(a,1); //將a循環左移1位後再賦給a
}
流水燈寫法3:
while(1)
{
a=0x01; //賦初值00000001
for(i=0;i<7;i++)
{
P0=a;
delay(500);
a=a<<1; //左移
}
for(i=0;i<7;i++)
{
P0=a;
delay(500);
a=a>>1; //右移
}
}
寫法3:
void t0() interrupt 1 //中斷服務函數
{
TH0=(65536-50000)/256; //計數寄存器高8位重新載入
TL0=(65536-50000)%256; //計數寄存器低8位重新載入
num++;
if(num>=10) //500ms 調整流水速度
{
num=0;
P0=1<<i; //進入位移操作,熄滅相對應位的LED P0=1然後P0右移i位
i++;
if(i>7) i=0;
}
}