51单片机学习之路 —— 1.8 矩阵键盘
—.— 好久没有更新,最近太忙了,我被英语快搞死了,马上要四级了,自己语法好差。迷茫ing
1 什么是矩阵键盘?
这里补一个键盘的定义




大家看原理图,这就是矩阵键盘(4*4)
四行 分别连到P3.0 P3.1 P3.2(INT0) P3.3(INT1) (从上到下)
四列 分别连到P3.4(LCDEN) P3.5(RS) P3.6(WR) P3.7(RD)(左到右)
2
独立键盘一端固定位低电平! 检验较为方便
但矩阵键盘不一样,他两边都与单片机的I/O相连接。所以检测方法有些不同
要人为送出低电平,我们采取以下的检测方法:
1. 先送一列为低电平,其余几列都为高电平(用此来确定列数)
2. 然后立即轮流检测每一行是否有低电平(确定行数)

我们写一个函数,用两个变量接受列和行的数据 cord_l cord_h
P3 = 0xf0; // 1111 0000
![]()
判断是否有按键按下: 例如 S6按下
1.
2. 假设S6按下

此刻S6按下导通P3.4接口LCDEN为低电平(可以这样理解是P3.0与P3.4 0&1=0)
此时的P3口为 1110 0000 (0xe0)
P3 & 0xf0 (P3和0xf0按位与)
P3 = 1110 0000
0xf0 = 1111 0000
= 1110 0000 = 0xe0
这时
成立
表示有按键按下
3 延时消抖
![]()
4 储存值

P3 = 1110 0000
0xf0 = 1111 0000
cord_l = 1110 0000

cord_l = 1110 0000
0x0f = 0000 1111
P3 = 1110 1111 = 1110 1110(按下的是s6 P3.0 与 P3.1 与)

P3 = 1110 1110
0x0f = 0000 1111
cord_h = 0000 1110

cord_l = 1110 0000
cord_h = 0000 1110
返回值 = 1110 1110 = 0xee
这样我们就确定了一个值0xee 意味着是s6按下
2 程序编写 要求:按顺序按下s6~s21 依次显示0~f 6个数码管静态显示即可
1 #include <reg52.h> 2 #define uchar unsigned char 3 #define uint unsigned int 4 sbit we = P2^7; 5 sbit du = P2^6; 6 uchar code leddata[]={ 7 8 0x3F, //"0" 9 0x06, //"1" 10 0x5B, //"2" 11 0x4F, //"3" 12 0x66, //"4" 13 0x6D, //"5" 14 0x7D, //"6" 15 0x07, //"7" 16 0x7F, //"8" 17 0x6F, //"9" 18 0x77, //"A" 19 0x7C, //"B" 20 0x39, //"C" 21 0x5E, //"D" 22 0x79, //"E" 23 0x71, //"F" 24 0x76, //"H" 25 0x38, //"L" 26 0x37, //"n" 27 0x3E, //"u" 28 0x73, //"P" 29 0x5C, //"o" 30 0x40, //"-" 31 0x00, //熄灭 32 0x00 //自定义 33 34 }; 35 void delay(uint z) 36 { 37 uint x,y; 38 for(x = z; x > 0; x--) 39 for(y = 114; y > 0 ; y--); 40 } 41 42 43 uchar KeyScan() //带返回值的子函数 44 { 45 uchar cord_l,cord_h;//声明列线和行线的值的储存变量 46 P3 = 0xf0;//1111 0000 47 if( (P3 & 0xf0) != 0xf0)//判断是否有按键按下 48 { 49 delay(5);//软件消抖 50 if( (P3 & 0xf0) != 0xf0)//判断是否有按键按下 51 { 52 cord_l = P3 & 0xf0;// 储存列线值 53 P3 = cord_l | 0x0f; 54 cord_h = P3 & 0x0f;// 储存行线值 55 while( (P3 & 0x0f) != 0x0f );//松手检测 56 return (cord_l + cord_h);//返回键值码 57 } 58 } 59 60 } 61 62 void KeyPro() 63 { 64 switch( KeyScan() ) 65 { 66 //第一行键值码 67 case 0xee: P0 = leddata[0]; break; 68 case 0xde: P0 = leddata[1]; break; 69 case 0xbe: P0 = leddata[2]; break; 70 case 0x7e: P0 = leddata[3]; break; 71 72 //第二行键值码 73 case 0xed: P0 = leddata[4]; break; 74 case 0xdd: P0 = leddata[5]; break; 75 case 0xbd: P0 = leddata[6]; break; 76 case 0x7d: P0 = leddata[7]; break; 77 78 //第三行键值码 79 case 0xeb: P0 = leddata[8]; break; 80 case 0xdb: P0 = leddata[9]; break; 81 case 0xbb: P0 = leddata[10]; break; 82 case 0x7b: P0 = leddata[11]; break; 83 84 //第四行键值码 85 case 0xe7: P0 = leddata[12]; break; 86 case 0xd7: P0 = leddata[13]; break; 87 case 0xb7: P0 = leddata[14]; break; 88 case 0x77: P0 = leddata[15]; break; 89 } 90 } 91 92 void main() 93 { 94 we = 1;//打开位选 95 P0 = 0;//八位数码管全显示 96 we = 0;//锁存位选 97 98 du = 1;//打开段选端 99 P0 = leddata[22]; 100 while(1) 101 { 102 KeyPro();//提取键值码并且送不同数值给数码管显示 103 } 104 }

