概要
用单片机实现数字时钟,要求采用串口进行时钟的设置和对闹钟的设定。
整体架构流程
一.首先,我们 ·要确定串口发送的数据帧格式,我这里采用的格式是->
1.当想发送的是“设置时间”时就发送这个格式的数据帧:S-hour:min:sec\n
2.当想发送的是“设定闹钟”时就发送这个格式的数据帧:D-hour:min:sec\n
分析:首个字节是确定发送数据的类型,如果是S就表明是“设置时间”的数据;否则,D就是“设定闹钟”的数据。hour-时、min-分、sec秒,比如你想设定时间从10:11:00开始计时,你就在串口助手中发送这一串字符串:“S-10:11:00\n”,如果想设定闹钟在10:15:00响铃就发送“D-10:15:00\n”来设定闹钟;
二、数据格式确定好后,咋们就开始编写程序实现我们的功能。
程序设计思路:
- 先编写出:数字时钟+LCD显示的功能模块程序
- 然后再编写:串口接送的功能模块程序
分析: 分步骤写程序是为了方便我们调试程序
三、烧录程序到开发板上进行调试
STC-ISP是一个既可以下载程序,又可以进行串口调试的软件
代码参考
#include <REG52.H>
#define uchar unsigned char
#define uint unsigned int
#define BUFFER_SIZE 11 // 假设接收缓冲区的大小为10个字节
uchar rx_buffer[BUFFER_SIZE]; // 接收缓冲区
uchar rx_index = 0; // 接收缓冲区索引
sbit LED=P2^0;
sbit Beep=P1^5;
sbit RS=P2^6;
sbit RW=P2^5;
sbit E=P2^7;
char hour=0,min=0,sec=0;//时分秒
char D_hour,D_min,D_sec;//闹钟时分秒
uchar con=0;
bit D_flag=0;
void delayms(uint ms)
{
uchar i;
while(ms--)
for(i=0;i<123;i++);
}
void w_com(uchar com)
{
RS=0;
RW=0;
E=1;
P0=com;
E=0;
delayms(1);
}
void w_dat(uchar dat)
{
RS=1;
RW=0;
E=1;
P0=dat;
E=0;
delayms(1);
}
void lcd_init()
{
delayms(10);
w_com(0x38);
delayms(10);
w_com(0x0c);
delayms(10);
w_com(0x06);
delayms(10);
w_com(0x01);
delayms(10);
w_com(0x38);
delayms(10);
}
void T0_inti()//T0定时1s
{
TMOD&=0xf0;
TMOD|=0x01;//方式一16位定时器
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;
TR0=0;
ET0=0;
}
void usart () //串口初始化 配置串口的波特率(T1)
{
SCON=0x50;
PCON&=0x7f;
TMOD&=0x0f;
TMOD|=0x20;
TH1=0xfd; //设置串口为9600波特率
TL1=0xfd;
ET1=0;
TR1=1; //T1定时器启用
EA=1; //打开总中断使能
ES=1; //打开串口中断使能
}
void ProcessReceivedData(unsigned char *data_d)
{
uchar hour_s,hour_g,min_s,min_g,sec_s,sec_g;
uchar D_hour_s,D_hour_g,D_min_s,D_min_g,D_sec_s,D_sec_g;
if(data_d[0]=='S')
{ TR0=0;
ET0=0;
hour_s=data_d[2]-'0';
hour_g=data_d[3]-'0';
hour=hour_s*10+hour_g;
min_s=data_d[5]-'0';
min_g=data_d[6]-'0';
min=min_s*10+min_g;
sec_s=data_d[8]-'0';
sec_g=data_d[9]-'0';
sec=sec_s*10+sec_g;
TR0=1 ;
ET0=1;
}
if(data_d[0]=='D')
{ D_flag=1;
D_hour_s=data_d[2]-'0';
D_hour_g=data_d[3]-'0';
D_hour=D_hour_s*10+D_hour_g;
D_min_s=data_d[5]-'0';
D_min_g=data_d[6]-'0';
D_min=D_min_s*10+D_min_g;
D_sec_s=data_d[8]-'0';
D_sec_g=data_d[9]-'0';
D_sec=D_sec_s*10+D_sec_g;
}
}
void sentdata()
{
uint i;
for(i=0;i<BUFFER_SIZE;i++)
{
SBUF=rx_buffer[i];
while(!TI);
TI=0;
}
}
void main()
{
T0_inti();
lcd_init();
usart ();
while(1)
{
w_com(0x84);
w_dat(hour/10+0x30);
w_dat(hour%10+0x30);
w_dat(':');
w_dat(min/10+0x30);
w_dat(min%10+0x30);
w_dat(':');
w_dat(sec/10+0x30);
w_dat(sec%10+0x30);
if(D_flag)
{
w_com(0xc0);
w_dat(D_hour/10+0x30);
w_dat(D_hour%10+0x30);
w_dat(':');
w_dat(D_min/10+0x30);
w_dat(D_min%10+0x30);
w_dat(':');
w_dat(D_sec/10+0x30);
w_dat(D_sec%10+0x30);
}
if((hour==D_hour&&min==D_min&&sec==D_sec)&&D_flag)//闹钟响应函数
{
Beep=0;
delayms(3000);
Beep=1;
}
}
}
void T0_EX0()interrupt 1//T0用于计时50ms*20=1s
{
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;
if(++con==20)//1s
{
con=0;
if(++sec==60)//1min
{
sec=0;
if(++min==60)//1hour
{ min=0;
if(++hour==24)//1day
hour=0;
}
}
}
}
void Serial_ISR() interrupt 4
{
if (RI) { // 接收中断标志置位
RI = 0; // 清除接收中断标志
rx_buffer[rx_index++] = SBUF; // 将接收到的数据存入缓冲区
// 检查是否接收到完整的数据包(例如,以换行符结束)
if (rx_buffer[rx_index - 1] == '\n' )
{
// 处理接收到的数据
sentdata();
rx_index=0;
ProcessReceivedData(rx_buffer);
}
}
}
调试与结果
下载好程序后,进入窗口调试窗口进行数据的发送。先发送时钟信息,然后再发送闹钟信息
.发送设置时钟的数据
.发送设置闹钟的数据
.实现效果
小结
提示:如果要用51单片机做出这个效果,硬件这方面晶振一定要是11.0592MHz,如果是开发板上的晶振是12MHz会导致发送的数据丢失、不准确