介绍
LCD12864大数字万年历电子钟设计,用了一个多星期时间,经过实物实测,每月时间相差几分钟,这是时钟走时芯片决定的,温度显示还算正常。
图片
代码
#include
#include
//#include
#include
#define uchar unsigned char
#define uint unsigned int
/******LCD12864通讯端口******/
sbit RS_LCD12864=P2^7; //定义选择显示类型, 定义数据或指令,1=数据,0=指令
sbit RW_LCD12864=P2^6; //定义读写信号控制端, 定义读或写??1=读,??0=写
sbit EN_LCD12864=P2^5; //定义数据锁存信号, 定义使能操作, 1=能,??0=否
#define LCD12864_Databus P0 //定义数据端
#define sc0 0
#define sc1 1
uchar DS1302_flag; //定义DS1302RAM中是否写数的标志位,第一次开机初始化后RAM中写1
sbit CS1=P2^4; //定义选择芯片右半屏信号
sbit CS2=P2^3; //定义选择芯片左半屏信号
/*******DS1302时钟端口******/
sbit SCLK=P2^0; //DS1302时钟口
sbit DATA=P2^1; //DS1302串口数据
sbit RST=P2^2; //DS1302的复位口
uchar code Write_RTC_ADDR[7]={0x80,0x82,0x84,0x86,0x88,0x8a,0x8c};
uchar code READ_RTC_ADDR[7] ={0x81,0x83,0x85,0x87,0x89,0x8b,0x8d};
uchar TIME[7]={0, 0x38, 0x15, 0x25, 0x05, 0x03, 0x22};
//2022年5月25星期3,15:38:00
/***********DS18B20**********/
sbit DQ=P3^7; //温度探测口
uchar fb; //文字反白标示
uint tempvalue; //温度值,此变量若为uchar则温度不正常
uchar Temp_Flag; //温度正负标志
/***************按键端口************/
sbit set =P1^0; //设置
sbit key1=P1^1; //加
sbit key2=P1^2; //减
sbit key3=P1^3; //蜂鸣开关
sbit key4=P1^4; //背光开关
uchar setflag=0; //按键计数,决定调节的日期和时间
sbit bl=P3^5; //背光控制端
sbit bz=P3^6; //蜂鸣控制端
uchar tempa; //调时
/*********农历部分********/
#define uint unsigned int
char sec,min,hour,day,month,year,week; //定义全局变量,秒,分,时,日,月,年和星期
bit century; //世纪位标志,0为20世纪,1为19世纪
uchar sec_count=0;//定义定时计数,当sec_count==20时,秒加一
code uchar table_week[12]={0,3,3,6,1,4,6,2,5,0,3,5}; //月修正数据表
code uchar day_code1[9]={0x0,0x1f,0x3b,0x5a,0x78,0x97,0xb5,0xd4,0xf3};//月份数据表
code uint day_code2[3]={0x111,0x130,0x14e};
bit c_moon;
data uchar year_moon,month_moon,day_moon;
/*******函数声明********/
//读取数据表中农历月的大月或小月,如果该月为大返回1,为小返回0
bit get_moon_day(uchar month_p,uint table_addr);
void Conversion(bit c,char year,char month,char day);//输入阳历数据,输出阴历数据
void Conver_week(); //输入BCD阳历数据,输出BCD星期数据
void delay_ms(uint x);
void Lcd12864_BusyChk();
void set_xy(unsigned char x,unsigned char y);
/*************************************************************************************
* 函数名称 :Conversion
* 功能描述 :输入阳历数据,输出阴历数据(只允许1901-2099年)
* 参数 :参数名称
****************************************************************************************/
void Conversion(bit c,char year,char month,char day)
{
//c=0 为21世纪,c=1 为19世纪 输入输出数据均为BCD数据
uchar temp1,temp2,temp3,month_p;
uint temp4,table_addr;
bit flag2,flag_y;
//定位数据表地址
if(c==0) { table_addr=(year+0x64-1)*0x3; }
else { table_addr=(year-1)*0x3; }
//定位数据表地址完成
//取当年节日所在的公历月份
temp1=year_code[table_addr+2]&0x60;
temp1=_cror_(temp1,5);
//取当年节日所在的公历月份完成
//取当年节日所在的公历日
temp2=year_code[table_addr+2]&0x1f;
//取当年节日所在的公历日完成
// 计算当年春年离当年元旦的天数,节日只会在公历1月或2月
if(temp1==0x1) { temp3=temp2-1; }
else { temp3=temp2+0x1f-1; }
// 计算当年春年离当年元旦的天数完成
//计算公历日离当年元旦的天数,为了减少运算,用了两个表
//day_code1[9],day_code2[3]
//如果公历月在九月或前,天数会少于0xff,用表day_code1[9],
//在九月后,天数大于0xff,用表day_code2[3]
//如输入公历日为8月10日,则公历日离元旦天数为day_code1[8-1]+10-1
//如输入公历日为11月10日,则公历日离元旦天数为day_code2[11-10]+10-1
if (month<10){ temp4=day_code1[month-1]+day-1; }
else { temp4=day_code2[month-10]+day-1;}
if ((month>0x2)&&(year%0x4==0)&&(year!=0))
temp4+=1; //如果公历月大于2月并且该年的2月为闰月,天数加1
//计算公历日离当年元旦的天数完成
//判断公历日在节日前还是节日后
if (temp4>=temp3)
{ //公历日在节日后或就是节日当日使用下面代码进行运算
temp4-=temp3;
month=0x1;
month_p=0x1; //month_p为月份指向,公历日在节日前或就是节日当日month_p指向首月
flag2=get_moon_day(month_p,table_addr); //检查该农历月为大小还是小月,大月返回1,小月返回0
flag_y=0;
if(flag2==0)temp1=0x1d; //小月29天
else temp1=0x1e; //大小30天
temp2=year_code[table_addr]&0xf0;
temp2=_cror_(temp2,4); //从数据表中取该年的闰月月份,如为0则该年无闰月
while(temp4>=temp1)
{
temp4-=temp1;
month_p+=1;
if(month==temp2)
{
flag_y=~flag_y;
if(flag_y==0)month+=1;
}
else month+=1;flag2=get_moon_day(month_p,table_addr);
if(flag2==0)temp1=0x1d;
else temp1=0x1e;
}
day=temp4+1;
}
else
{ //公历日在节日前使用下面代码进行运算
temp3-=temp4;
if (year==0x0){year=0x63;c=1;}
else year-=1;
table_addr-=0x3;
month=0xc;
temp2=year_code[table_addr]&0xf0;
temp2=_cror_(temp2,4);
if (temp2==0)month_p=0xc;
else month_p=0xd;
//month_p为月份指向,如果当年有闰月,一年有十三个月,月指向13,无闰月指向12
flag_y=0;
flag2=get_moon_day(month_p,table_addr);
if(flag2==0)
temp1=0x1d;
else
temp1=0x1e;
while(temp3>temp1)
{
temp3-=temp1;
month_p-=1;
if(flag_y==0)month-=1;
if(month==temp2)flag_y=~flag_y;
flag2=get_moon_day(month_p,table_addr);
if(flag2==0)temp1=0x1d;
else temp1=0x1e;
}
day=temp1-temp3+1;
}
c_moon=c;
//原程序这里又把这得出的值变回BCD码。但根据我后面的程序,我不需要。
//后面用来显示的农历信息的程序分别是disp_t3()和disp_t4()
year_moon=year;
month_moon=month;
day_moon=day;
}
/******************************************************************************************
* 函数名称 :Conver_week
* 功能描述 :输入BCD阳历数据,输出BCD星期数据(只允许1901-2099年)
* 参数 : 参数名称: 输入/输出? 类型 描述
* 算法:日期+年份+所过闰年数+月较正数之和除7 的余数就是星期,但如果是在
闰年又不到3 月份上述之和要减一天再除7星期数。余数为0时,为星期天。
******************************************************************************************/
void Conver_week()
{//century=0 为21世纪,c=1 为19世纪 输入输出数据均为BCD数据
uchar temp1,temp2;
temp1=year;
if (century==0){temp1=temp1+100;} //如果为21世纪,年份数加100
temp2=temp1/4; //所过闰年数只算1900年之后的
temp2=temp1+temp2;
temp2=temp2%7; //为节省资源,先进行一次取余,避免数大于255
temp2=temp2+day+table_week[month-1];
if (year%0x4==0&&month<3)temp2-=1;
week=temp2%7;
}
/********************************LCD12864部分*****************************/
/******************************************************************************
端口说明:EN_LCD12864:使能端锁存信号。RS_LCD12864:D/I 命令/数据寄存器选择端
RW_LCD12864:读写信号控制端. define LCD_Data P0
RS(D/I)=1,表示DB0-DB7显示数据; RS(D/I)=0,表示DB0-DB7显示指令数据
RW=1,E=1,数据被读到DB7-DB0;RW=0,E=1--0,数据被读到DB7-DB0;数据被
写到IR或DR。
(定义数据端口为 LCD_Data为P0口)
RST_LCD12864复位端口,不接或接高电平,低电平会导致复位
函数名称:void Lcd12864_BusyChk()
函数功能:忙检测,若忙则等待,最长等待时间为60MS(此判忙函数经过仿真已OK)
入口参数:无
出口参数:无
***********************************************************************/
void Lcd12864_BusyChk()
{
LCD12864_Databus=0x00;
EN_LCD12864=0;
RS_LCD12864=0;
RW_LCD12864=1;
EN_LCD12864=1;
while(LCD12864_Databus&0x80); //判断P0.7口
_nop_();
EN_LCD12864=0;
}
/**********************************************************************
* 函数名称: void set_xy(unsigned char x,unsigned char y)
(仿真时的函数,已OK)
* 功能描述: 设置显示位置! X,Y分别代表横纵坐标!
* 输入参数?: unsigned char x,unsigned char y
*输出参数: 无??
*参数名称:? ?//列地址赋值,?x取值0----64,页面地址赋值,y取值0----8
***********************************************************************/
/*void set_xy(unsigned char x,unsigned char y)
{
if (x>=64)
{CS1=1;CS2=0;} //选择右半屏
else
{CS1=0;CS2=1;} //选择左半屏
Lcd12864_BusyChk();
RS_LCD12864=0;
RW_LCD12864=0;
LCD12864_Databus=0x40|x; //列地址赋值,x取值0----64
EN_LCD12864=1;
EN_LCD12864=0;
Lcd12864_BusyChk();
RS_LCD12864=0;
RW_LCD12864=0;
LCD12864_Databus=0xb8|y; //页面地址赋值,y取值0----8
EN_LCD12864=1;
EN_LCD12864=0;
LCD12864_Databus=0xff;
}*/
/**********************************************************************
* 函数名称: void set_xy(unsigned char x,unsigned char y)
(实物时的函数,已OK)
* 功能描述: 设置显示位置! X,Y分别代表横纵坐标!
* 输入参数?: unsigned char x,unsigned char y
*输出参数: 无??
*参数名称:? ?//列地址赋值,?x取值0----64,页面地址赋值,y取值0----8
***********************************************************************/
/***************************************************************************************
函数名称:void LCD12864_DispYanYueRi(fb)
函数功能:设置日期的时候,选中的参数可以反白显示,右屏第一行显示程序,
由which决定第几个参数黑显,如which==1时,年份黑显.
入口参数:无
出口参数:无
****************************************************************************************/
void LCD12864_DispYanYueRi(fb) //显示年月日
{
if(century) //如果世纪为1
{
Lcd12864_DispChar(0,0,1,0); //则第1行第1列显示’1”
Lcd12864_DispChar(1,0,9,0); //则第1行第2列显示’9”
}
else
{
Lcd12864_DispChar(0,0,2,0); //则第1行第1列显示’2”
Lcd12864_DispChar(1,0,0,0); //则第1行第2列显示’0”
}
Lcd12864_DispChar(2,0,year/10,fb); //第1行第3列显示年十位数
Lcd12864_DispChar(3,0,year%10,fb); //第1行第4列显示年个位数
Lcd12864_DispChar(4,0,11,0); //第1行第5列显示第11个数据”-”
Lcd12864_DispChar(5,0,month/10,fb); //第1行第6列显示月十位数
Lcd12864_DispChar(6,0,month%10,fb); //第1行第7列显示月个位数
Lcd12864_DispChar(7,0,11,0); //第1行第8列显示第11个数据”-”
Lcd12864_DispChar(8,0,day/10,fb); //第1行第9列显示日十位数
Lcd12864_DispChar(9,0,day%10,fb); //第1行第10列显示日个位数
}
/******************************************************************************
函数名称:void LCD12864_DispShiFenMiao(fb) 显示时分秒
函数功能:设置时间的时候,选中的参数可以反白显示,右屏第二行显示程序,
由which决定第几个参数黑显,如which==1时,年份黑显.
入口参数:无
出口参数:无
***********************************************************************/
void LCD12864_DispShiFenMiao(fb)
{
Lcd12864_DispDaShuZi(0,2,hour/10,fb); //第2行第1列显示小时十位数
Lcd12864_DispDaShuZi(2,2,hour%10,fb); //第2行第3列显示小时个位数
if(sec%2==0) //如果秒为奇数则显示冒号,否则显示空
Lcd12864_DispDaShuZi(4,2,10,0); //第2行第4列第10个大数字为显示冒号,不反白
else
Lcd12864_DispDaShuZi(4,2,11,0); //第2行第4列第11个大数字为显示空,不反白
Lcd12864_DispDaShuZi(6,2,min/10,fb); //第2行第6列显示分钟的十位数
Lcd12864_DispDaShuZi(8,2,min%10,fb); //第2行第8列显示分钟的个位数
if(sec%2==0)
Lcd12864_DispDaShuZi(10,2,10,0); //第2行第10列第10个大数字为显示冒号,不反白
else
Lcd12864_DispDaShuZi(10,2,11,0); //第2行第10列第11个大数字为显示空,不反白
Lcd12864_DispDaShuZi(12,2,sec/10,fb); //第2行第10列显示秒钟的十位数
Lcd12864_DispDaShuZi(14,2,sec%10,fb); //显示秒钟
}
/******************************************************************************
函数名称:void LCD12864_DispWeek(fb) 显示 周
函数功能:设置时间的时候,选中的参数可以反白显示,右屏第一行显示程序,
由which决定第几个参数黑显,如which==1时,年份黑显.
入口参数:无
出口参数:无
*******************************************************************************/
void LCD12864_DispWeek()
{
uchar temp;
Lcd12864_DispWord(12,0,27,0); //第1行第13列第27个汉字为显示“周”字
Conver_week(); //调用星期阳历数据
if(week)
temp=week; //赋week值为1----6,用来显示“一”----“六”
else
week=26; //赋week值为0时,赋值26用来显示“日”
Lcd12864_DispWord(14,0,week,0); //第1行第14列第26个汉字为显示“日”
//verify_time(); //此函数加上才能得到十二生肖后的农历日期
ReadTime_DS1302();
GetTime_DS1302();
Conversion(century,year,month,day); //得到农历日期
if(c_moon)
temp=year_moon%12+12; //如果是19世纪,则可直接得出年的属性
else
temp=(year_moon+100)%12+12; //农历年也过了世纪,则农历年加100再求属性
Lcd12864_DispWord(0,6,temp,1); // 第7行第1列 显示十二生肖属性
}
/******************************************************************************
函数名称:void LCD12864_DispNongLiRiQi(fb) 显示 农历日期
函数功能:第4行农历显示
由which决定第几个参数黑显,如which==1时,年份黑显.
入口参数:无
出口参数:无
*******************************************************************************/
void LCD12864_DispNongLiRiQi()
{
uchar temp1,temp2;
// verify_time();
Conversion(century,year,month,day); //得到农历日期,世纪年月日
temp1=month_moon/10;
temp2=month_moon%10;
//月份高位为0,低位为1,则月份前位显"正",后位显示“月”字
if(temp1==0&&temp2==1) //如果农历日期,月的十位为0,个位为1,则为正月
{
Lcd12864_DispWord(2,6,39,0); //第7行第3列 显示”正”字
Lcd12864_DispWord(4,6,25,0); //第7行第5列 显示”月”字
}
//月份高位为0,低位都大于等于2,则月份高位显月份,后位显月。
else if (temp1==0&&temp2>=2)
{
Lcd12864_DispWord(2,6,temp2,0);//第7行第3列 显示月份
Lcd12864_DispWord(4,6,25,0); //第7行第5列 显示”月”字
}
//月份高位为1,低位为0,则月份高位显“十”,后位显月。
else if (temp1==1&&temp2==0)
{
Lcd12864_DispWord(2,6,0,0); //第7行第3列 显示”十”字
Lcd12864_DispWord(4,6,25,0); //第7行第5列 显示”月”字
}
//月份高位为1,低位为1,则月份高位显“冬”,后位显月。
else if (temp1==1&&temp2==1)
{
Lcd12864_DispWord(2,6,29,0); //第7行第3列 显示”冬”字
Lcd12864_DispWord(4,6,25,0); //第7行第5列 显示”月”字
}
else
{
Lcd12864_DispWord(2,6,30,0); //第7行第3列 显示”腊”字
Lcd12864_DispWord(4,6,25,0); //第7行第5列 显示”月”字
}
temp1=day_moon/10;
temp2=day_moon%10;
switch (temp1)
{ //日期高位为0,则前位显“初”
case 0: Lcd12864_DispWord(6,6,10,0); //第7行第7列 显示”初”字
Lcd12864_DispWord(8,6,temp2,0);//第7行第9列 显示低位字
break;
//日期高位为1且低位不为0,则前位显“十”
case 1: if(temp2)
{
Lcd12864_DispWord(6,6,0,0); //第7行第7列 显示”十”字
Lcd12864_DispWord(8,6,temp2,0); //第7行第9列 显示低位农历月份
break;
}
else //日期高位为1且低位为0,则显“初十”
{
Lcd12864_DispWord(6,6,10,0); //第7行第7列 显示”初”字
Lcd12864_DispWord(8,6,0,0); //第7行第9列 显示”十”字
break;
}
//日期高位为2,则前位显“廿”
case 2: Lcd12864_DispWord(6,6,11,0); //第7行第7列 显示”"廿"字
Lcd12864_DispWord(8,6,temp2,0); //第7行第9列 显示低位农历月份
break;
//日期高位为3,则前位显“三”,低位显“十”
case 3: Lcd12864_DispWord(6,6,3,0); //第7行第7列 显示”三”字
Lcd12864_DispWord(6,6,temp2,0); //第7行第9列 显示低位农历月份
break;
}
}
/*主程序*/
void main(void)
{
bl=0;
lcd12864_Init(); //液晶初始化,此函数只起清屏的作用
century=0; //对世纪赋初值
Conversion(century,year,month,day);
DS1302_flag=Read_DS1302(0xc0); //读取首地址中的值,0xc0为DS1302RAM的首地址,
//偶数为写,奇数读
if(DS1302_flag==0)
{
Init_DS1302(); //时间初始化,起决于当前显示的时间
Write_DS1302(0xc0,1);
}
while(1)
{
ReadTime_DS1302(); //读出时钟数据
GetTime_DS1302(); //将BCD时钟数据转换为可以计算的HEX数据
GetTemp();
Lcd12864_DispTemp();
KeyScan();
if(setflag==0)
{
Lcd12864_DispTime(); //这里调用显示时间程序
}
}
}
页面更新:2024-03-07
本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828
© CopyRight 2008-2024 All Rights Reserved. Powered By bs178.com 闽ICP备11008920号-3
闽公网安备35020302034844号