提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
一、实验要求
1.以单片机为硬件基础,以C51语言为设计语言编程实现电子日历功能。具体如下:
(1)显示年、月、日
(2)显示时、分、秒
2.:通过单片机上提供的按键,实现电子日历的“调时”及“调日期”和“调秒”功能
二、使用步骤
1.引入库
代码如下(示例):
/**
* @brief 使用LCD1602实现电子万年历
* @author不留名
* @date 2022-06-07 22:30:00
* @version 2.0
* */
#include"REG51.H"
#define uint unsigned int
typedef unsigned char uchar;
sbit RS=P2^0;
sbit RW=P2^1;
sbit E=P2^2;
sbit P2_3=P2^3;
sbit P2_4=P2^4;
sbit P2_5=P2^5;
uint Flag=0;//Flag用来判断按键按了几下
//闰年只影响2月份。因此只要用if进行判断就可以得到闰年的2月份
uint Pmonthnum[]={00,31,28,31,30,31,30,31,31,30,31,30,31};//平年数
uchar SegCode[]={0x3f,0x06,0x5b,0x4f};//用于显示按键按了几下
uint year=2020,month=2,day=28;
uint hour=23,minute=59,second=41;
uchar num=0,xq=4,count=0;
uchar code week[][3]={"MON","TUE","WED","THR","FRI","SAT","SUN"};
uchar Table1[]={" 2020-02-28 FRI"};
uchar Table2[]={"23:59:11"};
void DelayMs(uint ms);
void write_com(uchar command)//写指令
{
RS=0;
RW=0;
E=0;
P1=command;
E=1;
DelayMs(1);
E=0;
}
void write_data(uchar date)//写数据
{
RS=1;
RW=0;
E=0;
P1=date;
E=1;
DelayMs(1);
E=0;
}
void disp1(uchar add,uchar content)
{
uchar shi,ge;
shi=content/10;
ge=content%10;
write_com(add);
DelayMs(2);
write_data(shi+0x30);
DelayMs(2);
write_data(ge+0x30);
DelayMs(2);
}
void disp2(uchar add,uchar content)
{
uchar qian,bai,shi,ge;
qian=content/1000;
bai=(content/100)%10;
shi=content%100/10;
ge=content%10;
write_com(add);
DelayMs(2);
write_data(qian+0x30);
DelayMs(2);
write_data(bai+0x30);
DelayMs(2);
write_data(shi+0x30);
DelayMs(2);
write_data(ge+0x30);
DelayMs(2);
}
void Init()
{
write_com(0x38);//设置16*2显示,5*7点阵,8位数据接口
write_com(0x0c);//设置开显示,不显示光标
write_com(0x06);//写一个字符后地址++
write_com(0x01);//显示清0,数据指针清0
DelayMs(1);
IE=0x82;//使用T0
TMOD=0x01;//方式一
TH0=15536/256;
TL0=15536%256;
TR0=1;
write_com(0x80);//第一行
for(num=0;num<15;num++)
{
write_data(Table1[num]);
DelayMs(2);
}
write_com(0xc4);//第二行
for(num=0;num<8;num++)
{
write_data(Table2[num]);
DelayMs(2);
}
write_com(0x8c);//显示星期
for(num=0;num<3;num++)
{
write_com(week[xq][num]);
DelayMs(1);
}
}
void main(void)
{
Init();
P3=0x00;
while(1)
{
if(P2_3==0)
{
DelayMs(20);//延时消抖
if(P2_3==0)
{
while(P2_3==0);//松手检测
Flag++;
if(Flag==4)
Flag=0;
}
}
switch(Flag)
{
case 0:break;
case 1:P3=SegCode[1];EA=0;
if(P2_4==0){DelayMs(20);if(P2_4==0){while(P2_4==0);second++;}}
if(P2_5==0){DelayMs(20);if(P2_5==0){while(P2_5==0);second--;}}
EA=1;break;
case 2:P3=SegCode[2];EA=0;
if(P2_4==0){DelayMs(20);if(P2_4==0){while(P2_4==0);minute++;}}
if(P2_5==0){DelayMs(20);if(P2_5==0){while(P2_5==0);minute--;}}
EA=1;break;
case 3:P3=SegCode[3];
if(P2_4==0){DelayMs(20);if(P2_4==0){while(P2_4==0);hour++;}}
if(P2_5==0){DelayMs(20);if(P2_5==0){while(P2_5==0);hour--;}}
EA=1;break;
default:break;
}
disp1(0xc4,hour);
disp1(0xc7,minute);
disp1(0xca,second);
}//防止跑飞
}
void Timer0(void)interrupt 1
{
TH0=15536/256;
TL0=15536%256;
count++;
if(count==20)
{
count=0;
second++;
if(second>=60)
{
second=0;
minute++;
if(minute>=60)
{
minute=0;
hour++;
if(hour>=24)
{
hour=0;
xq++;
if(xq==7)
xq=0;
if(((year%4==0&&year%100!=0)||year%400==0)&&month==2)
{ //如果是闰年,二月份的天数应该为29
day++;
if(day>29)
{
day=1;
month++;
if(month>12)
{
year++;
month=1;
if(year>9999)
year=0;
disp2(0x81,year);
}
disp1(0x86,month);
}
disp1(0x89,day);
write_com(0x8c);
for(num=0;num<3;num++)
write_data(week[xq][num]);
}
else//不是闰年
{
day++;
if(day>Pmonthnum[month])
{
day=1;
month++;
if(month>12)
{
year++;
month=1;
if(year>9999)
year=0;
disp2(0x81,year);
}
disp1(0x86,month);
}
disp1(0x89,day);
write_com(0x8c);
for(num=0;num<3;num++)
write_data(week[xq][num]);
}
}
}
}
}
}
void DelayMs(uint ms)
{
uint i=0;
do{
for(;i<113;i++);
}while(--ms);
}
三、实验原理图
总结
实验中遇到的最大的困难就是对于LCD1602的不熟悉。因此,我花了2小时来进行学习LCD1602基础知识的学习。因为上次实验,让我发现了proteus上仿真可能存在定时不准确的情况。因此本次实验proteus只是起到辅助的作用,单片机起到了主要作用。本次实验也只是对于LCD1602最基本的运用。当我LCD1602运用熟练之后,我也会学习功能更加丰富的单片机液晶显示模块。
最后,建议大家在进行学习单片机的时候,可以自己买一块开发版。