资源描述
湖北文理学院物理与电子工程学院11应用电子专业综合课程设计---------智能电子钟
专业综合课程设计报告
题目:智能电子钟(LCD)
题目智能电子钟(LCD)
一、 设计要求:
制作一个LCD显示的智能电子钟:
(1) 计时:秒、分、时、日、月、年、星期。
(2) 闰年自动判别。
(3) 时间、年、月、日、星期交替显示。
(5) 自定任意时刻自动开/关屏。
(6) 计时精度:误差≤1秒/月(具有微调设置)。
二、 方案论证:
本实验可采用并行时钟芯片(DS12C887)和串行时钟芯片(DS1302),DS1302要用户自己安装后备电池和串口通讯,要32.768KHz的晶振,而DS12C887自带后备电池,并口通讯,无需外围元件,并且DS12C887多了一个字节来记录世纪使用的,处在RAM的32H单元,但是其他的寄存器定义都相同。由于本实验用到了STC12C5A60S2直插40P封装的单片机、nokia5110液晶屏、独立式按键、四路2输入与门并且都是直插的,而且在实验室做PCB只能是单层板,为了节约空间和简化电路于是就选用了串行时钟芯片DS1302。
三、 理论设计:
用CAD软件绘制的硬件原理图
电源和程序下载端口,此部分的USB可提供电源和下载端口适用于USB下载端口,DOWN端口适用于四角插针式下载、BAT为备用电源端口。
CPU主控部分,此部分采用的是高速51系列的STC12C5A60S2的单片机,该芯片不仅运行速度快稳定驱动能力更大,还为用户提供了内部集成8位/10位可调分辨率ADC模块(在此设计中有用到),1KB可擦写EEPROM本设计中用其设计成可调闹钟功能存放闹钟值。
此图为串行数据nokia5110的LCD显示器模块,采用可控背光和可控电源有很好的节能效果。该显示器能显示汉字,字符,图片、并且处理显示数据速度快。
此模块为串行数据实时时钟模块,此模块采用的是达拉斯公司生产的DS1302具有闰年补偿。
此图为按键中断模块,在此模块中每个独立式按键都能申请外部中断及时处理按键按下的值来执行用户的操作。
此图为蜂鸣器模块此模块用于闹钟铃声设计,和开机提示。
此图为PCB版图
此图为PCB打印预览
软件流程图
开始
按键检测,判断按键是否按下
yes其他键 yes
按下目录键
NO
时间处理
初始化时钟
功能1(时间)
内部子程序,包括键值处理,加减上下,确认,背光控制,闹钟,时间日期的设置
温度处理
读数据
功能2(温度)
电压处理
数据处理
功能3(电压)
显示
闹钟处理
功能4(闹钟)
返回
程序清单
完整C程序源代码
/**************************************************************************************
* 主程序:顶层程序 *
* 显示默认功能:时间日期显示; *
* 调用子程序; *
* *
***************************************************************************************/
# include <intrins.h>
# include "zimo.h" //字模程序;
# include "nokia5110.h"//5110驱动程序;
# include "ds1302.h" //ds1302驱动程序;
# include "key.h" //按键扫描程序;
# include "printf.h" //显示函数;
# include "power.h" //电源模块;
# include "main.h" //引脚定义;
# include "delay.h" //延时函数;
# include "macroandconst.h"//数据类型宏定义;
# include "ADC.H" //ADC电压测量
# include "ds18b20.h" //温度模块;
void main()
{
system_inint(); //系统初始化;
//Set_RTC();
while(1)
{
checkclock();
caidan(); //菜单显示;
if(menue==0)
{
if(ok==1)
{
LCD_clear(); //清屏幕
while(menue==0) //由此进入时钟功能
{
ok=0;
logo();
Read_RTC();//读取时钟;
data_change();//时钟数据处理
tiaozheng_flag();
date_time(); //显示年月日时分秒;
week();//星期处理;
set_date_time();//设置改变时间和日期;
powervcc();
checkclock();
}
LCD_clear(); //清屏幕
}
}
else if(menue==1) //由此进入温度检测功能
{
if(ok==1)
{
LCD_clear(); //清屏幕
while(menue==1)
{
temperatuercheck();
ok=0;
}
LCD_clear(); //清屏幕
}
}
else if(menue==2) //由此进入电压测量功能
{
if(ok==1)
{
LCD_clear(); //清屏幕
while(menue==2)
{
power();//电量检测
ok=0;
}
LCD_clear(); //清屏幕
}
}
else if(menue==3)//由此进入闹钟功能
{
if(ok==1)
{
LCD_clear(); //清屏幕
while(menue==3)
{
clock();
ok=0;
checkclock();
}
LCD_clear(); //清屏幕
}
}
else {LCD_clear(); caidan();}
}
}
void extern0() interrupt 0 /*外部中断0中断函数定义;*/
{
key();
}
/**************************************************************************************
* 子程序:底层程序 *
* 功能:时间日期数据处理; *
* *
* *
***************************************************************************************/
# include <intrins.h>
# include "macroandconst.h"
# include "stc12c5a60s2.h"
# include "nokia5110.h"
sbit SCK = P0^2; //DS1302时钟;
sbit SDA = P0^1; //DS1302数据;
sbit RST = P0^0;// DS1302复位;
uchar l_tmpDate[]={0,0,0,1,1,1,13};//秒分时日月周年08-05-15 12:00:00
uchar l_tmpdisplay[13];
code uchar Write_rtc_address[7]={0x80,0x82,0x84,0x86,0x88,0x8a,0x8c}; //秒分时日月周年 最低位读写位
code uchar Read_RTC_address[7]={0x81,0x83,0x85,0x87,0x89,0x8b,0x8d};
/******************************************************************/
/* 写一个字节 */
/******************************************************************/
void Write_Ds1302_Byte(unsigned char temp)
{
unsigned char i;
for (i=0;i<8;i++) //循环8次 写入数据
{
SCK=0;
SDA=temp&0x01; //每次传输低字节
temp>>=1; //右移一位
SCK=1;
}
}
/******************************************************************/
/* 写入DS1302 */
/******************************************************************/
void Write_Ds1302( unsigned char address,unsigned char dat )
{
RST=0;
_nop_();
SCK=0;
_nop_();
RST=1;
_nop_(); //启动
Write_Ds1302_Byte(address); //发送地址
Write_Ds1302_Byte(dat); //发送数据
RST=0; //恢复
}
/******************************************************************/
/* 读出DS1302数据 */
/******************************************************************/
unsigned char Read_Ds1302 ( uchar address )
{
unsigned char i,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;
} //每次传输低字节
temp>>=1; //右移一位
SCK=1;
_nop_();
_nop_();
SCK=0;
}
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); //返回
}
/******************************************************************/
/* 读时钟数据 */
/******************************************************************/
void Read_RTC(void) //读取 日历
{
unsigned char i,*p;
p=Read_RTC_address; //地址传递
for(i=0;i<7;i++) //分7次读取 秒分时日月周年
{
l_tmpDate[i]=Read_Ds1302(*p);
p++;
}
}
/******************************************************************/
/* 设定时钟数据 */
/******************************************************************/
void Set_RTC(void) //设定 日历
{
uchar i,*p,tmp;
for(i=0;i<7;i++)
{ //BCD处理
tmp=l_tmpDate[i]/10;
l_tmpDate[i]=l_tmpDate[i]%10;
l_tmpDate[i]=l_tmpDate[i]+tmp*16;
}
Write_Ds1302(0x8E,0X00); //关闭写保护;
p=Write_rtc_address; //传地址
for(i=0;i<7;i++) //7次写入 秒分时日月周年
{
Write_Ds1302(*p,l_tmpDate[i]);
p++;
}
Write_Ds1302(0x8E,0x80); //打开写保护;
}
/**************************************************************************************
* 子程序:底层程序 *
* 功能:按键处理,键值显示; *
* *
* *
***************************************************************************************/
# include "main.h"
# include "ds1302.h"
# include "nokia5110.h"
# include "delay.h"
# include "printf.h"
# include "eeprom.h"
uchar set=0; //按键选择标志位;
char key_flag=0;//按键加减标志位;
uchar menue=0; //菜单选择标志位;
uchar ok=0; //确认标志位;
char miao,fen,shi,ri,yue,zhou,nian;/*时间日期数值标志位;*/
uchar clocktable[5]; //分,时,星期;
char hour=7;
char minute=30;
char week2=1;
void Delay10ms() //@11.0592MHz
{
unsigned char i, j;
i = 108;
j = 145;
do
{
while (--j);
} while (--i);
}
void key()
{
EA=0;
/*判断选择按键是否按下;如果按下了当松开的时候让背光打开;set++;*/
if(keyswitch==0)
{
Delay10ms();
if(keyswitch==0)
{
Delay10ms();
while(keyswitch==0);
LCD_BLA=1;
if(set>8)set=0;
set++;
}
}
/*up和down按键的检测;加减标志位*/
if(keyup==0)
{ Delay10ms();
if(keyup==0)
{
LCD_BLA=1;
Delay10ms();
while(keyup==0);
key_flag++;
}
}
if(keydown==0)
{ Delay10ms();
if(keydown==0)
{
LCD_BLA=1;
Delay10ms();
while(keydown==0);
key_flag--;
}
}
if(keymenue==0)
{
Delay10ms();
if(keymenue==0) //菜单选择标志位;
{
Delay10ms();
while(keymenue==0);
LCD_BLA=1;
menue++;
if(menue>3)menue=0;
}
} if(keyok==0)
{
Delay10ms();
if(keyok==0) //确认标志位;
{ Delay10ms();
while(keyok==0);
ok++;
if(ok>1)ok=0;
set=0;LCD_BLA=0;TR0 = 0;
}
}
if(set>=2)TR0 = 0;
EA=1;
}
void set_date_time()
{
if(set==2)
{
// while(keyup==0|keydown==0);
{
miao=l_tmpdisplay[10]*10+l_tmpdisplay[11];
miao=miao+key_flag;
if((key_flag<0)&(miao==0))miao=59;
if(miao>59)miao=0;
miao=miao%10+(miao/10)*16;
Write_Ds1302(0x8E,0x00);
Write_Ds1302(0x80,miao);
Write_Ds1302(0x8E,0x80);
}
}
if(set==3)
{
// while(keyup==0||keydown==0);
{
fen=l_tmpdisplay[8]*10+l_tmpdisplay[9];
fen=fen+key_flag;
if(fen>59)
{
fen=0;
}
if((key_flag<0)&&(fen<0))
{
fen=59;
}
fen=fen%10+(fen/10)*16;
Write_Ds1302(0x8E,0x00);
Write_Ds1302(0x82,fen);
Write_Ds1302(0x8E,0x80);
}
}
if(set==4)
{
// while(keyup==0||keydown==0);
{
shi=l_tmpdisplay[6]*10+l_tmpdisplay[7];
shi=shi+key_flag;
if(shi>23)shi=0;
if((key_flag<0)&&(shi<0))shi=23;
shi=shi%10+(shi/10)*16;
Write_Ds1302(0x8E,0x00);
Write_Ds1302(0x84,shi);
Write_Ds1302(0x8E,0x80);
}
}
if(set==5)
{
// while(keyup==0||keydown==0);
{
ri=l_tmpdisplay[4]*10+l_tmpdisplay[5];
ri=ri+key_flag;
if(ri>31)ri=1;
if((key_flag<0)&&(ri<1))ri=31;
ri=ri%10+(ri/10)*16;
Write_Ds1302(0x8E,0x00);
Write_Ds1302(0x86,ri);
Write_Ds1302(0x8E,0x80);
}
}
if(set==6)
{
//while(keyup==0||keydown==0);
{
yue=l_tmpdisplay[2]*10+l_tmpdisplay[3];
yue=yue+key_flag;
if(yue>12)yue=1;
if((key_flag<0)&&(yue<1))yue=12;
yue=yue%10+(yue/10)*16;
Write_Ds1302(0x8E,0x00);
Write_Ds1302(0x88,yue);
Write_Ds1302(0x8E,0x80);
}
}
if(set==7)
{
//while(keyup==0||keydown==0);
{
zhou=l_tmpdisplay[12];
zhou=zhou+key_flag;
if(zhou>7)zhou=1;
if((key_flag<0)&&(zhou<1))zhou=7;
zhou=zhou%10+(zhou/10)*16;
Write_Ds1302(0x8E,0x00);
Write_Ds1302(0x8A,zhou);
Write_Ds1302(0x8E,0x80);
}
}
if(set==8)
{
// while(keyup==0||keydown==0);
{
nian=l_tmpdisplay[0]*10+l_tmpdisplay[1]+key_flag;;
if(nian>79)nian=0;
if((key_flag<0)&&(nian<0))nian=79;
nian=nian%10+(nian/10)*16;
Write_Ds1302(0x8E,0x00);
Write_Ds1302(0x8C,nian);
Write_Ds1302(0x8E,0x80);
}
}
key_flag=0;
}
void caidan()
{
uchar counter;
uchar function;
/*光标显示位置控制*/
if(menue==0)
{
LCD_write_hanzi(0,4,10);Delay1ms(120);LCD_write_hanzi(0,0,3);Delay1ms(120);LCD_write_hanzi(0,2,10);LCD_write_hanzi(4,0,10);
}
else if(menue==1)
{
LCD_write_hanzi(0,0,10);Delay1ms(120);LCD_write_hanzi(0,2,3);Delay1ms(120);LCD_write_hanzi(0,4,10);LCD_write_hanzi(4,0,10);
}
else if(menue==2)
{
LCD_write_hanzi(0,2,10);Delay1ms(120);LCD_write_hanzi(0,4,3);Delay1ms(120);LCD_write_hanzi(0,0,10);LCD_write_hanzi(4,0,10);
}
else if(menue==3)
{LCD_write_hanzi(0,4,10);Delay1ms(120);LCD_write_hanzi(0,0,10);Delay1ms(120);LCD_write_hanzi(0,2,10);LCD_write_hanzi(4,0,28);}
else
{
LCD_write_hanzi(0,4,10);Delay1ms(120);LCD_write_hanzi(0,0,3);Delay1ms(120);LCD_write_hanzi(0,2,10);LCD_write_hanzi(4,0,10);
}
for(function=0;function<2;function++)
{
LCD_write_hanzi(function+1,0,function+4);
LCD_write_hanzi(function+1,2,function+6);
LCD_write_hanzi(function+1,4,function+8);
}
if(set<2)
{
TR0 = 1;
if(TF0==1)
{
counter++;
TF0=0;
}
if(counter==100)
{
counter=0;LCD_BLA=0;TR0 = 0;
if(menue==0)ok=1;
}
}
}
/*闹钟程序 */
void clock()
{
Read_RTC();//读取时钟;
data_change();//时钟数据处理
if(set==2)
{
// while(keyup==0||keydown==0);
{
minute+=key_flag;
if((key_flag<0)&(minute==0))minute=59;
if(minute>59)minute=0;
EA=0;//使用iap功能时关闭中断;
hour=R_EROM(1,2);//读闹钟小时数据;
week2=R_EROM(1,3);//读闹钟分数据;
C_EROM(1);
W_EROM(1,1,minute); //写闹钟分数据;
W_EROM(1,2,hour); //写闹钟小时数据;
W_EROM(1,3,week2);//写闹钟星期数据;
EA=1;//不使用iap功能时打开中断;
}
key_flag=0;
}
if(set==3)
{
// while(keyup==0||keydown==0);
{
hour=hour+key_flag;
if(hour>23)hour=0;
if((key_flag<0)&&(hour<0))hour=23;
}
EA=0;//使用iap功能时关闭中断
minute=R_EROM(1,1);
week2=R_EROM(1,3);
C_EROM(1);
W_EROM(1,1,minute);
W_EROM(1,2,hour);
W_EROM(1,3,week2);
EA=1;//不使用iap功能时打开中断;
key_flag=0;
}
if(set==4)
{
// while(keyup==0||keydown==0);
{
week2=week2+key_flag;
if(week2>7)week2=1;
if((key_flag<0)&&(week2<1))week2=7;
}
EA=0;//使用iap功能时关闭中断
minute=R_EROM(1,1);
hour=R_EROM(1,2);
C_EROM(1);
W_EROM(1,1,minute);
W_EROM(1,2,hour);
W_EROM(1,3,week2);
EA=1;//不使用iap功能时打开中断;
key_flag=0;
}
EA=0;//使用iap功能时关闭中断
minute=R_EROM(1,1);
hour=R_EROM(1,2);
week2=R_EROM(1,3);
EA=1;//不使用iap功能时打开中断;
clocktable[0]=minute/10;//分十位;
clocktable[1]=minute%10;//分个位
clocktable[2]=hour/10; //时十位
clocktable[3]=hour%10; //时个位
clocktable[4]=week2; //星期;
LCD_write_hanzi(2,0,28);
LCD_write_shu(1,2,clocktable[2]);
LCD_write_shu(2,2,clocktable[3]);//时
LCD_write_shu(3,2,64);
LCD_write_shu(4,2,clocktable[0]);
LCD_write_shu(5,2,clocktable[1]);//分;
if(clocktable[4]==1)
{
LCD_write_6x8shu(10,3,23);
LCD_write_6x8shu(11,3,25);
LCD_write_6x8shu(12,3,24);
}
if(clocktable[4]==2)
{
LCD_write_6x8shu(10,3,30);
LCD_write_6x8shu(11,3,31);
LCD_write_6x8shu(12,3,15);
}
if(clocktable[4]==3)
{
LCD_write_6x8shu(10,3,33);
LCD_write_6x8shu(11,3,15);
LCD_write_6x8shu(12,3,14);
}
if(clocktable[4]==4)
{
LCD_write_6x8shu(10,3,30);
LCD_write_6x8shu(11,3,18);
LCD_write_6x8shu(12,3,31);
}
if(clocktable[4]==5)
{
LCD_write_6x8shu(10,3,16);
LCD_write_6x8shu(11,3,28);
LCD_write_6x8shu(12,3,19);
}
if(clocktable[4]==6)
{
LCD_write_6x8shu(10,3,29);
LCD_write_6x8shu(11,3,11);
LCD_write_6x8shu(12,3,30);
}
if(week2==7)
{
LCD_write_6x8shu(10,3,29);
LCD_write_6x8shu(11,3,31);
LCD_write_6x8shu(12,3,24);
}
switch(set)
{
case 0: LCD_write_6x8shu(10,4,96);LCD_write_6x8shu(11,4,96);LCD_write_6x8shu(12,4,96);LCD_write_6x8shu(13,4,96);break;
case 1: LCD_write_6x8shu(10,4,96);LCD_write_6x8shu(11,4,96);LCD_write_6x8shu(12,4,96);LCD_write_6x8shu(13,4,96);break;
case 2: Delay100ms();LCD_write_shu(4,2,76);LCD_write_shu(5,2,76);Delay100ms(); LCD_write_6x8shu(10,4,96);LCD_write_6x8shu(11,4,23);LCD_write_6x8shu(12,4,45);LCD_write_6x8shu(13,4,50);break;
case 3: Delay100ms();LCD_
展开阅读全文