作业讲解

第三题:

先用定时器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 }

 不过这个矩阵键盘方法太麻烦了,浪费资源,看看清翔的或者别人的,都比这个简洁。