单片机数字钟设计报告.docx
《单片机数字钟设计报告.docx》由会员分享,可在线阅读,更多相关《单片机数字钟设计报告.docx(31页珍藏版)》请在冰点文库上搜索。
单片机数字钟设计报告
中国矿业大学
2011年电子设计竞赛
作品设计总结报告
作品名称:
多功能数字钟
参赛队员:
联系电话:
摘要:
本多功能数字钟采用ATMEL公司的AT89S52单片机作为核心器件,实现对整个系统的自动控制。
采用DALLAS公司的DS1302实时时钟芯片作为时间信号源,实现年、月、日、时、分、秒、星期的自动计时,同时利用其内部31字节的SRAM静态寄存器,实现闹钟数据和生日提醒数据的掉电保存。
采用DALLAS公司的DS18B20单总线数字温度传感器采集环境温度数据,温度转换精度可达0.0625度。
显示器件采用LCD1602液晶显示屏,该显示屏单屏可显示32个字符,所有的时间及温度数据均可在一屏中显示。
关键字:
单片机数字钟AT89S52DS1302DS18B20LCD1602
多功能数字钟设计报告
一、总体要求
1、基本要求:
(1)可实现基本时钟功能,十进制显示小时、分和秒位。
(2)可调时,可预置时间。
(3)倒计时功能。
(4)可定时。
定时时间到发出提示(提示为声音或光等均可)。
2、扩展功能:
(1)时钟12小时制和24小时制之间可调节自由转换。
(2)实现秒表计时功能。
(3)时钟芯片的精确计时。
.
二、整体介绍:
本作品整体如上图,由主板,电池两部分组成。
采用双路供电,电池、交流任选。
交流输入不分极性,板载整流全桥,自动调整电源极性。
直流输入连接6-24伏任意直流电源,有连接座方便连接。
时钟部分不须外界电源保持,自带后备电池,维持时钟运行。
当系统整体工作时,时钟部分自动对后备电源涓流充电,保持电源容量。
键盘输入部分采用矩阵键盘,预留4个空白键位,为以后系统功能拓展,对按键需求增加时准备。
带有3组闹钟,断电自动保护,重新上电后闹钟不丢失。
定时精度为分钟。
闹钟到时会有蜂鸣器鸣响,约一分钟后自动停闹。
还带有一路生日提醒,到达日期后也会有蜂鸣器鸣响。
板载的实时温度测量探头可以实时测量环境温度,显示精度代0.1度,同时有上下限超温报警功能。
一旦温度超过报警上限或低于报警下限,就会报警。
上下限温度可自行设定。
测温范围0度到99度
三、操作说明
主板上的显示部分液晶显示器显示的内容自左向右分别是:
第一行:
年、月、日、星期
第二行:
时、分、秒,实时温度
2*2矩阵键盘的左侧两列共4个按键,4个按键自上而下依次定义为:
第一列:
模式切换①、保存闹钟②、修改时间确认③、闹钟换组④
第二列:
光标左移⑤、数字加一⑥、数字减一⑦、光标右移⑧
液晶显示器下方的白色按键是电源切换开关,弹起为交流供电,按下为直流供电。
下面按模式介绍使用方法。
(注:
因为上电自动进入模式2正常显示模式,所以实际使用中模式显示的顺序与本说明不同)
1、模式0:
闹钟调整模式
按动模式切换键至液晶屏左上角显示“alarm”,设置第一组闹钟。
用光标移动键配合数字加减键设定闹钟,设定好后按保存闹钟键保存闹钟,此时液晶屏上显示“SaveAlarm”,片刻后返回设置界面。
按动闹钟换组键切换至下一组闹钟,按同样的步骤设置。
切换时,屏幕上显示“ChangeTeam”,片刻后返回设置界面。
3组闹钟可以循环切换。
闹钟断电后可保存不丢失。
注意:
每设完一组闹钟后都需要保存,切换闹钟后上一组闹钟的数据会被覆盖。
同时退出闹钟设置模式会将缓冲区内的闹钟数据全部清空。
2、模式1:
时间调整模式
按动模式切换键至液晶屏右上角显示“adjust”,设置时间。
用光标移动键配合数字加减键设定时间、日期,设定完成后,必须按修改时间确认键,确认并保存修改后的时间,否则,修改的时间数据不会被更新到时钟芯片中。
3、模式2:
正常显示模式
上电默认进入的模式,正常显示时间、日期、温度等数据
4、模式4:
上下限报警温度设置模式
按动模式切换键至液晶屏左边显示“max_temp、min_temp”,各自对应着上限报警温度和下限报警温度。
用光标移动键配合数字加减键设定,自动保存,设置完成后可直接退出。
注:
上下限报警温度掉电不保存。
5、模式5:
生日提醒模式
按动模式切换键至液晶屏左上角显示“birthday”,设置生日提醒。
操作同闹钟设置。
生日提醒数据断电不丢失。
五,功能测试
1、设定好三组闹钟(时间间隔3分钟以上),分别到时后蜂鸣器报警,约一分钟后自动停止。
2、用手捏住温度传感器,显示温度值上升,超过温度报警上限后蜂鸣器报警,松手后显示温度下降,低于温度报警上限后,蜂鸣器自动停止。
3、设定好时间、闹钟、生日提醒等数据后,切断外部电源供给(取下电池,切断220V电源),3小时后恢复供电,检查所有数据依然正确,时钟在断电期间依然在走动。
七、未来功能扩展
1、画面风格显示功能选择。
2、增加EEPROM存储器,使闹钟的组数增多,保存时间不再受备份电源的限制。
3、增加无线数据传输功能,可对其他多部同型号数字钟同步统一时间、闹钟、生日提醒、温度报警设定等设定。
附录一:
总体电原理图
附录二:
程序清单
#include
#include
#defineucharunsignedchar
#defineuintunsignedint
sbitlcd_rs=P2^7;
sbitlcd_rw=P2^6;
sbitlcd_enable=P2^5;
sbitsck=P2^1;
sbitio=P2^2;
sbitrst=P2^3;
sbitDQ=P2^0;
sbitkey1=P1^0;
sbitkey2=P1^1;
sbitkey3=P1^2;
sbitkey4=P1^3;
sbitbeep=P2^4;
uchartime_data[7]={12,7,4,17,11,58,30};
ucharwrite_add[7]={0x8c,0x8a,0x88,0x86,0x84,0x82,0x80};//对时时向里面写的地址
ucharread_add[7]={0x8d,0x8b,0x89,0x87,0x85,0x83,0x81};//读时间时向里面写的地址
uchardisp[14];
uchart_data[7]={12,7,4,17,11,58,30};
/*sbitlcd_rs=P3^4;
sbitlcd_rw=P3^5;
sbitlcd_enable=P3^6;
sbitsck=P2^4;
sbitio=P2^5;
sbitrst=P2^6;
sbitDQ=P2^7;
*/
//***********************************************************
//***********************************************************
voidwrite_ds1302_byte(uchardat);
voidwrite_ds1302(ucharadd,uchardat);
ucharread_ds1302(ucharadd);
voidset_rtc();
voidread_rtc();
voidtime_pros();
voidchange_day(ucharcom);//星期转换
voidlcd_1302_display();
//************************************************
//************************************************
//延时函数,在12MHz的晶振频率下
//大约50us的延时
//************************************************
voiddelay_50us(uintt);
//************************************************
//延时函数,在12MHz的晶振频率下
//大约50ms的延时
//************************************************
voiddelay_50ms(uintt);
//**********************************************
//**********************************************
voidlcd_delay(uintz);
voidlcd_com(ucharcom);//写指令
voidlcd_dat(uchardat);//写数据
voidlcd_inital();//液晶初始化
voidlcd_com_dat(ucharcom,uchardat);
voidlcd_com_string(ucharcom,uchardat[]);
//**********************************************
//**********************************************
voidinit_ds18b20(void);
voidb1820_delay(uintt);
voidwrite_byte(uchardat);
ucharread_byte(void);
uintreadtemperature(void);
voidchange_temperature();
//**************************************************
//**************************************************
voidkey_change_time();
//**************************************************
//**************************************************
voidmain()
{
lcd_inital();
while
(1)
{
key_change_time();//时间调节
delay_50us(20);
lcd_1302_display();//时间显示
change_temperature();//温度显示
}
}
//***********************************************
//***********************************************
voiddelay_50us(uintt)
{
ucharj;
for(;t>0;t--)
for(j=19;j>0;j--);
}
voiddelay_50ms(uintt)
{
uintj;
for(;t>0;t--)
for(j=6245;j>0;j--);
}
voidlcd_com(ucharcom)//写指令
{
lcd_rs=0;
lcd_rw=0;
P0=com;
lcd_enable=1;
lcd_delay
(1);
lcd_enable=0;
}
voidlcd_dat(uchardat)//写数据
{
lcd_rs=1;
lcd_rw=0;
P0=dat;
lcd_enable=1;
lcd_delay
(1);
lcd_enable=0;
}
voidlcd_inital()//初始化程序
{
lcd_rs=0;
lcd_rw=0;
lcd_com(0x38);
lcd_com(0x01);
lcd_delay(5);
lcd_com(0x0c);//不显示光标
}
voidlcd_delay(uintz)//延时函数
{
uintx,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}
voidlcd_com_dat(ucharcom,uchardat)//在液晶的某一位置写某个数
{
lcd_com(0x80+com);
lcd_delay(5);
if(dat>='A'&&dat<='Z'||dat>='a'&&dat<='z')
lcd_dat(dat);
else
lcd_dat(0x30+dat);
}
voidlcd_com_string(ucharcom,uchardat[])//在某个位置写字符串
{
uchara;
lcd_com(0x80+com);
lcd_delay(5);
for(a=0;a<3;a++)
{
lcd_dat(dat[a]);
lcd_delay(5);
}
}
//**********************************************
//**********************************************
//1302实时时钟部分
voidwrite_ds1302_byte(uchardat)//用时钟写一个字节
{
uchari;
for(i=0;i<8;i++)
{
sck=0;
io=dat&0x01;
dat=dat>>1;
sck=1;
}
}
voidwrite_ds1302(ucharadd,uchardat)//随机写入数据
{
rst=0;
_nop_();
sck=0;
_nop_();
rst=1;
_nop_();
write_ds1302_byte(add);
write_ds1302_byte(dat);
rst=0;
_nop_();
io=1;
sck=1;
}
ucharread_ds1302(ucharadd)//随机读出一个数据
{
uchari,value;
rst=0;
_nop_();
sck=0;
_nop_();
rst=1;
_nop_();
write_ds1302_byte(add);
for(i=0;i<8;i++)
{
value=value>>1;
sck=0;
if(io)
value=value|0x80;
sck=1;
}
rst=0;
_nop_();
sck=0;
_nop_();
sck=1;
io=1;
returnvalue;
}
voidset_rtc()//对1302进行对时
{
uchartime_data[7]={12,7,4,17,11,58,30};//年周月日时分秒
uchari,j;
for(i=0;i<7;i++)
{
j=time_data[i]/10;
time_data[i]=time_data[i]%10;
time_data[i]=time_data[i]+j*16;
}
write_ds1302(0x8e,0x00);//去除写保护
for(i=0;i<7;i++)
write_ds1302(write_add[i],time_data[i]);
write_ds1302(0x8e,0x80);//加写保护
}
voidread_rtc(void)//读出当前时间
{
uchari;
for(i=0;i<7;i++)
time_data[i]=read_ds1302(read_add[i]);
}
voidtime_pros(void)//显示时分秒
{
disp[0]=time_data[6]%16;//秒
disp[1]=time_data[6]/16;
disp[2]=time_data[5]%16;//分
disp[3]=time_data[5]/16;
disp[4]=time_data[4]%16;//时
disp[5]=time_data[4]/16;
disp[6]=time_data[3]%16;//日
disp[7]=time_data[3]/16;
disp[8]=time_data[2]%16;//月
disp[9]=time_data[2]/16;
disp[10]=time_data[1]%16;//周
disp[11]=time_data[1]/16;
disp[12]=time_data[0]%16;//年
disp[13]=time_data[0]/16;
}
voidchange_day(ucharcom)//写星期进去
{
switch(disp[10])
{
case1:
lcd_com_string(com,"MON");break;
case2:
lcd_com_string(com,"TUE");break;
case3:
lcd_com_string(com,"WED");break;
case4:
lcd_com_string(com,"THU");break;
case5:
lcd_com_string(com,"FRI");break;
case6:
lcd_com_string(com,"SAT");break;
case7:
lcd_com_string(com,"SUN");break;
}
}
voidlcd_1302_display()
{
rst=1;
read_rtc();//读时间
rst=0;
time_pros();//处理时间
lcd_com_dat(0x01+2,2);
lcd_com_dat(0x02+2,0);
lcd_com_dat(0x03+2,disp[13]);//年十位
lcd_com_dat(0x04+2,disp[12]);//年个位
lcd_com_dat(0x05+2,0x2d-0x30);
lcd_com_dat(0x06+2,disp[9]);//月十位
lcd_com_dat(0x07+2,disp[8]);//月个位
lcd_com_dat(0x08+2,0x2d-0x30);
change_day(0x0d);//周
lcd_com_dat(0x09+2,disp[7]);//日十位
lcd_com_dat(0x0a+2,disp[6]);//日个位
lcd_com_dat(0x48,disp[0]);//秒个位
lcd_com_dat(0x47,disp[1]);//秒十位
lcd_com_dat(0x46,0x3a-0x30);
lcd_com_dat(0x45,disp[2]);//分个位
lcd_com_dat(0x44,disp[3]);//分时位
lcd_com_dat(0x43,0x3a-0x30);
lcd_com_dat(0x42,disp[4]);//时个位
lcd_com_dat(0x41,disp[5]);//时十位
}
//***************************************************
//***************************************************
//温度部分
voidb1820_delay(uintt)
{
while(t--);
}
voidinit_ds18b20(void)//对ds18b20进行初始化
{
ucharn;
DQ=1;
b1820_delay(8);
DQ=0;
b1820_delay(80);
DQ=1;
b1820_delay(8);
n=DQ;
b1820_delay(4);
}
voidwrite_byte(uchardat)//对ds18b20写一个字节
{
uchari;
for(i=0;i<8;i++)
{
DQ=0;
DQ=dat&0x01;
b1820_delay(4);
DQ=1;
dat>>=1;
}
b1820_delay(4);
}
ucharread_byte(void)//对ds18b20读一个字节
{
uchari,value;
for(i=0;i<8;i++)
{
DQ=0;
value>>=1;
DQ=1;
if(DQ)
value|=0x80;
b1820_delay(4);
}
returnvalue;
}
uintreadtemperature(void)//返回的一个16位的数
{
uinta,c,b;
init_ds18b20();
write_byte(0xcc);//跳过ROM
write_byte(0x44);//启动温度测量
b1820_delay(300);
init_ds18b20();
write_byte(0xcc);
write_byte(0xbe);
a=read_byte();//读低8位
b=read_byte();//读第二个8位
c=b*256+a;
returnc;
}
voidchange_temperature()
{
uinttemp;
uchartp;
temp=readtemperature()>>3;
//readtemperature()/256;
tp=temp&0x01;
if(tp==1)//显示小数
lcd_com_dat(0x4d,5);
else
lcd_com_dat(0x4d,0);
temp=readtemperature()>>4;//显示整数部分
lcd_com_dat(0x4a,temp/10%10);
lcd_com_dat(0x4b,temp%10);
lcd_com_dat(0x4c,0x2e-0x30);
lcd_com_dat(0x4e,0xdf-0x30);
lcd_com_dat(0x4f,'C');
}
//*****************************************************************
//*****************************************************************
voidkey_c