STC89c52单片机基于1302与1602数字钟程序分4个h文件.docx
- 文档编号:24630516
- 上传时间:2023-05-29
- 格式:DOCX
- 页数:20
- 大小:21.51KB
STC89c52单片机基于1302与1602数字钟程序分4个h文件.docx
《STC89c52单片机基于1302与1602数字钟程序分4个h文件.docx》由会员分享,可在线阅读,更多相关《STC89c52单片机基于1302与1602数字钟程序分4个h文件.docx(20页珍藏版)》请在冰豆网上搜索。
STC89c52单片机基于1302与1602数字钟程序分4个h文件
#include
#include
#include<1602.h>
#include<1302.h>
#include
#include
voidmain(void)//主函数
{
lcd_init();//LCD1602初始化
InitTimer0();//定时器T0初始化用于设定时使设定值闪烁
Set_RTC();//初始化DS1302若有备用电源可将此屏蔽
while
(1)
{
Read_RTC();//读各时间寄存器和3个RAM。
并将其转换为二进制,并将其存于time[11]中
naolingchek();//闹铃检测是否到设定时间
zhuanhuan();//将time[11]中的时间值转化为ASC码以便用1602显示
shanshuo();//根据设定状态确定哪一项该闪烁
if(zhuangtai<8)//年月日周时分秒这七项在第一页显示,当设定那一项小于8时显示的是display1[15],display2[15]
{display1
(1);display2
(2);}//显示年月日周
else
{display3
(1);display4
(2);}//显示naolingkai/guan和闹铃时间
keychek();//键盘检测
}
}
voidTimer0Interrupt(void)interrupt1//定时器0中断程序
{
TH0=0x3C;//工作方式1,需填装初始值,每次中断50ms
TL0=0x0B0;
cs++;//中断次数加1
if(cs==20){cs=0;}//当中断次数到20时,即为0.5s,控制设定的值灭,从而实现每秒闪一次
}
#include
#include
typedefunsignedcharBYTE;//宏替换
typedefbitBOOL;
sbitLCD_RS=P2^6;//LCD读引脚定义
sbitLCD_RW=P2^5;//LCD写引脚定义
sbitLCD_EP=P2^7;//LCD使能引脚定义
externunsignedcharzhuangtai;//外部变量声明key.h中表示设定的哪一项
externunsignedcharnaoling;//闹铃状态标志,为0表示关闭,为1表示开启,为2表示闹铃时间到
unsignedcharcs=0;//T0中断次数变量控制闪烁
unsignedchardis1[16]={"2012-12-14zhou5"};//第一行显示年月日周
unsignedchardis2[16]={"am08:
44:
00"};//第二行显示时分秒
unsignedchardis3[16]={"naolingkai"};//第一行显示naolingkai/guan
unsignedchardis4[16]={"am08:
44"};//第二行显示闹铃时,分
voiddelay(intms)
{//延时子程序
inti;
while(ms--)
{
for(i=0;i<250;i++)
{
_nop_();
_nop_();
_nop_();
_nop_();
}
}
}
BOOLlcd_bz()
{//测试LCD忙碌状态
BOOLresult;
LCD_RS=0;
LCD_RW=1;
LCD_EP=1;
_nop_();
_nop_();
_nop_();
_nop_();
result=(BOOL)(P0&0x80);
LCD_EP=0;
returnresult;
}
voidlcd_wcmd(BYTEcmd)
{//写入指令数据到LCD
while(lcd_bz());
LCD_RS=0;
LCD_RW=0;
LCD_EP=0;
_nop_();
_nop_();
P0=cmd;
_nop_();
_nop_();
_nop_();
_nop_();
LCD_EP=1;
_nop_();
_nop_();
_nop_();
_nop_();
LCD_EP=0;
}
voidlcd_pos(BYTEpos)
{//设定显示位置,第一行第一个位置传递变量pos为0
lcd_wcmd(pos|0x80);
}
voidlcd_wdat(BYTEdat)
{//写入字符显示数据到LCD
while(lcd_bz());
LCD_RS=1;
LCD_RW=0;
LCD_EP=0;
P0=dat;
_nop_();
_nop_();
_nop_();
_nop_();
LCD_EP=1;
_nop_();
_nop_();
_nop_();
_nop_();
LCD_EP=0;
}
voidlcd_init()
{//LCD初始化设定
lcd_wcmd(0x38);//16*2显示,5*7点阵,8位数据
delay
(1);
lcd_wcmd(0x0c);//显示开,关光标
delay
(1);
lcd_wcmd(0x06);//移动光标
delay
(1);
lcd_wcmd(0x01);//清除LCD的显示内容
delay
(1);
}
voiddisplay1(charh)//在第h行显示字符组1h为1或2
{chari=0;//i为循环控制变量
if(h==1)h=0;elseh=0x40;//第一行首地址为零,第二行首地址为0x40
lcd_pos(h);//设定写的首地址
while(dis1[i]!
='\0')
{
lcd_wdat(dis1[i]);//写入字符串直到完
i++;
}
}
voiddisplay2(charh)//在第h行显示字符组2
{chari=0;//同上
if(h==1)h=0;elseh=0x40;
lcd_pos(h);
while(dis2[i]!
='\0')
{
lcd_wdat(dis2[i]);
i++;
}
}
voiddisplay3(charh)//在第h行显示字符组3
{chari=0;//同上
if(h==1)h=0;elseh=0x40;
lcd_pos(h);
while(dis3[i]!
='\0')
{
lcd_wdat(dis3[i]);
i++;
}
}
voiddisplay4(charh)//在第h行显示字符组4
{chari=0;//同上
if(h==1)h=0;elseh=0x40;
lcd_pos(h);
while(dis4[i]!
='\0')
{
lcd_wdat(dis4[i]);
i++;
}
}
voidshanshuo(void)
{if(naoling==0){dis3[9]='g';dis3[10]='u';dis3[11]='a';dis3[12]='n';}//由于dis1[15],dis2[15],dis4[15],每次都有转换函数赋值
else{dis3[9]='k';dis3[10]='a';dis3[11]='i';dis3[12]='';}//但是dis3[15]没有所以在此根据闹铃开关状态标志判断是显示开还是关此部分也可以放在zhuanhuan();函数里
if(cs>10)//当定时器中断次数为10时表示已经显示了0.5秒,虽然转换函数将该显示的已经赋值,在这赋值''空格,就会是闪烁的情况
switch(zhuangtai)
{//根据状态(标志哪一项处于设定状态)标志选择将哪一项赋值空格显示成闪烁状态
case1:
{dis1[0]='';dis1[1]='';dis1[2]='';dis1[3]='';break;}//年
case2:
{dis1[5]='';dis1[6]='';break;}//月
case3:
{dis1[8]='';dis1[9]='';break;}//日
case4:
{dis1[15]='';break;}//周
case5:
{dis2[2]='';dis2[3]='';break;}//时
case6:
{dis2[5]='';dis2[6]='';break;}//分
case7:
{dis2[8]='';dis2[9]='';break;}//秒
case8:
{dis4[2]='';dis4[3]='';break;}//闹铃时
case9:
{dis4[5]='';dis4[6]='';break;}//闹铃分
case10:
{dis3[9]='';dis3[10]='';dis3[11]='';dis3[12]='';break;}//闹铃开关
default:
break;//由于编程的思路所以这个子程序要放在转换之后才能有效果
}
}
#include
#include
sbitSCK=P3^6;//时钟
sbitSDA=P3^4;//数据
sbitRST=P3^5;//DS1302复位
//外部变量声明
externunsignedchardis1[16];//记录要显示的年-月-日周的值
externunsignedchardis2[16];//记录要显示的时:
分:
秒的值
externunsignedchardis4[16];//记录要显示的闹铃时:
分的值
unsignedchartime[11]={0,0,12,1,1,7,12,0x00,20,0,9};//对应存储从DS1302寄存器读取的时间值
////////////////////////秒分时日月周年写保护百年闹铃分闹铃时
///////////////////////2012-1-112:
00:
00闹铃9:
00
codeunsignedcharread_rtc_address[11]={0x81,0x83,0x85,0x87,0x89,0x8b,0x8d,0x8f,0xc1,0xc3,0xc5};//读DS102寄存器地址数据以BCD码存储分别对应秒分时日月周年写保护百年闹铃分闹铃时
codeunsignedcharwrite_rtc_address[11]={0x80,0x82,0x84,0x86,0x88,0x8a,0x8c,0x8e,0xc0,0xc2,0xc4};//写DS1302寄存器地址数据以BCD码存储分别对应秒分时日月周年写保护百年闹铃分闹铃时
voidWrite_Ds1302_Byte(unsignedchartemp)//写一个字节
{
unsignedchari=0;//定义控制循环的变量
for(i=0;i<8;i++)//有八位循环8次写入数据
{
SCK=0;//根据时序图先将SCK拉低
SDA=temp&0x01;//每次传输低字节temp存有要写的数据
temp>>=1;//右移一位
SCK=1;
}
}
voidWrite_Ds1302(unsignedcharaddress,unsignedchardat)//写入DS1302
{
RST=0;
_nop_();
SCK=0;
_nop_();
RST=1;
_nop_();//启动
Write_Ds1302_Byte(address);//调用写一个字节子程序发送地址
Write_Ds1302_Byte(dat);//调用写一个字节子程序发送数据
RST=0;//恢复
}
unsignedcharRead_Ds1302(unsignedcharaddress)//读出一个字节数据
{
unsignedchari=0,temp=0x00;
RST=0;
_nop_();
_nop_();
SCK=0;
_nop_();
_nop_();
RST=1;
_nop_();
_nop_();
Write_Ds1302_Byte(address);
for(i=0;i<8;i++)//循环8次读取数据
{
if(SDA)
temp|=0x80;//每次传输低字节
SCK=0;
temp>>=1;//右移一位
_nop_();
_nop_();
_nop_();
SCK=1;
}
RST=0;
_nop_();//以下为DS1302复位的稳定时间
_nop_();
RST=0;
SCK=0;
_nop_();
_nop_();
_nop_();
_nop_();
SCK=1;
_nop_();
_nop_();
SDA=0;
_nop_();
_nop_();
SDA=1;
_nop_();
_nop_();
return(temp);//返回
}
voidRead_RTC(void)//读取日历即将DS1302的寄存器的BCD值读出以二进制存于time[11]中
{
unsignedchari=0,*p,tmp=0;//i为循环次数控制变量,*p为循环地址指针依次指向读寄存器个地址
p=read_rtc_address;//读寄存器地址传递
for(i=0;i<11;i++)//分11次读取秒分时日月周年,暂停标志,百年,闹铃分,闹铃时
{
time[i]=Read_Ds1302(*p);
p++;
}
for(i=0;i<8;i++){//将读取的BCD码
tmp=time[i]/16;//取出高四位
time[i]=time[i]%16;//取出低四位
time[i]=time[i]+tmp*10;//高四位*10加上低四位即是二进制
}
}
voidSet_RTC(void)//设定日历即将读出二进制存于time[11]中的值以BCD形式存于DS1302的寄存器中
{
unsignedchari=0,*p,tmp=0;
for(i=0;i<8;i++){//十进制转换为BCD处理
tmp=time[i]/10;
time[i]=time[i]%10;
time[i]=time[i]+tmp*16;
}
p=write_rtc_address;//传地址
for(i=0;i<11;i++)//11次写入秒分时日月周年,暂停标志,百年,闹铃分,闹铃时
{
Write_Ds1302(*p,time[i]);
p++;
}
}
voidzhuanhuan(void)//将读取的时间数据转换为显示字符
{
dis2[9]=time[0]%10+0x30;//取出秒的个位,加上0x30即是ASC码,赋给要显示的位置的字符串(即第一面的第二行第10个字符)
dis2[8]=time[0]/10+0x30;//取出秒的十位,加上0x30即是ASC码,赋给要显示的位置的字符串(即第一面的第二行第9个字符)
dis2[6]=time[1]%10+0x30;//以下以此类推分的十位
dis2[5]=time[1]/10+0x30;//分的个位
if(time[2]>11)//因为在BCD码转换时方便,DS1302运行于24小时模式,要显示出12小时模式要进行是显示am还是pm判断
{if(time[2]>12)time[2]-=12;dis2[0]='p';}//12点时已经是下午,所以要在小时大于11时显示PM,而当13时要减去12才是下午一点
elsedis2[0]='a';//time[2]中小时不大于11是上午
if(time[2]==0)//若为time[2]为0点应该显示12点
time[2]=12;
dis2[3]=time[2]%10+0x30;//此时time[2]中小时已经是12小时模式直接取出个位
dis2[2]=time[2]/10+0x30;//此时time[2]中小时已经是12小时模式直接取出十位
dis1[9]=time[3]%10+0x30;//取出日个位
dis1[8]=time[3]/10+0x30;//取出日十位
dis1[6]=time[4]%10+0x30;//取出月个位
dis1[5]=time[4]/10+0x30;//取出月十位
dis1[15]=time[5]+0x30;//取出周,直接赋给相应位
dis1[3]=time[6]%10+0x30;//取出年个位
dis1[2]=time[6]/10+0x30;//取出年十位
dis1[1]=time[8]%10+0x30;//取出百年个位
dis1[0]=time[8]/10+0x30;//取出百年十位
dis4[6]=time[9]%10+0x30;//取出闹铃分个位
dis4[5]=time[9]/10+0x30;//取出闹铃分十位
if(time[10]>11)//闹铃在键盘程序调整中用十进制比较方便,所以和时间小时一样也要进行12小时模式转换
{if(time[10]>12)time[10]-=12;dis4[0]='p';}
elsedis4[0]='a';
if(time[10]==0)
time[10]=12;
dis4[3]=time[10]%10+0x30;
dis4[2]=time[10]/10+0x30;
}
#include
#include
externunsignedcharnaoling;//闹铃状态标志,为0表示关闭,为1表示开启,为2表示闹铃时间到
sbitling=P1^0;//铃的引脚,接蜂鸣器阴极,为1不响为0响,若改动需在key.h,T0.h中改动相应位
sbitsheding=P2^0;//按键设定
sbitjia=P2^1;//按键增加
sbitjian=P2^2;//按键减小
unsignedcharzhuangtai=0;//用于记录正在设定的是哪一项,还作为判断哪一项闪烁的标志,为零时表示处于非设定状态,此时定时器T0关闭
voidriqijiaozhengjia(void)//由于各个月份公历天数不一所以进行增加设定时要进行最大值判断
{
if((time[4]==6||time[4]==9||time[4]==11)&&time[3]==31)time[3]=1;//6,9,11月最大30天,当time[3]中记录的月数加1后为31,应该改为1
elseif(time[4]==2)//如果是二月
{
if(!
((time[6]%4==0&&time[6]%100!
=0)||time[6]%400==0))//不是闰年2月最大天数28天(闰年能被4且不能被100整除或者能被400整除)
{if(time[3]==29)time[3]=1;}//在不是闰年时二月天数加1后为29,置为1
elseif(time[3]==30)time[3]=1;//是闰年2月最大天数29天
}
elseif(time[3]==32)time[3]=1;//不是6,9,11,2月为最大为31天
}
voidriqijiaozhengjian(void)//由于各个月份公历天数不一,所以进行减小设定时,且减为0后,要进行最大值赋值
{if((time[4]==6||time[4]==9||time[4]==11)&&time[3]==0)time[3]=30;//6,9,11月最大30天
elseif(time[4]==2)
{
if(!
((time[6]%4==0&&time[6]%100!
=0)||time[6]%400==0))//不是闰年2最大天数28天
{if(time[3]==0)time[3]=28;}
elseif(time[3]==0)time[3]=29;}//是闰年2月最大天数29天
elseif(time[3]==0)time[3]=31;//不是6,9,11,2月为31天
}
voidkeychek(void)//键盘检测子程序
{
if(zhuangtai!
=0)TR0=1;elseTR0=0;//开T0控制的闪烁表示正在设定的那一项
//设定键的检测
if(sheding==0)
{
delay(10);//消抖动,目的防止检测错误
if(sheding==0)//仍然为零表示键按下
{
while(sheding==0);//等待,键松开时不然会一直执行以下程序且很快,因为键一直处于按下状态,满足条件
if(naoling==2){ling=1;naoling=1;}//naoling==2表示闹铃时间到,这里是已经判断设定键按下,要停止铃声,并将闹铃状态改为1(开启)
zhuangtai++;//每次按下设定键设定项目移向下一个直到第10项闹铃开关设定
if(zhuangtai==11)zhuangtai=0;}//然后改为非设定状态此时前面的if将T0关闭
}
//增加键的检测
if(jia==0)
{
delay(10);//消抖
if(jia==0)//却是按下
{while(jia==0);//等待松开
if(naoling==2){ling=1;naoling=1;}//同上设定键naoling==2表示闹铃时间到,这里是已经判断设定键按下,要停止铃声,并将闹铃状态改为1(开启)
Read_RTC();//读取DS1302的值因为子程序zhuanhuan();将读取的值已经
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- STC89c52 单片机 基于 1302 1602 数字 程序 文件