这里让数码管一开始显示一个-
用了一个循环让其一直执行

注意switch中的表达式就是我们通过扫描键盘扫描出的键值码。
3 补充:
c语言中的一些运算符
|
运算符 |
范例 |
说明 |
|
+ |
a+b |
a变量值和b变量值相加 |
|
- |
a-b |
a变量值和b变量值相减 |
|
* |
a*b |
a变量值乘以b变量值 |
|
/ |
a/b |
a变量值除以b变量值 |
|
% |
a%b |
取a变量值除以b变量值的余数 |
|
= |
a=6 |
将6设定给a变量,即a变量值等于6 |
|
+= |
a+=b |
等同于a=a+b,将a和b相加的结果又存回a |
|
-= |
a-=b |
等同于a=a-b,将a和b相减的结果又存回a |
|
*= |
a*=b |
等同于a=a*b,将a和b相乘的结果又存回a |
|
/= |
a/=b |
等同于a=a/b,将a和b相除的结果又存回a |
|
%= |
a%=b |
等同于a=a%b,将a变量值除以b变量值余数又存回a |
|
++ |
a++ |
a的值加1,即a=a+1 |
|
-- |
a-- |
a的值减1,即a=a-1 |
|
> |
a>b |
测试a的值是否大于b |
|
< |
a<b |
测试a的值是否小于b |
|
= |
a=b |
测试a的值是否等于于b |
|
>= |
a>=b |
测试a的值是否大于或等于b |
|
<= |
a<=b |
测试a的值是否小于或等于b |
|
!= |
a!=b |
测试a的值是否不等于b |
|
&& |
a&&b |
a和b做逻辑做AND,两个变量都是“真”,结果才为“真”否则结果为“0” |
|
|| |
a||b |
a和b做逻辑做OR,只要任何一个变量为“真”,结果就为“真” |
|
! |
!a |
将a变量的值取反,即原来为“真”则变“假”,为“假”则变为“真” |
|
>> |
a>>b |
将a按位右移b个位 |
|
<< |
a<<b |
将a按位左移b个位,右侧补“0” |
|
| |
a|b |
a和b的按位做OR运算 |
|
& |
a&b |
a和b的按位做AND运算 |
|
^ |
a^b |
a和b的按位做XOR运算 |
|
~ |
~a |
将a的每一位取反 |
|
& |
a=&b |
将b变量的地址存入a寄存器 |
|
* |
*a |
用来取寄存器所指地址内的值 |
浙公网安备 33010602011771号