51单片机学习笔记(郭天祥版)(5)——作业讲解、独立键盘、矩阵键盘
作业讲解
第三题:
先用定时器0把流水灯的写出来,再写定时器1的数码管显示,用变量存储765432,再定时器中断函数里自减,当到达7654398时,关闭定时器就不会变化了,这里765是不变的,偷懒,只管432。写完数码管停止和流水灯停止都试验后再写剩下的。改变定时器计时时间这里要记住。
1 #include<reg51.h> 2 #include<intrins.h> 3 4 #define uchar unsigned char 5 #define uint unsigned int 6 7 void Delay1ms(); 8 void delay(int n); 9 void display(uchar a,uchar b,uchar c,uchar bai,uchar shi,uchar ge); 10 void init(); 11 sbit WEI=P2^7; 12 sbit DUAN=P2^6; 13 14 uchar code Table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x00,0x76,0x79,0x38,0x3f}; 15 // 0 1 2 3 4 5 6 7 8 9 A B C D E F 无显示 H E L O 16 uchar flag=0,flag1=0; 17 uchar t0=0,t1=0; 18 uint number=432; 19 uchar bai=0,shi=0,ge=0; 20 void main() 21 { 22 init(); 23 bai=number/100; 24 shi=number/10%10; 25 ge=number%10; 26 while(1) 27 { 28 if(flag1!=1) 29 { 30 display(7,6,5,bai,shi,ge); 31 } 32 else 33 { 34 display(17,18,19,19,20,16); 35 } 36 } 37 } 38 39 void delay(int n) 40 { 41 while(n--) 42 { 43 Delay1ms(); 44 } 45 } 46 void Delay1ms() //@12.000MHz 47 { 48 unsigned char i, j; 49 50 i = 2; 51 j = 239; 52 do 53 { 54 while (--j); 55 } while (--i); 56 } 57 void init() 58 { 59 P1=0xfe; 60 TMOD=0x11;//两个定时器都设置为方式1 61 TH0=(65536-50000)/256; 62 TL0=(65536-50000)%256; 63 TH1=(65536-50000)/256; 64 TL1=(65536-50000)%256; 65 EA=1; 66 ET0=1; 67 TR0=1; 68 ET1=1; 69 TR1=1; 70 } 71 void timer1() interrupt 3 72 { 73 TH1=(65536-50000)/256; 74 TL1=(65536-50000)%256; 75 t1++; 76 if(t1==2) 77 { 78 t1=0; 79 number--; 80 bai=number/100; 81 shi=number/10%10; 82 ge=number%10; 83 if(number==398) 84 { 85 //定时器0到这个位置还在运行,且TH0和TL0不知道是多少,所以要重新赋值 86 TR0=0; 87 88 TH0=(65536-50000)/256; 89 TL0=(65536-50000)%256; 90 TR0=1; 91 flag=1; 92 t0=0; 93 P1=0xff; 94 TR1=0; 95 } 96 } 97 } 98 void timer0() interrupt 1 99 { 100 TH0=(65536-50000)/256; 101 TL0=(65536-50000)%256; 102 t0++; 103 if(flag!=1) 104 { 105 if(t0==10) 106 { 107 t0=0; 108 P1=_crol_(P1,1); 109 } 110 } 111 else 112 { 113 if(t0%4==0) 114 { 115 P1=~P1; 116 if(t0==60) 117 { 118 TR0=0; 119 P1=0xff; 120 flag1=1; 121 } 122 } 123 } 124 } 125 void display(uchar a,uchar b,uchar c,uchar bai,uchar shi,uchar ge) 126 { 127 DUAN=1; 128 P0=Table[a]; 129 DUAN=0; 130 131 P0=0xff; 132 WEI=1; 133 P0=0xfe; 134 WEI=0; 135 delay(1); 136 137 DUAN=1; 138 P0=Table[b]; 139 DUAN=0; 140 141 P0=0xff; 142 WEI=1; 143 P0=0xfd; 144 WEI=0; 145 delay(1); 146 147 DUAN=1; 148 P0=Table[c]; 149 DUAN=0; 150 151 P0=0xff; 152 WEI=1; 153 P0=0xfb; 154 WEI=0; 155 delay(1); 156 157 DUAN=1; 158 P0=Table[bai]; 159 DUAN=0; 160 161 P0=0xff; 162 WEI=1; 163 P0=0xf7; 164 WEI=0; 165 delay(1); 166 167 DUAN=1; 168 P0=Table[shi]; 169 DUAN=0; 170 171 P0=0xff; 172 WEI=1; 173 P0=0xef; 174 WEI=0; 175 delay(1); 176 177 DUAN=1; 178 P0=Table[ge]; 179 DUAN=0; 180 181 P0=0xff; 182 WEI=1; 183 P0=0xdf; 184 WEI=0; 185 delay(1); 186 }
中断函数不能太长,我们每50ms进入一次中断,如果中断函数长达50ms,那么当下一次中断进入函数时,上一次中断没退出,就会把下一次的丢失,程序就会出错。如何看这个时间呢,一个机器周期1us,指令有单周期指令和双周期指令,一般指令都是单周期指令,一个单周期指令1us,双周期2us,如果函数有1000条指令也才1ms,所以没问题,只要不加延时函数一般没事。
键盘
计算机键盘是ps2型的接口,键盘每按下一个值,内部有一个编码器,编码完后发给计算机,计算机有专门给键盘开的中断,优先级比较高,外接的任何响应计算机会立马从中断中收到数据,看出是按得哪一个按键。
单片机的是非编码键盘。非编码键盘又分为独立键盘和行列式(又称为矩阵式)键盘。
独立键盘的典型接法。32个IO口都可以作为输入输出,所以在哪个口接键盘都可以,检测按下:P1~P3IO口线内均有固定的上拉电阻,当这三个准双向IO口作输入口使用时,要向该口先写1,然后才能读取这个口的状态。原本P3.4=1,当键盘按下,P3.4接地了,TTL电路中IO口不是高阻态、没有三态状态,它与和它相连的线是线与的关系。如果P3.4变为低电平了就说明按下了。
类似这两根线,只要有一根线为0,那么整个线路就是低电平。还有一种是线或的关系,当某一根线和具有三态功能的线相连,当三态IO口处于高阻态状态,和它连接的线产生线或的关系,跟他连接的线是高电平,高阻态就会变为高电平。
单片机中独立键盘和矩阵键盘的接法。
接下来写个代码试试独立键盘
1 #include<reg51.h> 2 3 #define uchar unsigned char 4 #define uint unsigned int 5 6 sbit led0=P1^0; 7 sbit key0=P3^0; 8 9 void main() 10 { 11 while(1) 12 { 13 if(key0==0) 14 led0=0; 15 else 16 led0=1; 17 } 18 }
这就是单片机的输入了,之前学的全都是单片机的输出。
但这个代码其实是有毛病的,这样你可能看不出来,接下来再写一个程序看看,数码管初始0,按一下键盘+1,到10归0;
1 #include<reg51.h> 2 3 #define uchar unsigned char 4 #define uint unsigned int 5 6 sbit WEI=P2^7; 7 sbit DUAN=P2^6; 8 9 sbit led0=P1^0; 10 sbit key0=P3^0; 11 12 uchar code Table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x00}; 13 // 0 1 2 3 4 5 6 7 8 9 A B C D E F 无显示 14 uchar num=0; 15 16 void main() 17 { 18 WEI=1; 19 P0=0xfe; 20 WEI=0; 21 while(1) 22 { 23 if(key0==0) 24 { 25 led0=0; 26 num++; 27 if(num>9) 28 { 29 num=0; 30 } 31 } 32 else 33 { 34 led0=1; 35 } 36 DUAN=1; 37 P0=Table[num]; 38 DUAN=0; 39 } 40 }
你会发现按下键盘,数码管不是+1,而是随机的。
原因如下:
右侧为硬件消抖,所以不需要看,有时软件消抖不方便或者不想浪费资源就用硬件消抖
抖动时就会检测你按了很多次。
你可能会说上面的代码可能就是按了一下,但是很长时间没抬起,所以进入了很多次if,从而num++许多次,那么我们加上松手检测。
按键按下时key0=0,那么只要当key0==0时为死循环就可以了
1 #include<reg51.h> 2 3 #define uchar unsigned char 4 #define uint unsigned int 5 6 sbit WEI=P2^7; 7 sbit DUAN=P2^6; 8 9 sbit led0=P1^0; 10 sbit key0=P3^0; 11 12 uchar code Table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x00}; 13 // 0 1 2 3 4 5 6 7 8 9 A B C D E F 无显示 14 uchar num=0; 15 void Delay1ms(); 16 void delay(int n); 17 18 void main() 19 { 20 WEI=1; 21 P0=0xfe; 22 WEI=0; 23 while(1) 24 { 25 if(key0==0) 26 { 27 led0=0; 28 num++; 29 if(num>9) 30 { 31 num=0; 32 } 33 while(!key0); 34 } 35 else 36 { 37 led0=1; 38 } 39 DUAN=1; 40 P0=Table[num]; 41 DUAN=0; 42 } 43 } 44 45 void delay(int n) 46 { 47 while(n--) 48 { 49 Delay1ms(); 50 } 51 } 52 void Delay1ms() //@12.000MHz 53 { 54 unsigned char i, j; 55 56 i = 2; 57 j = 239; 58 do 59 { 60 while (--j); 61 } while (--i); 62 }
这样就能证明存在抖动的现象。
我们只去除按下时的抖动,松开时的不需要,如何去呢?用延时函数,当按下去时我们延时10ms,按键按下抖动大约5ms左右,那么为了稳定我们可以写10ms,低电平保持的时间大约有20ms,所以消抖用掉5ms,还剩15ms,我们完全可以侧得到。
下面是消抖的代码:
1 #include<reg51.h> 2 3 #define uchar unsigned char 4 #define uint unsigned int 5 6 sbit WEI=P2^7; 7 sbit DUAN=P2^6; 8 9 sbit led0=P1^0; 10 sbit key0=P3^0; 11 12 uchar code Table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x00}; 13 // 0 1 2 3 4 5 6 7 8 9 A B C D E F 无显示 14 uchar num=0; 15 void Delay1ms(); 16 void delay(int n); 17 18 void main() 19 { 20 WEI=1; 21 P0=0xfe; 22 WEI=0; 23 while(1) 24 { 25 if(key0==0) 26 { 27 delay(10); 28 if(key0==0) 29 { 30 led0=0; 31 num++; 32 if(num>9) 33 { 34 num=0; 35 } 36 } 37 while(!key0); 38 } 39 else 40 { 41 led0=1; 42 } 43 DUAN=1; 44 P0=Table[num]; 45 DUAN=0; 46 } 47 } 48 49 void delay(int n) 50 { 51 while(n--) 52 { 53 Delay1ms(); 54 } 55 } 56 void Delay1ms() //@12.000MHz 57 { 58 unsigned char i, j; 59 60 i = 2; 61 j = 239; 62 do 63 { 64 while (--j); 65 } while (--i); 66 }
这样就没有问题了,这里最后的松手检测放在第二层if(key0==0)里面和外面都一样。
有时为了更加稳定会在末尾再加上一次消抖,如下:
1 #include<reg51.h> 2 3 #define uchar unsigned char 4 #define uint unsigned int 5 6 sbit WEI=P2^7; 7 sbit DUAN=P2^6; 8 9 sbit led0=P1^0; 10 sbit key0=P3^0; 11 12 uchar code Table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x00}; 13 // 0 1 2 3 4 5 6 7 8 9 A B C D E F 无显示 14 uchar num=0; 15 void Delay1ms(); 16 void delay(int n); 17 18 void main() 19 { 20 WEI=1; 21 P0=0xfe; 22 WEI=0; 23 while(1) 24 { 25 if(key0==0) 26 { 27 delay(10); 28 if(key0==0) 29 { 30 led0=0; 31 num++; 32 if(num>9) 33 { 34 num=0; 35 } 36 } 37 while(!key0); 38 delay(10); 39 while(!key0); 40 } 41 else 42 { 43 led0=1; 44 } 45 DUAN=1; 46 P0=Table[num]; 47 DUAN=0; 48 } 49 } 50 51 void delay(int n) 52 { 53 while(n--) 54 { 55 Delay1ms(); 56 } 57 } 58 void Delay1ms() //@12.000MHz 59 { 60 unsigned char i, j; 61 62 i = 2; 63 j = 239; 64 do 65 { 66 while (--j); 67 } while (--i); 68 }
延时去抖改为5ms也是可以的,尽量不要让cpu有过多的等待。
接下来是矩阵键盘
这是典型的矩阵键盘的接法(总线方式):
你也可以自己仿照做成2*2,3*3,甚至4*5的,这时一组IO口不够用,那就接到别的IO口,检测的原理都是一样的。
检测原理:
其实和独立键盘都是一样的,都是检测低电平,但是四行四列全部连得IO口,没有接地的,所以低电平由你写程序给予。
先给P3.0~3.3这样赋值,然后读取P3.4~3.7的数据,如果第一个键按下去了,那么P3.4就是0(线与的关系,没忘吧?),同一时刻你只能按下一个键,检测时都是有先后顺序的。那么P3的值就是如下:
如果是按下的第1行第2列的键,那么就会如下:
以此类推。如果都没按下去,那么P3.4~P3.7都是1。我们就根据每一次读取的值判断按下去的是哪一个键。这就是第一行的检测,矩阵键盘的检测要依次对四行进行扫描,第一次P3.0=0,然后读取四列,如果没有按下去,那么下一次就是把P3.1=0,其它三个为1,也是这样判断。只要有任何一个键被按下,就跳出整个大循环,直接退出扫描程序。如果你是两个一起按下去的,也是有先后顺序的,那么后面的也检测不到。
先让P3=0xfe,在定义一个变量temp,保存P3的值(temp=P3),接下来我们要读的实际上是P3的高4位,只想知道高4位什么状态,然后再让temp&0xf0(按位与),如果一个都没按下,那么高4位全是1,低4位不管(任何数和0与都是0),那么temp&0xf0的结果还是0xf0,如果不是0xf0就是有键按下,如果第一个键按下了,那么P3.7~3.4就是1110,后面低4位不管,那么和0xf0与的时候就是1110 0000,不等于0xf0(1111 0000),就知道有键按下了,之后延时一下,再检测一遍,如果还是这个数,0xe0,那么就知道第一个键按下去了,用一个变量num,num=1,标记第一个键。一共扫描16次(第一行赋值0,扫描4列,第二行0,扫描4列......)。
再举一下例子:
例如按下去的是第一行第二列的键。
那么第一次赋值P3=1111 1110后,temp就会为1101 1110,temp&0xfe=1101 0000,然后和0xfe比较即可,之后num=按下去的键的值。
写程序看看,按下键盘,数码管显示对应的值,键盘的值分别为,第一行:0123,只检测第一行的。
1 #include<reg51.h> 2 3 #define uchar unsigned char 4 #define uint unsigned int 5 6 sbit WEI=P2^7; 7 sbit DUAN=P2^6; 8 9 sbit led0=P1^0; 10 sbit key0=P3^0; 11 12 uchar code Table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x00}; 13 // 0 1 2 3 4 5 6 7 8 9 A B C D E F 无显示 14 uchar num=0,temp; 15 void Delay1ms(); 16 void delay(int n); 17 18 void main() 19 { 20 DUAN=1; 21 P0=0x00; 22 DUAN=0; 23 WEI=1; 24 P0=0xfe; 25 WEI=0; 26 while(1) 27 { 28 P3=0xfe; 29 temp=P3; 30 temp=temp&0xf0; 31 while(temp!=0xf0) 32 { 33 delay(5); 34 temp=P3; 35 temp=temp&0xf0; 36 while(temp!=0xf0) 37 { 38 temp=P3; 39 switch(temp) 40 { 41 case 0xee:num=1;break; 42 case 0xde:num=2;break; 43 case 0xbe:num=3;break; 44 case 0x7e:num=4;break; 45 } 46 DUAN=1; 47 P0=Table[num-1]; 48 DUAN=0; 49 } 50 } 51 } 52 } 53 54 void delay(int n) 55 { 56 while(n--) 57 { 58 Delay1ms(); 59 } 60 } 61 void Delay1ms() //@12.000MHz 62 { 63 unsigned char i, j; 64 65 i = 2; 66 j = 239; 67 do 68 { 69 while (--j); 70 } while (--i); 71 }
明明用if更简单,郭天祥竟然用while
1 #include<reg51.h> 2 3 #define uchar unsigned char 4 #define uint unsigned int 5 6 sbit WEI=P2^7; 7 sbit DUAN=P2^6; 8 9 sbit led0=P1^0; 10 sbit key0=P3^0; 11 12 uchar code Table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x00}; 13 // 0 1 2 3 4 5 6 7 8 9 A B C D E F 无显示 14 uchar num=0,temp; 15 void Delay1ms(); 16 void delay(int n); 17 18 void main() 19 { 20 DUAN=1; 21 P0=0x00; 22 DUAN=0; 23 WEI=1; 24 P0=0xfe; 25 WEI=0; 26 while(1) 27 { 28 P3=0xfe; 29 temp=P3; 30 temp=temp&0xf0; 31 if(temp!=0xf0) 32 { 33 delay(5); 34 temp=P3; 35 temp=temp&0xf0; 36 if(temp!=0xf0) 37 { 38 switch(temp) 39 { 40 case 0xe0:num=1;break; 41 case 0xd0:num=2;break; 42 case 0xb0:num=3;break; 43 case 0x70:num=4;break; 44 } 45 DUAN=1; 46 P0=Table[num-1]; 47 DUAN=0; 48 } 49 } 50 } 51 } 52 53 void delay(int n) 54 { 55 while(n--) 56 { 57 Delay1ms(); 58 } 59 } 60 void Delay1ms() //@12.000MHz 61 { 62 unsigned char i, j; 63 64 i = 2; 65 j = 239; 66 do 67 { 68 while (--j); 69 } while (--i); 70 }
然后我们再把剩下四行也加上看看
1 #include<reg51.h> 2 3 #define uchar unsigned char 4 #define uint unsigned int 5 6 sbit WEI=P2^7; 7 sbit DUAN=P2^6; 8 9 sbit led0=P1^0; 10 sbit key0=P3^0; 11 12 uchar code Table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x00}; 13 // 0 1 2 3 4 5 6 7 8 9 A B C D E F 无显示 14 uchar num=0,temp; 15 void Delay1ms(); 16 void delay(int n); 17 18 void main() 19 { 20 DUAN=1; 21 P0=0x00; 22 DUAN=0; 23 WEI=1; 24 P0=0xfe; 25 WEI=0; 26 while(1) 27 { 28 //第一行 29 P3=0xfe; 30 temp=P3; 31 temp=temp&0xf0; 32 while(temp!=0xf0) 33 { 34 delay(5); 35 temp=P3; 36 temp=temp&0xf0; 37 while(temp!=0xf0) 38 { 39 temp=P3; 40 switch(temp) 41 { 42 case 0xee:num=1;break; 43 case 0xde:num=2;break; 44 case 0xbe:num=3;break; 45 case 0x7e:num=4;break; 46 } 47 48 /*没有这里的话,如果按下某一行,就会一直进入上面这个while循环,即使松手也出不来, 49 有了它,不松手就一直在下面的循环,松手后就会改变temp的值,变为0xf0*/ 50 while(temp!=0xf0) 51 { 52 temp=P3; 53 temp=temp&0xf0; 54 } 55 DUAN=1; 56 P0=Table[num-1]; 57 DUAN=0; 58 } 59 } 60 61 //第二行 62 P3=0xfd; 63 temp=P3; 64 temp=temp&0xf0; 65 while(temp!=0xf0) 66 { 67 delay(5); 68 temp=P3; 69 temp=temp&0xf0; 70 while(temp!=0xf0) 71 { 72 temp=P3; 73 switch(temp) 74 { 75 case 0xed:num=5;break; 76 case 0xdd:num=6;break; 77 case 0xbd:num=7;break; 78 case 0x7d:num=8;break; 79 } 80 while(temp!=0xf0) 81 { 82 temp=P3; 83 temp=temp&0xf0; 84 } 85 DUAN=1; 86 P0=Table[num-1]; 87 DUAN=0; 88 } 89 } 90 91 //第三行 92 P3=0xfb; 93 temp=P3; 94 temp=temp&0xf0; 95 while(temp!=0xf0) 96 { 97 delay(5); 98 temp=P3; 99 temp=temp&0xf0; 100 while(temp!=0xf0) 101 { 102 temp=P3; 103 switch(temp) 104 { 105 case 0xeb:num=9;break; 106 case 0xdb:num=10;break; 107 case 0xbb:num=11;break; 108 case 0x7b:num=12;break; 109 } 110 while(temp!=0xf0) 111 { 112 temp=P3; 113 temp=temp&0xf0; 114 } 115 DUAN=1; 116 P0=Table[num-1]; 117 DUAN=0; 118 } 119 } 120 121 //第四行 122 P3=0xf7; 123 temp=P3; 124 temp=temp&0xf0; 125 while(temp!=0xf0) 126 { 127 delay(5); 128 temp=P3; 129 temp=temp&0xf0; 130 while(temp!=0xf0) 131 { 132 temp=P3; 133 switch(temp) 134 { 135 case 0xe7:num=13;break; 136 case 0xd7:num=14;break; 137 case 0xb7:num=15;break; 138 case 0x77:num=16;break; 139 } 140 while(temp!=0xf0) 141 { 142 temp=P3; 143 temp=temp&0xf0; 144 } 145 DUAN=1; 146 P0=Table[num-1]; 147 DUAN=0; 148 } 149 } 150 } 151 } 152 153 void delay(int n) 154 { 155 while(n--) 156 { 157 Delay1ms(); 158 } 159 } 160 void Delay1ms() //@12.000MHz 161 { 162 unsigned char i, j; 163 164 i = 2; 165 j = 239; 166 do 167 { 168 while (--j); 169 } while (--i); 170 }
我们可以把扫描改为函数,方便移植到别的程序
1 #include<reg51.h> 2 3 #define uchar unsigned char 4 #define uint unsigned int 5 6 sbit WEI=P2^7; 7 sbit DUAN=P2^6; 8 9 sbit led0=P1^0; 10 sbit key0=P3^0; 11 12 uchar code Table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x00}; 13 // 0 1 2 3 4 5 6 7 8 9 A B C D E F 无显示 14 uchar num=17,temp;//num一开始为17,这样-1后就是不显示,用于最初没有按键按下时的情况 15 void Delay1ms(); 16 void delay(int n); 17 uchar keyscan(); 18 void main() 19 { 20 DUAN=1; 21 P0=0x00; 22 DUAN=0; 23 WEI=1; 24 P0=0xfe; 25 WEI=0; 26 while(1) 27 { 28 DUAN=1; 29 P0=Table[keyscan()-1]; 30 DUAN=0; 31 } 32 } 33 34 void delay(int n) 35 { 36 while(n--) 37 { 38 Delay1ms(); 39 } 40 } 41 void Delay1ms() //@12.000MHz 42 { 43 unsigned char i, j; 44 45 i = 2; 46 j = 239; 47 do 48 { 49 while (--j); 50 } while (--i); 51 } 52 53 uchar keyscan() 54 { 55 //第一行 56 P3=0xfe; 57 temp=P3; 58 temp=temp&0xf0; 59 while(temp!=0xf0) 60 { 61 delay(5); 62 temp=P3; 63 temp=temp&0xf0; 64 while(temp!=0xf0) 65 { 66 temp=P3; 67 switch(temp) 68 { 69 case 0xee:num=1;break; 70 case 0xde:num=2;break; 71 case 0xbe:num=3;break; 72 case 0x7e:num=4;break; 73 } 74 75 /*没有这里的话,如果按下某一行,就会一直进入上面这个while循环,即使松手也出不来, 76 有了它,不松手就一直在下面的循环,松手后就会改变temp的值,变为0xf0*/ 77 while(temp!=0xf0) 78 { 79 temp=P3; 80 temp=temp&0xf0; 81 } 82 //放入函数里有就不需要这个显示了 83 // DUAN=1; 84 // P0=Table[num-1]; 85 // DUAN=0; 86 } 87 } 88 89 //第二行 90 P3=0xfd; 91 temp=P3; 92 temp=temp&0xf0; 93 while(temp!=0xf0) 94 { 95 delay(5); 96 temp=P3; 97 temp=temp&0xf0; 98 while(temp!=0xf0) 99 { 100 temp=P3; 101 switch(temp) 102 { 103 case 0xed:num=5;break; 104 case 0xdd:num=6;break; 105 case 0xbd:num=7;break; 106 case 0x7d:num=8;break; 107 } 108 while(temp!=0xf0) 109 { 110 temp=P3; 111 temp=temp&0xf0; 112 } 113 // DUAN=1; 114 // P0=Table[num-1]; 115 // DUAN=0; 116 } 117 } 118 119 //第三行 120 P3=0xfb; 121 temp=P3; 122 temp=temp&0xf0; 123 while(temp!=0xf0) 124 { 125 delay(5); 126 temp=P3; 127 temp=temp&0xf0; 128 while(temp!=0xf0) 129 { 130 temp=P3; 131 switch(temp) 132 { 133 case 0xeb:num=9;break; 134 case 0xdb:num=10;break; 135 case 0xbb:num=11;break; 136 case 0x7b:num=12;break; 137 } 138 while(temp!=0xf0) 139 { 140 temp=P3; 141 temp=temp&0xf0; 142 } 143 // DUAN=1; 144 // P0=Table[num-1]; 145 // DUAN=0; 146 } 147 } 148 149 //第四行 150 P3=0xf7; 151 temp=P3; 152 temp=temp&0xf0; 153 while(temp!=0xf0) 154 { 155 delay(5); 156 temp=P3; 157 temp=temp&0xf0; 158 while(temp!=0xf0) 159 { 160 temp=P3; 161 switch(temp) 162 { 163 case 0xe7:num=13;break; 164 case 0xd7:num=14;break; 165 case 0xb7:num=15;break; 166 case 0x77:num=16;break; 167 } 168 while(temp!=0xf0) 169 { 170 temp=P3; 171 temp=temp&0xf0; 172 } 173 // DUAN=1; 174 // P0=Table[num-1]; 175 // DUAN=0; 176 } 177 } 178 return num; 179 }
同样的也可以把显示用函数封装起来。这里就不给代码了。
接下来我们看下用if不用while的。(末尾加上松手检测比while好多了)
1 #include<reg51.h> 2 3 #define uchar unsigned char 4 #define uint unsigned int 5 6 sbit WEI=P2^7; 7 sbit DUAN=P2^6; 8 9 sbit led0=P1^0; 10 sbit key0=P3^0; 11 12 uchar code Table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x00}; 13 // 0 1 2 3 4 5 6 7 8 9 A B C D E F 无显示 14 uchar num=0,temp; 15 void Delay1ms(); 16 void delay(int n); 17 18 void main() 19 { 20 DUAN=1; 21 P0=0x00; 22 DUAN=0; 23 WEI=1; 24 P0=0xfe; 25 WEI=0; 26 while(1) 27 { 28 //第一行 29 P3=0xfe; 30 temp=P3; 31 temp=temp&0xf0; 32 if(temp!=0xf0) 33 { 34 delay(5); 35 temp=P3; 36 temp=temp&0xf0; 37 if(temp!=0xf0) 38 { 39 temp=P3; 40 switch(temp) 41 { 42 case 0xee:num=1;break; 43 case 0xde:num=2;break; 44 case 0xbe:num=3;break; 45 case 0x7e:num=4;break; 46 } 47 48 // /*没有这里的话,如果按下某一行,就会一直进入上面这个while循环,即使松手也出不来, 49 // 有了它,不松手就一直在下面的循环,松手后就会改变temp的值,变为0xf0*/ 50 // while(temp!=0xf0) 51 // { 52 // temp=P3; 53 // temp=temp&0xf0; 54 // } 55 DUAN=1; 56 P0=Table[num-1]; 57 DUAN=0; 58 } 59 } 60 61 //第二行 62 P3=0xfd; 63 temp=P3; 64 temp=temp&0xf0; 65 if(temp!=0xf0) 66 { 67 delay(5); 68 temp=P3; 69 temp=temp&0xf0; 70 if(temp!=0xf0) 71 { 72 temp=P3; 73 switch(temp) 74 { 75 case 0xed:num=5;break; 76 case 0xdd:num=6;break; 77 case 0xbd:num=7;break; 78 case 0x7d:num=8;break; 79 } 80 // while(temp!=0xf0) 81 // { 82 // temp=P3; 83 // temp=temp&0xf0; 84 // } 85 DUAN=1; 86 P0=Table[num-1]; 87 DUAN=0; 88 } 89 } 90 91 //第三行 92 P3=0xfb; 93 temp=P3; 94 temp=temp&0xf0; 95 if(temp!=0xf0) 96 { 97 delay(5); 98 temp=P3; 99 temp=temp&0xf0; 100 if(temp!=0xf0) 101 { 102 temp=P3; 103 switch(temp) 104 { 105 case 0xeb:num=9;break; 106 case 0xdb:num=10;break; 107 case 0xbb:num=11;break; 108 case 0x7b:num=12;break; 109 } 110 // while(temp!=0xf0) 111 // { 112 // temp=P3; 113 // temp=temp&0xf0; 114 // } 115 DUAN=1; 116 P0=Table[num-1]; 117 DUAN=0; 118 } 119 } 120 121 //第四行 122 P3=0xf7; 123 temp=P3; 124 temp=temp&0xf0; 125 if(temp!=0xf0) 126 { 127 delay(5); 128 temp=P3; 129 temp=temp&0xf0; 130 if(temp!=0xf0) 131 { 132 temp=P3; 133 switch(temp) 134 { 135 case 0xe7:num=13;break; 136 case 0xd7:num=14;break; 137 case 0xb7:num=15;break; 138 case 0x77:num=16;break; 139 } 140 // while(temp!=0xf0) 141 // { 142 // temp=P3; 143 // temp=temp&0xf0; 144 // } 145 DUAN=1; 146 P0=Table[num-1]; 147 DUAN=0; 148 } 149 } 150 } 151 } 152 153 void delay(int n) 154 { 155 while(n--) 156 { 157 Delay1ms(); 158 } 159 } 160 void Delay1ms() //@12.000MHz 161 { 162 unsigned char i, j; 163 164 i = 2; 165 j = 239; 166 do 167 { 168 while (--j); 169 } while (--i); 170 }
不过这个矩阵键盘方法太麻烦了,浪费资源,看看清翔的或者别人的,都比这个简洁。