在前面内容,我们已经学习了大部分的51单片机基础知识,但是,我们缺乏对这块板子的综合引用,现在,让我们一起来做一题综合题,比较彻底的使用51单片机中的各个功能
上面就是题目的要求了,根据题目要求,我将解答简单分为这几部分:
1:初始化系统,写好锁存器选择函数,定义好变量。
2:检查灯和数码管
3:对定时器T0和T1,还有UART串口进行配置
4:让数码管动态显示系统运行时间
5:通过键盘和串口对LED灯进行控制
6:主函数
接下来,我也将以这个顺序来讲解我对这题的体悟
1:初始化系统,写好锁存器选择函数,定义好变量。
这一步比较简单,主要是将后面需要用到的一些变量先定义好,要注意的是,我们在写寄存器选择时,注意要多写一个不选择任何锁存器的选项,在后续代码中,通过这个选择,可以帮我们避开一些错误。
#include "reg52.h"
sfr AUXR = 0x8e;
sbit S5 = P3^2;
sbit S4 = P3^3;
unsigned char code SMG[18]={0xc0,0xf9,
0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,
0x88,0x80,0xc6,0xc0,0x86,0x8e,0xbf,0x7f};
unsigned int count;
unsigned char stat_LED = 0xff;
unsigned char s;
unsigned char m;
unsigned char h;
unsigned char command;
//选择锁存器和初始化系统------------------------
void SelectHC573(unsigned char channel)
{
switch(channel)
{
case 4:
P2 = (P2 & 0x1f) | 0x80;
break;
case 5:
P2 = (P2 & 0x1f) | 0xa0;
break;
case 6:
P2 = (P2 & 0x1f) | 0xc0;
break;
case 7:
P2 = (P2 & 0x1f) | 0xe0;
break;
case 0:
P2 = (P2 & 0x1f) | 0x00;
break;
}
}
void InitSystem()
{
SelectHC573(5);
P0 = 0x00;
SelectHC573(4);
P0 = 0xff;
SelectHC573(0);
}
2:检查灯和数码管
在检查灯和数码管时,我们要注意的是题目要求的一位一位亮起来,也就是到最后是所有的灯(数码管)都亮起来的,所以在这里,我们需要使用左移符号了,通过循环和左移符,我们可以实现让灯(数码管)从1111 1110,到1111 1100然后再一位一位变成0000 0000,每一次的变化中间的时间我们可以用一个delay函数来决定。而且,在这里,我们需要先将灯的状态赋值给stat_LED然后再给P0,不然的话我们可能会出现P0混乱的现象,因为P0是要用在多个地方的。当我们要将灯(数码管)灭掉的时候,我们对他取反就可以了。
void Delay(unsigned int t)
{
while(t--);
}
void CheckLED()
{
unsigned char i = 0;
SelectHC573(4);
for (i = 1;i <= 8;i++)
{
stat_LED = 0xfe <<i;
P0 = stat_LED;
Delay(60000);
}
for (i = 1;i <= 8;i++)
{
stat_LED = ~(0xfe <<i);
P0 = stat_LED;
Delay(60000);
}
SelectHC573(0);
}
void CheckSMG()
{
unsigned char i = 0;
for (i = 1;i <= 8;i++)
{
SelectHC573(7);
P0 = 0x00;
SelectHC573(6);
P0 = ~(0xfe << i);
Delay(60000);
}
for (i = 1;i <= 8;i++)
{
SelectHC573(7);
P0 = 0x00;
SelectHC573(6);
P0 = 0xfe << i;
Delay(60000);
}
SelectHC573(0);
}
3:对定时器T0和T1,还有UART串口进行配置
要实现后面的种种功能,定时器是必不可少的。关于定时器的初始化和定数服务函数的书写,是比较基础的部分,我们直接给出代码吧。注意,在定时服务函数中,我们需要对定时初值进行重组。
void InitT0()
{
TMOD = 0x21;
TH0 = (65535 - 50000) / 256;
TL0 = (65535 - 50000) % 256;
EA = 1;
TR0 = 1;
ET0 = 1;
}
void ServeT0() interrupt 1
{
TH0 = (65535 - 50000) / 256;
TL0 = (65535 - 50000) % 256;
count++;
if(count == 20)
{
s++;
count = 0;
}
if(s == 60)
{
m++;
s = 0;
}
if(m == 60)
{
h++;
m = 0;
}
}
void InitUart()
{
TMOD = 0x21;
TH1 = 0xfd;
TL1 = 0xfd;
AUXR = 0x00;
SCON = 0x50;
EA = 1;
ES = 1;
TR1 = 1;
}
void ServeUart() interrupt 4
{
TH1 = 0xfd;
TL1 = 0xfd;
if(RI == 1)
{
RI = 0;
command = SBUF;
}
}
void Sending(unsigned char dat)
{
SBUF = dat;
while(TI == 0);
TI = 0;
}
4:让数码管动态显示系统运行时间
接下来,是如何让数码管显示系统的运行时间,在上面,我们已经让系统的时间通过定时器来计算,而我们要动态显示数码管,我们需要运用前面的知识,利用余晖效应我们可以实现数码管的动态显示。
void ShowSMGOnly(unsigned char value,unsigned char location)
{
P0 = 0xff;
SelectHC573(7);
P0 = value;
SelectHC573(6);
P0 = 0x01 << location;
SelectHC573(0);
}
void DisplayTime()
{
ShowSMGOnly(SMG[s%10],7);
Delay(500);
ShowSMGOnly(SMG[s/10],6);
Delay(500);
ShowSMGOnly(SMG[16],5);
Delay(500);
ShowSMGOnly(SMG[m%10],4);
Delay(500);
ShowSMGOnly(SMG[m/10],3);
Delay(500);
ShowSMGOnly(SMG[16],2);
Delay(500);
ShowSMGOnly(SMG[h%10],1);
Delay(500);
ShowSMGOnly(SMG[h%10],0);
Delay(500);
}
5:通过键盘和串口对LED灯进行控制
这是这一题里面较难的部分,他需要用到逻辑门的运算规则。首先,我们先来写键盘控制L7,L8的代码。为了消除抖动,我们写一个延时函数,但是这个延时函数里的while(t--)不能像之前那样,我们需要在函数里面加入时间显示的函数,以保证在检查键盘的时候,数码管依旧在显示时间不会暂停或停止。然后后面的松手检测也是一样。在这个函数中,我们对stat_LED利用逻辑门直接定义,做到只改变一位而其他位不发生改变。我们就以 stat_LED = (stat_LED & 0xbf) | (~stat_LED & 0x40); 为例子进行解释:
首先,(stat_LED & 0xbf),0xbf也就是1011 1111,1与上任何数就是任何数,0与上任何数都是0,这就保证这个运算的结果第7位是0而其他位置保持不变,但这也仅仅是开灯而已,我们还需要关灯。后半部分(~stat_LED & 0x40)0x40也就是0100 0000,stat_LED本来第7位是0的时候,取反以后第7位是1,运算以后第7位还是1,当stat_LED本来第7位时1的时候,取反以后第7位时0,运算以后第7位是0,接着最后运算时,第7位就相当于取反,而其他位不变,非常巧妙!另外一个也是相同。
而通过串口控制L1到L4,首先我们先判断传输过来的不是空信号,防止无意义的无限发送数据过来,接着我们将锁存器调为4,然后利用switch语句来判断传输过来的信号高四位是a还是b,通过逻辑门保留高四位,将第四位全部变成0。接着,当传输过来的信号高四位是a时,我们先保留灯原来高四位的状态,由于我们的命令是1开灯0关灯,和电路板刚好相反,所以我们先对命令进行取反,接着利用逻辑门保存低四位,最后综合运算以后,我们就可以做到不影响高四位的情况下,对低四位进行改变,然后来控制灯。接着我们将数值赋给P0,关闭所有锁存器,将命令赋值为0x00,防止无限的发送数据过来。
而下面的数据发送,我们需要用到上面的Sending函数。我需要发送时分秒,高四位显示十位数,低四位显示个位数,所以我们需要用到移位符。将十位数左移4位移到高四位,接着或上个位数,我们就能接收到系统时间了。最后,我们还需要将命令改为0x00,防止无限发送数据。
void DelaySMG(unsigned int t)
{
while(t--)
{
DisplayTime();
}
}
void ScanKey()
{
if(S5 == 0)
{
DelaySMG(100);
if(S5 == 0)
{
while(S5 == 0)
{
DisplayTime();
}
SelectHC573(4);
stat_LED = (stat_LED & 0xbf) | (~stat_LED & 0x40);
P0 = stat_LED;
SelectHC573(0);
}
}
if(S4 == 0)
{
DelaySMG(100);
if(S4 == 0)
{
while(S4 == 0)
{
DisplayTime();
}
SelectHC573(4);
stat_LED = (stat_LED & 0x7f) | (~stat_LED & 0x80);
P0 = stat_LED;
SelectHC573(0);
}
}
}
void ControlLED()
{
if(command != 0x00)
{
SelectHC573(4);
switch(command & 0xf0)
{
case 0xa0:
stat_LED = (stat_LED | 0x0f) & (~command | 0xf0);
P0 = stat_LED;
SelectHC573(0);
command = 0x00;
break;
case 0xb0:
Sending(h/10 <<4 | h%10);
Sending(m/10 <<4 | m%10);
Sending(s/10 <<4 | s%10);
SelectHC573(0);
command = 0x00;
break;
}
}
}
6:主函数
最后就是主函数啦,主函数没什么可以说的,直接看代码吧
void main()
{
InitSystem();
CheckLED();
CheckSMG();
InitT0();
InitUart();
while(1)
{
DisplayTime();
ScanKey();
ControlLED();
}
}
最后的最后的全部代码,这一次,我终于大概的了解了逻辑门在51中的应用啦!
#include "reg52.h"
sfr AUXR = 0x8e;
sbit S5 = P3^2;
sbit S4 = P3^3;
unsigned char code SMG[18]={0xc0,0xf9,
0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,
0x88,0x80,0xc6,0xc0,0x86,0x8e,0xbf,0x7f};
unsigned int count;
unsigned char stat_LED = 0xff;
unsigned char s;
unsigned char m;
unsigned char h;
unsigned char command;
//选择锁存器和初始化系统------------------------
void SelectHC573(unsigned char channel)
{
switch(channel)
{
case 4:
P2 = (P2 & 0x1f) | 0x80;
break;
case 5:
P2 = (P2 & 0x1f) | 0xa0;
break;
case 6:
P2 = (P2 & 0x1f) | 0xc0;
break;
case 7:
P2 = (P2 & 0x1f) | 0xe0;
break;
case 0:
P2 = (P2 & 0x1f) | 0x00;
break;
}
}
void InitSystem()
{
SelectHC573(5);
P0 = 0x00;
SelectHC573(4);
P0 = 0xff;
SelectHC573(0);
}
//检查灯和数码管----------------------------------
void Delay(unsigned int t)
{
while(t--);
}
void CheckLED()
{
unsigned char i = 0;
SelectHC573(4);
for (i = 1;i <= 8;i++)
{
stat_LED = 0xfe <<i;
P0 = stat_LED;
Delay(60000);
}
for (i = 1;i <= 8;i++)
{
stat_LED = ~(0xfe <<i);
P0 = stat_LED;
Delay(60000);
}
SelectHC573(0);
}
void CheckSMG()
{
unsigned char i = 0;
for (i = 1;i <= 8;i++)
{
SelectHC573(7);
P0 = 0x00;
SelectHC573(6);
P0 = ~(0xfe << i);
Delay(60000);
}
for (i = 1;i <= 8;i++)
{
SelectHC573(7);
P0 = 0x00;
SelectHC573(6);
P0 = 0xfe << i;
Delay(60000);
}
SelectHC573(0);
}
//定时器与串口配置------------------------------
void InitT0()
{
TMOD = 0x21;
TH0 = (65535 - 50000) / 256;
TL0 = (65535 - 50000) % 256;
EA = 1;
TR0 = 1;
ET0 = 1;
}
void ServeT0() interrupt 1
{
TH0 = (65535 - 50000) / 256;
TL0 = (65535 - 50000) % 256;
count++;
if(count == 20)
{
s++;
count = 0;
}
if(s == 60)
{
m++;
s = 0;
}
if(m == 60)
{
h++;
m = 0;
}
}
void InitUart()
{
TMOD = 0x21;
TH1 = 0xfd;
TL1 = 0xfd;
AUXR = 0x00;
SCON = 0x50;
EA = 1;
ES = 1;
TR1 = 1;
}
void ServeUart() interrupt 4
{
TH1 = 0xfd;
TL1 = 0xfd;
if(RI == 1)
{
RI = 0;
command = SBUF;
}
}
void Sending(unsigned char dat)
{
SBUF = dat;
while(TI == 0);
TI = 0;
}
//数码管运行时间-------------
void ShowSMGOnly(unsigned char value,unsigned char location)
{
P0 = 0xff;
SelectHC573(7);
P0 = value;
SelectHC573(6);
P0 = 0x01 << location;
SelectHC573(0);
}
void DisplayTime()
{
ShowSMGOnly(SMG[s%10],7);
Delay(500);
ShowSMGOnly(SMG[s/10],6);
Delay(500);
ShowSMGOnly(SMG[16],5);
Delay(500);
ShowSMGOnly(SMG[m%10],4);
Delay(500);
ShowSMGOnly(SMG[m/10],3);
Delay(500);
ShowSMGOnly(SMG[16],2);
Delay(500);
ShowSMGOnly(SMG[h%10],1);
Delay(500);
ShowSMGOnly(SMG[h%10],0);
Delay(500);
}
//控制LED-----------
void DelaySMG(unsigned int t)
{
while(t--)
{
DisplayTime();
}
}
void ScanKey()
{
if(S5 == 0)
{
DelaySMG(100);
if(S5 == 0)
{
while(S5 == 0)
{
DisplayTime();
}
SelectHC573(4);
stat_LED = (stat_LED & 0xbf) | (~stat_LED & 0x40);
P0 = stat_LED;
SelectHC573(0);
}
}
if(S4 == 0)
{
DelaySMG(100);
if(S4 == 0)
{
while(S4 == 0)
{
DisplayTime();
}
SelectHC573(4);
stat_LED = (stat_LED & 0x7f) | (~stat_LED & 0x80);
P0 = stat_LED;
SelectHC573(0);
}
}
}
void ControlLED()
{
if(command != 0x00)
{
SelectHC573(4);
switch(command & 0xf0)
{
case 0xa0:
stat_LED = (stat_LED | 0x0f) & (~command | 0xf0);
P0 = stat_LED;
SelectHC573(0);
command = 0x00;
break;
case 0xb0:
Sending(h/10 <<4 | h%10);
Sending(m/10 <<4 | m%10);
Sending(s/10 <<4 | s%10);
SelectHC573(0);
command = 0x00;
break;
}
}
}
//主函数-------------
void main()
{
InitSystem();
CheckLED();
CheckSMG();
InitT0();
InitUart();
while(1)
{
DisplayTime();
ScanKey();
ControlLED();
}
}