一、任务要求
在CT107D单片机上,设计程序:用于本地和远程控制现场灯光的开关,并能通过串口远程读取工厂的系统运行时间。
1.设计系统初始化函数,关闭蜂鸣器和继电器等无关设备;
2.设计设备检测函数,首先检测LED指示灯,从L1~L8依次逐个点亮,再依次逐个熄灭;然后检测数码管,从左到右依次点亮数码管的所有段码,再依次从左到右熄灭。
3.系统从上电开始显示系统运行时间,从00时00分00秒开始,显示格式:00-00-00;
4.八个LED指示灯分为两组:L1——L4为远程控制组,L7——L8为本地控制组。远程控制组的指示灯由上位机通过串口发送命令控制开关,本地控制组的指示灯由独立按键控制开关。按键检测需做去抖动处理,松开有效,按键S5控制S7,按键S4控制L8.
串口方面
1.串口工作在8位UART模式,波特率为9600BPS;
2.上位机通过串口控制下位机的L1——L4指示灯和读取系统运行时间;
3.控制命令为一个字节,高四位为命令类型,低四位为执行参数;
4.控制灯光开关命令中,低四位每一位控制一个LED指示灯的开关,无返回值;
5.读取运行时间命令中,低四位保留,返回3个字节的时间数据,用16进制的BCD码表示,先发时,再发分,后发秒。如果系统运行时间为12时24分16秒,收到读取时间命令后,返回 0x12 0x24 0x16。
二、实验结果
上位机通过串口控制下位机的L1——L4指示灯和读取系统运行时间:
串口发送a0,单片机LED0指示灯亮:
三、参考代码
#include <STC15F2K60S2.H>
sbit S5 = P3^2;
sbit S4 = P3^3;
unsigned char stat_led = 0xff;
unsigned char count = 0;
unsigned char t_s = 0;
unsigned char t_m = 0;
unsigned char t_h = 0;
unsigned char command = 0x00;
unsigned char code SEG[18] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xc0,0x86,0x8e,0xbf,0x7f};
/*========时间延迟函数================
功能:精准延时50us误差0us。
参数:n--用户需求的时间。
返回:无
设计:张智洪(2022年3月27日)
======================================*/
void m_delay(unsigned char n) //满足用户需求的延迟时间n毫秒
{
unsigned char i,j;
for(i = n; i > 0; i--)
for(j = 110; j > 0; j--);
}
/*========时间延迟函数================
功能:延时t--个时间长度。
参数:n--用户需求的时间。
返回:无
设计:张智洪(2022年3月27日)
======================================*/
void delay(unsigned char t)
{
while(t--);
while(t--);
}
/*========选择锁存器函数================
功能:选择相关设备的控制。
参数:channel--相应信道。
返回:无
设计:张智洪(2022年3月27日)
======================================*/
void select_HC573(unsigned char channel)
{
switch(channel)
{
case 4:
P2 = (P2 & 0x1f) | 0x80; //Y4输出0,选择LED指示灯控制
break;
case 5:
P2 = (P2 & 0x1f) | 0xa0; //Y5输出0,选择蜂鸣器与继电器控制
break;
case 6:
P2 = (P2 & 0x1f) | 0xc0; //Y6输出0,选择数码管位选控制
break;
case 7:
P2 = (P2 & 0x1f) | 0xe0; //Y7输出0,选择数码管段码控制
break;
case 0:
P2 = (P2 & 0x1f) | 0xff; //Y所有锁存器不选择
break;
}
}
/*========初始化系统函数================
功能:关闭蜂鸣器与继电器等无关设备。
参数:无
返回:无
设计:张智洪(2022年3月27日)
======================================*/
void initial_system()
{
select_HC573(5);
P0 = 0x00;
select_HC573(6);
P0 = 0x00;
select_HC573(4);
P0 = stat_led;
select_HC573(0);
}
/*========LED指示灯显示模块检测函数=====
功能:逐个检查LED指示灯是否正常工作。
参数:无
返回:无
设计:张智洪(2022年3月27日)
=======================================*/
void check_LED()
{
unsigned char i;
select_HC573(4);
for(i = 0; i < 9; i++)
{
stat_led = 0xfe << i;
P0 = stat_led;
m_delay(200);
}
for(i = 0; i < 9; i++)
{
stat_led = ~(0xfe << i);
P0 = stat_led;
m_delay(200);
}
select_HC573(0);
}
/*========时间显示模块检测函数=========
功能:逐个检查数码管是否正常工作。
参数:无
返回:无
设计:张智洪(2022年3月27日)
======================================*/
void check_SEG()
{
unsigned char i;
select_HC573(7);
P0 = 0x00;
for(i = 0; i < 9; i++)
{
select_HC573(6);
P0 = ~(0xfe << i); //逐个点亮数码管
m_delay(200);
}
for(i = 0; i < 9; i++)
{
select_HC573(6);
P0 = 0xfe << i; 逐个关闭数码管
m_delay(200);
}
select_HC573(0);
}
/*========数码管显示控制模块函数=========
功能:控制数码管输出函数。
参数:pos--控制数码管位选,val--控制数码管显示的内容。
返回:无
设计:张智洪(2022年3月27日)
======================================*/
void out_SEG_bit(unsigned char val,unsigned char pos)
{
P0 = 0xff; //消隐
select_HC573(6);
P0 = 0x01 << pos;
select_HC573(7);
P0 = val;
}
/*========定时器0初始化模块函数=========
功能:初始化定时器各项参数。
参数:无
返回:无
设计:张智洪(2022年3月27日)
======================================*/
void initial_Timer0()
{
TMOD = 0x21; //确保程序后面的串口开启时不会使定时器0关闭。
TH0 = (65535 - 50000) / 256;
TL0 = (65535 - 50000) % 256;
TR0 = 1;
ET0 = 1;
EA = 1;
}
/*========串口初始化模块函数=========
功能:将串口初始化位模式1,波特率位9600,允许接收。
参数:无
返回:无
设计:张智洪(2022年3月27日)
======================================*/
void initial_URAT()
{
TMOD = 0x21;//T0和T1一起赋值!设置定时器1的工作模式并保持打开定时器0。
TH1 = 0xfd; // TH1和TL1:设置波特率参数9600。
TL1 = 0xfd;
TR1 = 1; //打开定时器1。
SCON = 0x50; // //0101 0000,选择8位的URAT工作模式,允许接收数据。
AUXR = 0x00;
ES = 1;//打开串口中断开关。
EA = 1; //打开总中断开关。
}
/*========定时器0中断服务模块函数=========
功能:利用中断1实现秒、分和时 计数。
参数:count--50ms一次,t_s--秒,t_m--分,t_h--时。
返回:无
设计:张智洪(2022年3月27日)
======================================*/
void service_Timer0() interrupt 1
{
TH0 = (65535 - 50000) / 256;
TL0 = (65535 - 50000) % 256;
count++;
if(count == 20)
{
t_s++;
count = 0;
}
if(t_s == 60)
{
t_m++;
t_s = 0;
}
if(t_m == 60)
{
t_h++;
t_m = 0;
}
}
/*========数码管时间延迟函数================
功能:特定数码管延时相应时间。
参数:t--延时长度。
返回:无
设计:张智洪(2022年3月27日)
======================================*/
void SEG_delay(unsigned char t)
{
while(t--);
}
/*========数码管显示模块函数=========
功能:数码管按照 时:分:秒 格式输出函数。
参数:pos--控制数码管位选,val--控制数码管显示的内容。
返回:无
设计:张智洪(2022年3月27日)
======================================*/
void SEG_action()
{
out_SEG_bit(SEG[t_s % 10],7);
SEG_delay(500);
out_SEG_bit(SEG[t_s / 10],6);
SEG_delay(500);
out_SEG_bit(SEG[16],5);
SEG_delay(500);
out_SEG_bit(SEG[t_m % 10],4);
SEG_delay(500);
out_SEG_bit(SEG[t_m / 10],3);
SEG_delay(500);
out_SEG_bit(SEG[16],2);
SEG_delay(500);
out_SEG_bit(SEG[t_h % 10],1);
SEG_delay(500);
out_SEG_bit(SEG[t_h / 10],0);
SEG_delay(500);
}
/*========定时器1中断服务模块函数=========
功能:串行接口接收的内容。
参数:command--用户命令,用于打开某个LED指示灯。
返回:无
设计:张智洪(2022年3月27日)
======================================*/
void service_URAT() interrupt 4
{
if(RI == 1) //RI--串行接口接收完成中断的标志。
{
command = SBUF;
RI = 0;
}
}
/*========串口发送单字节模块函数=========
功能:串口向上位机发送一个字节。
参数:dat--要发送的内容。
返回:空
设计:张智洪(2022年3月27日)
======================================*/
void send_byte(unsigned char dat)
{
SBUF = dat;
while(TI == 0); //TI--串行接口发送完成中断的标志。
TI = 0;
}
/*========上位机命令解析执行模块函数=========
功能:接受上位机的数据并保持在command变量中。
参数:无
返回:空
设计:张智洪(2022年3月27日)
======================================*/
void execute_command()
{
if(command != 0x00)
{
switch(command & 0xf0) //取出命令类型。
{
case 0xa0: //远程灯光控制命令。
select_HC573(4);
stat_led = (stat_led | 0x0f) & (~command | 0xf0); 保留P0高四位,改变低四位,command保留低四位。
P0 = stat_led;
select_HC573(0);
command = 0x00;
break;
case 0xb0:
send_byte((t_h / 10 << 4) | (t_h % 10)); //读取 现场 系统时间 命令。
send_byte((t_m / 10 << 4) | (t_m % 10));
send_byte((t_s / 10 << 4) | (t_s % 10));
command = 0x00;
break;
}
}
}
/*========独立按键控制LED指示灯模块函数=======
功能:独立按键取S4和S5部分控制LED7和LED8。
参数:无
返回:无
设计:张智洪(2022年3月27日)
=============================================*/
void scan_button_keys()
{
if(S4 == 0)
{
delay(60000);
if(S4 == 0)
{
while(S4 == 0)
{
SEG_action();
}
select_HC573(4);
stat_led = (stat_led | 0x80) & (~stat_led | 0x7f); //此行代码意思为:第一种情况:LED7熄灭的情况下,按键S4按着不动是不会跳转亮灯状态的;
//第二种情况:LED7亮灯的情况下,按键S4 按着不动也不会跳转到熄灭状态。
P0 = stat_led;
select_HC573(0);
}
}
if(S5 == 0)
{
delay(60000);
if(S5 == 0)
{
while(S5 == 0)
{
SEG_action();
}
select_HC573(4);
stat_led = (stat_led | 0x40) & (~stat_led | 0xbf); //此行代码意思为:第一种情况:LED8熄灭的情况下,按键S5按着不动是不会跳转亮灯状态的;
//第二种情况:LED8亮灯的情况下,按键S5 按着不动也不会跳转到熄灭状态。
P0 = stat_led;
select_HC573(0);
}
}
}
void main()
{
initial_system();
check_LED();
check_SEG();
initial_Timer0();
initial_URAT();
while(1)
{
execute_command();
SEG_action();
scan_button_keys();
}
}