基于51单片机+DS1302+ LCD1602显示时间Proteus仿真
Posted perseverance52
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于51单片机+DS1302+ LCD1602显示时间Proteus仿真相关的知识,希望对你有一定的参考价值。
基于51单片机+DS1302+ LCD1602显示时间Proteus仿真
AT89C52
、LCD1602
、DS1302
、Proteus
仿真器件
实例代码
#include <reg51.h>
#include <string.h>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
#define delayNOP() {_nop_();_nop_();_nop_();_nop_();}
sbit SDA=P2^6; // DS1302数据线
sbit CLK=P2^5; // DS1302时钟线
sbit RST=P2^4; // DS1302复位线
//DS18B20数据端口定义
sbit DQ=P2^4; //DS18B20数据端口
sbit LCD_RS=P2^0; // LCD寄存器选择
sbit LCD_RW=P2^1; // LCD读写/写控制
sbit LCD_EN=P2^2; // LCD启用
uchar tCount=0;
//一年中每个月的天数,2月的天数由年份决定
uchar MonthsDays[]= {0,31,0,31,30,31,30,31,31,30,31,30,31};
//周日,每周一到周六(0,1-6)【读取DS1302时分别是1-7】
uchar *WEEK[]= {"SUN","MON","TUS","WEN","THU","FRI","SAT"};
//LCD显示缓冲
uchar LCD_DSY_BUFFER1[]= {"00-00-00 "};
uchar LCD_DSY_BUFFER2[]= {"00-00-00 "};
uchar DateTime[7]; //所读取的日期时间
uchar Adjust_flag=0; //当前调节的时间对像:秒,分,时,日,月,年(1,2,3,4,5,6)
uchar Change_Flag[]=" YMDHM";//(分,时,日,月,年)(不调节秒与周)
void DelayMS(uchar x)//延时
{ uchar i;
while(x--)
for(i=0; i<120; i++);
}
void Write_A_Byte_TO_DS1302(uchar x)//向DS1302写入一个字节
{ uchar i;
for(i=0; i<8; i++)
{ SDA=x&1;
CLK=1;
CLK=0;
x>>=1;
}
}
uchar Get_A_Byte_FROM_DS1302()//读取一个字节
{ uchar i,b,t;
for(i=0; i<8; i++)
{ b>>=1;
t=SDA;
b|=t<<7;
CLK=1;
CLK=0;
}
return b/16*10+b%16;//BCD码转换
}
uchar Read_Data(uchar addr)//指定位置读数据
{ uchar dat;
RST=0;
CLK=0;
RST=1;
Write_A_Byte_TO_DS1302(addr);
dat=Get_A_Byte_FROM_DS1302();
CLK=1;
RST=0;
return dat;
}
void Write_DS1302(uchar addr,uchar dat)//向某地址写入数据
{ CLK=0;
RST=1;
Write_A_Byte_TO_DS1302(addr);
Write_A_Byte_TO_DS1302(dat);
CLK=0;
RST=0;
}
void SET_DS1302()//设置时间
{ uchar i;
Write_DS1302(0x8e,0x00);
for(i=0; i<7; i++)
{
Write_DS1302(0X80+2*i,(DateTime[i]/10<<4)|(DateTime[i]%10));//日,月,周,年,写入 地址每次增2
}
Write_DS1302(0x8e,0x80);//加保护
}
void GetTime()//读取本地的时间
{
uchar i;
for(i=0; i<7; i++)
{
DateTime[i]=Read_Data(0x81+2*i);
}
}
//LCD驱动代码
bit LCD_Busy_Check()//LCD忙
{ bit result;
LCD_RS=0;
LCD_RW=1;
LCD_EN=1;
delayNOP();
result=(bit)(P0&0x80);
LCD_EN=0;
return result;
}
void Write_LCD_Command(uchar cmd) //写指令
{ while(LCD_Busy_Check());
LCD_RS=0;
LCD_RW=0;
LCD_EN=0;
_nop_();
_nop_();
P0=cmd;
delayNOP();
LCD_EN=1;
delayNOP();
LCD_EN=0;
}
void Write_LCD_Data(uchar dat)//写数据
{ while(LCD_Busy_Check());
LCD_RS=1;
LCD_RW=0;
LCD_EN=0;
P0=dat;
delayNOP();
LCD_EN=1;
delayNOP();
LCD_EN=0;
}
void Init_LCD()//LCD初始化
{ Write_LCD_Command(0x01);
DelayMS(5);
Write_LCD_Command(0x38);
DelayMS(5);
Write_LCD_Command(0x0c);
DelayMS(5);
Write_LCD_Command(0x06);
DelayMS(5);
}
void Set_LCD_POS(uchar pos)//设置显示位置
{ Write_LCD_Command(pos|0x80);
}
void Display_LCD_String(uchar p,uchar *s)//在LCD上显示字符串
{ uchar i;
Set_LCD_POS(p);
for(i=0; i<16; i++)
{ Write_LCD_Data(s[i]);
DelayMS(1);
}
}
void Format_DateTime(uchar d,uchar *a)//日期与时间值转换为数字字符
{ a[0]=d/10+'0';
a[1]=d%10+'0';
}
uchar isLeapYear(uint y)//判断是否为闰年
{ return (y%4==0&&y%100!=0)||(y%400==0);
}
void RefreshWeekDay()
{ uint i,d,w=5; //
for(i=2021; i<2021+DateTime[6]; i++)
{ d=isLeapYear(i)?366:365;
w=(w+d)%7;
}
d=0;
for(i=1; i<DateTime[4]; i++)
d+=MonthsDays[i];
d+=DateTime[3];
DateTime[5]=(w+d)%7+1;
}
//定时器0每秒刷新LCD显示
void T0_INT() interrupt 1
{ uchar i;
if(++tCount!=2) return;
tCount=0;//刷新
Format_DateTime(DateTime[6],LCD_DSY_BUFFER1);//年
Format_DateTime(DateTime[4],LCD_DSY_BUFFER1+3);//月
Format_DateTime(DateTime[3],LCD_DSY_BUFFER1+6);//日
Format_DateTime(DateTime[2],LCD_DSY_BUFFER2);//时
Format_DateTime(DateTime[1],LCD_DSY_BUFFER2+3);//分
Format_DateTime(DateTime[0],LCD_DSY_BUFFER2+6);//秒
Display_LCD_String(0x03,LCD_DSY_BUFFER1);//显示年月日,星期,时分秒
Set_LCD_POS(0x43);
for(i=0; i<14; i++)
{
Write_LCD_Data(LCD_DSY_BUFFER2[i]);
DelayMS(1);
}
}
//主程序
void main()
{
Init_LCD();//液晶初始化
IE=0X87;//允许INT0,T0中断
TR0=1;
while(1)
{ GetTime();
}
}
以上是关于基于51单片机+DS1302+ LCD1602显示时间Proteus仿真的主要内容,如果未能解决你的问题,请参考以下文章
51单片机 LCD1602+DS1302实时时钟+Proteus仿真
基于51单片机+DS1302万年历+LCD1602显示+按键播报时间+温控风扇+按键控灯