电子钟毕业论文
#include"DS18B20_3。h "
#定义uint无符号整数
#定义uchar无符号字符
uchar a,苗,石,分,日,月,年,周,旗,key1n,temp
//flag用于读取头文件中的温度值并显示温度值。
#定义YH 0x 80//LCD第一行的初始位置,因为LCD1602字符地址的第一位D7恒定为1 (10000000 = 80)。
# definer 0x 80+0x40//LCD第二行的初始位置(因为第二行的第一个字符位置地址是0x 40)
LCD与C51引脚连接定义(显示数据线接C51的P0口)
sbit rs=p1^0;
sbit en=p1^2;
sbit rw=p1^1;//如果rw在硬件上是接地的,就不需要写这句话和rw=0。
sbit led=p3^7;//LCD背光开关
//DS1302时钟芯片与C51引脚连接定义
sbit io=p2^2;
sbit sclk=p2^1;
sbit rst=p2^2;
sbit acc0=acc^0;
sbit acc7=acc^7;
/************************************************************
ACC累加器=A
加速0=E0H
ACC.0是ACC的第0位。Acc可以是位寻址的。
累加器ACC是一个8位存储单元,用来放数据。然而,这个存储单元有其特殊的位置。
它是单片机中非常关键的单元,很多操作都要通过ACC来进行。以后学指令的时候,
通常用来表示累加器。但是也有一些例外,比如在PUSH指令中,必须使用ACC这个名字。
一般来说,A代表累加器的内容,ACC代表累加器的地址。
***************************************************************/
//时间校准键与C51引脚连接定义
sbit key1=p2^4;//设置密钥
sbit key2=p2^5;//键控
sbit key3=p2^6;//键还原
sbit buzzer=p2^0;//蜂鸣器,晶体管9012驱动,低电平端口响应。
/**************************************************************/
uchar代码tab 1[]= { " 20--" };//固定显示年份的字符
uchar代码tab 2[]= { "::" };//时间显示的固定字符
//延迟函数,后面经常调用。
void delay(uin TMS)//延迟函数,参数函数
{
uint x,y;
for(x = xms;x & gt0;x -)
for(y = 120;y & gt0;y-);
}
/* * * * * * * * LCD写指令功能和写数据功能,可以叫* * * * * * * * * */
/*在这个程序中,与液晶写入相关的函数会在DS1302的函数中调用,所以液晶程序要放在前面*/
write _ 1602 com(uchircom)/* * * * LCD写命令功能* * * *
{
RS = 0;//数据/指令选择设置为指令。
rw = 0;//读写选择设置为写。
P0 = com//发送数据
延时(1);
en = 1;//拉高enable引脚,为有效下降沿做准备。
延时(1);
en = 0;//en由高变低,产生下降沿,液晶执行命令。
}
write _ 1602 dat(uchardat)/* * * LCD写入数据功能* * * *
{
RS = 1;//数据/命令选择设置为数据
rw = 0;//读写选择设置为写。
P0 = dat//发送数据
延时(1);
en = 1;//en设为高电平,为下降沿做准备。
延时(1);
en = 0;//en由高变低,产生下降沿,液晶执行命令。
}
LCD _ init ()/* * * LCD初始化函数* * * *
{
write _ 1602 com(0x 38);//设置LCD工作模式,含义:16*2行显示,5*7点阵,8位数据。
write _ 1602 com(0x0c);//打开显示,但不显示光标
write _ 1602 com(0x 06);//整个屏幕不动,光标自动向右移动。
write _ 1602 com(0x 01);//清除显示
write _ 1602 com(yh+1);//日历显示固定符号在第一行第1位后开始显示。
for(a = 0;a & lt14;a++)
{
write _ 1602 dat(tab 1[a]);//将日历显示的固定符号部分写入液晶屏。
//delay(3);
}
write _ 1602 com(er+2);//时间显示固定的符号书写位置,从第二个位置开始。
for(a = 0;a & lt8;a++)
{
write _ 1602 dat(tab 2[a]);//写一个固定显示时间的符号,两个冒号。
//delay(3);
}
}
/********************超过******************/
/* * * * * * * * * * * * DS1302相关子功能* * * * * * * * * * * * * *
Void write_byte(uchar dat)//写入一个字节。
{
ACC = dat
RST = 1;
for(a = 8;a & gt0;答-)
{
IO = ACC0
SCLK = 0;
SCLK = 1;
ACC = ACC & gt& gt1;
}
}
Uchar read_byte()//读取一个字节。
{
RST = 1;
for(a = 8;a & gt0;答-)
{
ACC7 = IO
SCLK = 1;
SCLK = 0;
ACC = ACC & gt& gt1;
}
返回(ACC);
}
// -
Voidwrite _ 1302 (uchar add,uchar dat)//向1302芯片写一个函数,指定写地址和数据。
{
RST = 0;
SCLK = 0;
RST = 1;
write_byte(添加);
写入字节(dat);
SCLK = 1;
RST = 0;
}
uchar Read _ 1302(uchar add)//从1302读取数据函数,指定读取数据的源地址。
{
uchar温度;
RST = 0;
SCLK = 0;
RST = 1;
write_byte(添加);
temp=read_byte()。
SCLK = 1;
RST = 0;
返回(临时);
}
uchar BCD _ decimal(uchar BCD)//BCD码到decimal函数,输入BCD,返回decimal。
{
uchar十进制;
Decimal = bcd & gt& gt4;
return(Decimal = Decimal * 10+(BCD & amp;= 0x0F));
}
// -
void DS 1302 _ init()//1302芯片初始化子函数(2010-01-07,12: 00: 00,第4周)
{
RST = 0;
SCLK = 0;
write_1302(0x8e,0x 00);//允许写入,禁止写保护。
write_1302(0x80,0x 00);//将初始第二数据00写入DS1302中的写第二寄存器80H。
write_1302(0x82,0x 00);//将初始子数据00写入DS1302中的写子寄存器82H。
write_1302(0x84,0x 12);//将初始小时数据12写入DS1302中的写小时寄存器84H。
write_1302(0x8a,0x 04);//将初始周数据4写入DS1302中的写周寄存器8aH。
write_1302(0x86,0x 07);//将初始日期数据07写入DS1302中的写日期寄存器86H。
write_1302(0x88,0x 01);//将初始月份数据01写入DS1302中的写月份寄存器88H。
write_1302(0x8c,0x 10);//将初始年份数据10写入DS1302中的写年份寄存器8cH。
write_1302(0x8e,0x 80);//打开写保护
}
// -
//温度显示子功能
Voidwrite _ temp (uchar add,uchar dat)//将温度数据写入LCD并指定显示位置。
{
uchar gw,SW;
GW = dat % 10;//获取个位数。
SW = dat/10;//获取十位数
write _ 1602 com(er+add);//er是头文件中指定的值0x80+0x40。
write _ 1602 dat(0x 30+SW);//Number +30得到该号码的LCD1602显示码。
write _ 1602 dat(0x 30+GW);//Number +30得到该号码的LCD1602显示码。
write _ 1602 dat(0x df);//显示温度的小圆圈符号,0xdf是该符号在LCD字符库中的地址码。
write _ 1602 dat(0x 43);//显示符号“C”,0x43是LCD字符库中大写C的地址码。
}
// -
//以分、秒显示子功能。
Voidwrite _ SFM (UCHAR ADD,UCHAR DAT)//写入LCD时,有两个参数:显示位置加当前数据。
{
uchar gw,SW;
GW = dat % 10;//获取个位数。
SW = dat/10;//获取十位数
write _ 1602 com(er+add);//er是头文件中指定的值0x80+0x40。
write _ 1602 dat(0x 30+SW);//Number +30得到该号码的LCD1602显示码。
write _ 1602 dat(0x 30+GW);//Number +30得到该号码的LCD1602显示码。
}
// -
//年、月、日显示子功能。
Voidwrite _ nyr (uchar add,uchar dat)//将年月日写入LCD,有两个参数:显示位置加数和显示数据。
{
uchar gw,SW;
GW = dat % 10;//获取个位数。
SW = dat/10;//获取十位数
write _ 1602 com(yh+add);//将显示位置设置为第一个位置+add
write _ 1602 dat(0x 30+SW);//Number +30得到该号码的LCD1602显示码。
write _ 1602 dat(0x 30+GW);//Number +30得到该号码的LCD1602显示码。
}
// -
Void write_week(uchar week)//写周函数
{
write _ 1602 com(yh+0x0c);//显示星期几字符的位置
切换(周)
{
case 1:write _ 1602 dat(' M ');//当周数为1时,显示。
write _ 1602 dat(' O ');
write _ 1602 dat(' N ');
打破;
情况二:write _ 1602 dat(' T ');//当周数据为2时显示。
write _ 1602 dat(' U ');
write _ 1602 dat(' E ');
打破;
案例三:write _ 1602 dat(' W ');//当周数据为3时显示。
write _ 1602 dat(' E ');
write _ 1602 dat(' D ');
打破;
案例四:write _ 1602 dat(' T ');//显示4的周数据。
write _ 1602 dat(' H ');
write _ 1602 dat(' U ');
打破;
情况5:write _ 1602 dat(' F ');//当周数据为5时显示。
write _ 1602 dat(' R ');
write _ 1602 dat(' I ');
打破;
案例6:write _ 1602 dat(' S ');//当周数据为6时显示。
write _ 1602 dat(' T ');
write _ 1602 dat(' A ');
打破;
案例7:write _ 1602 dat(' S ');//当周数据为7时显示。
write _ 1602 dat(' U ');
write _ 1602 dat(' N ');
打破;
}
}
//* * * * * * * * * * * * * *键盘扫描相关功能* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *。
void键扫描()
{
如果(key1 = = 0)/ - key1是功能键(设置键)-。
{
延迟(9);//延迟,用于消除抖动
If(key1==0)//延迟一段时间后,确认再次按键。
{
蜂鸣器= 0;//蜂鸣器响一次。
延迟(20);
蜂鸣器= 1;
而(!key 1);
key 1n++;
if(key1n==9)
key 1n = 1;//设置按钮* * *有八个功能循环:秒、分、小时、周、日、月、年、返回。
开关(钥匙1n)
{
案例1:TR0 = 0;//关闭计时器
//tr 1 = 0;
write _ 1602 com(er+0x 09);//按一次设置键,光标以秒为单位显示。
write _ 1602 com(0x0f);//将光标设置为闪烁。
temp=(苗)/10*16+(苗)% 10;//sec数据写入DS1302。
write_1302(0x8e,0x 00);
write_1302(0x80,0x 80 | temp);//苗
write_1302(0x8e,0x 80);
打破;
案例二:write _ 1602 com(er+6);//按两下fen位置显示光标。
//write _ 1602 com(0x0f);
打破;
案例三:write _ 1602 com(er+3);//按三下,石
//write _ 1602 com(0x0f);
打破;
情况四:write _ 1602 com(yh+0x0e);//每周按4次
//write _ 1602 com(0x0f);
打破;
案例五:write _ 1602 com(yh+0);//按5次,ri
//write _ 1602 com(0x0f);
打破;
案例六:write _ 1602 com(yh+0x 07);//按6次,曰
//write _ 1602 com(0x0f);
打破;
情况7:write _ 1602 com(yh+0x 04);//按7次,年
//write _ 1602 com(0x0f);
打破;
案例8:
write _ 1602 com(0x0c);//第八次按,设置光标不闪烁。
TR0 = 1;//打开计时器
temp=(苗)/10*16+(苗)% 10;
write_1302(0x8e,0x 00);
write_1302(0x80,0x 00 | temp);//苗数据写入DS1302。
write_1302(0x8e,0x 80);
打破;
}
}
}
// -按下按键键2。
if(key1n!=0)//当按键1被按下时。按以下键有效(击键次数不等于零)
{
If(key2==0) //向上键
{
延时(10);
if(key2==0)
{
蜂鸣器= 0;//蜂鸣器响一次。
延迟(20);
蜂鸣器= 1;
而(!key 2);
开关(钥匙1n)
{
案例1:苗++;//按设置键1次调整秒。
如果(苗==60)
苗= 0;//如果秒超过59,则将1加零。
write_sfm(0x08,苗);//使LCD在正确的位置显示“加号”设定的秒数。
temp=(苗)/10*16+(苗)% 10;//ds 1302要求的十进制转换成DCB码。
write_1302(0x8e,0x 00);//允许写入,禁止写保护。
write_1302(0x80,temp);//将调整后的第二数据BCD码写入DS1302中的写第二寄存器80H。
write_1302(0x8e,0x 80);//打开写保护
write _ 1602 com(er+0x 09);//因为LCD模式设置为写入数据后自动向右移动光标,所以需要指定return。
//write _ 1602 com(0x0b);
打破;
案例二:fen++;
如果(fen==60)
fen = 0;
write_sfm(0x05,fen);//让LCD在正确的位置显示“加号”设定子数据。
temp=(分)/10*16+(分)% 10;//ds 1302要求的十进制转换成DCB码。
write_1302(0x8e,0x 00);//允许写入,禁止写保护。
write_1302(0x82,temp);//将调整后的子数据BCD码写入DS1302的子写寄存器82H。
write_1302(0x8e,0x 80);//打开写保护
write _ 1602 com(er+6);//因为LCD模式设置为写数据,指针会自动加一,这种情况下会写回原来的位置。
打破;
案例三:石++;
if(shi==24)
Shi = 0;
write_sfm(2,Shi);//使LCD在正确的位置显示“加号”设定小时数据。
temp=(石)/10*16+(石)% 10;//ds 1302要求的十进制转换成DCB码。
write_1302(0x8e,0x 00);//允许写入,禁止写保护。
write_1302(0x84,temp);//将调整后的小时数据BCD码写入DS1302中的写小时寄存器84H。
write_1302(0x8e,0x 80);//打开写保护
write _ 1602 com(er+3);//因为LCD模式设置为写数据,指针会自动加一,所以光标需要返回。
打破;
案例四:周++;
if(week==8)
周= 1;
write _ 1602 com(yh+0x0C);//在“加号”后指定周数据的显示位置
write_week(周);//指定每周数据显示内容。
temp=(周)/10*16+(周)% 10;//ds 1302要求的十进制转换成DCB码。
write_1302(0x8e,0x 00);//允许写入,禁止写保护。
write_1302(0x8a,temp);//将调整后的周数据BCD码写入DS1302中的周寄存器8aH。
write_1302(0x8e,0x 80);//打开写保护
write _ 1602 com(yh+0x0e);//因为LCD模式设置为写数据,指针会自动加一,所以光标需要返回。
打破;
案例五:ri++;
如果(ri==32)
ri = 1;
write_nyr(9,ri);//使LCD在正确的位置显示“加号”设定日期数据。
temp =(ri)/10 * 16+(ri)% 10;//ds 1302要求的十进制转换成DCB码。
write_1302(0x8e,0x 00);//允许写入,禁止写保护。
write_1302(0x86,temp);//将调整后的日期数据BCD码写入DS1302中的写日期寄存器86H。
write_1302(0x8e,0x 80);//打开写保护
write _ 1602 com(yh+10);//因为LCD模式设置为写数据,指针会自动加一,所以光标需要返回。
打破;
案例六:岳++;
if(岳==13)
岳= 1;
write_nyr(6,岳);//使LCD在正确的位置显示“加号”设定的月份数据。
temp=(岳)/10*16+(岳)% 10;//ds 1302要求的十进制转换成DCB码。
write_1302(0x8e,0x 00);//允许写入,禁止写保护。
write_1302(0x88,temp);//将调整后的月份数据BCD码写入DS1302中的月份写入寄存器88H。
write_1302(0x8e,0x 80);//打开写保护
write _ 1602 com(yh+7);//因为LCD模式设置为写数据,指针会自动加一,所以光标需要返回。
打破;
案例7:年++;
if(年==100)
年= 0;
write_nyr(3,年);//使LCD在正确的位置显示“加号”的设定年份数据。
temp=(年)/10*16+(年)% 10;//ds 1302要求的十进制转换成DCB码。
write_1302(0x8e,0x 00);//允许写入,禁止写保护。
write_1302(0x8c,temp);//将调整后的年份数据BCD码写入DS1302中的年份寄存器8cH。
write_1302(0x8e,0x 80);//打开写保护
write _ 1602 com(yh+4);//因为LCD模式设置为写数据,指针会自动加一,所以光标需要返回。
打破;
}
}
}
// - key3。有关每个句子的功能,请参考“Keying”注释。
if(key3==0)
{
延时(10);//延迟调整和抖动消除
if(key3==0)
{
蜂鸣器= 0;//蜂鸣器响一次。
延迟(20);
蜂鸣器= 1;
而(!key 3);
开关(钥匙1n)
{
案例1:苗-;
if(苗==-1)
苗= 59;//秒数据还原为-1时自动变成59。
write_sfm(0x08,苗);//在LCD的正确位置显示更改后的新秒数。
temp=(苗)/10*16+(苗)% 10;//ds 1302要求的十进制转换成DCB码。
write_1302(0x8e,0x 00);//允许写入,禁止写保护。
write_1302(0x80,temp);//将调整后的第二数据BCD码写入DS1302中的写第二寄存器80H。
write_1302(0x8e,0x 80);//打开写保护
write _ 1602 com(er+0x 09);//因为LCD模式设置为写数据,指针会自动加一,这种情况下会写回原来的位置。
//write _ 1602 com(0x0b);
打破;
案例2:fen-;
if(fen==-1)
fen = 59
write_sfm(5,fen);
temp=(分)/10*16+(分)% 10;//ds 1302要求的十进制转换成DCB码。
write_1302(0x8e,0x 00);//允许写入,禁止写保护。
write_1302(0x82,temp);//将调整后的子数据BCD码写入DS1302的子写寄存器82H。
write_1302(0x8e,0x 80);//打开写保护
write _ 1602 com(er+6);//因为LCD模式设置为写数据,指针会自动加一,这种情况下会写回原来的位置。
打破;
案例三:石-;
if(shi==-1)
石= 23;
write_sfm(2,Shi);
temp=(石)/10*16+(石)% 10;//ds 1302要求的十进制转换成DCB码。
write_1302(0x8e,0x 00);//允许写入,禁止写保护。
write_1302(0x84,temp);//将调整后的小时数据BCD码写入DS1302中的写小时寄存器84H。
write_1302(0x8e,0x 80);//打开写保护
write _ 1602 com(er+3);//因为LCD模式设置为写数据,指针会自动加一,所以光标需要返回。
打破;
案例四:周-;
if(week==0)
周= 7;
write _ 1602 com(yh+0x0C);//在“加号”后指定周数据的显示位置
write_week(周);//指定每周数据显示内容。
temp=(周)/10*16+(周)% 10;//ds 1302要求的十进制转换成DCB码。
write_1302(0x8e,0x 00);//允许写入,禁止写保护。
write_1302(0x8a,temp);//将调整后的周数据BCD码写入DS1302中的周寄存器8aH。
write_1302(0x8e,0x 80);//打开写保护
write _ 1602 com(yh+0x0e);//因为LCD模式设置为写数据,指针会自动加一,所以光标需要返回。
打破;
案例5:ri-;
如果(ri==0)
ri = 31;
write_nyr(9,ri);
temp =(ri)/10 * 16+(ri)% 10;//ds 1302要求的十进制转换成DCB码。
write_1302(0x8e,0x 00);//允许写入,禁止写保护。
write_1302(0x86,temp);//将调整后的日期数据BCD码写入DS1302中的写日期寄存器86H。
write_1302(0x8e,0x 80);//打开写保护
write _ 1602 com(yh+10);//因为LCD模式设置为写数据,指针会自动加一,所以光标需要返回。
打破;
案例6:岳-;
如果(岳==0)
岳= 12;
write_nyr(6,岳);
temp=(岳)/10*16+(岳)% 10;//ds 1302要求的十进制转换成DCB码。
write_1302(0x8e,0x 00);//允许写入,禁止写保护。
write_1302(0x88,temp);//将调整后的月份数据BCD码写入DS1302中的月份写入寄存器88H。
write_1302(0x8e,0x 80);//打开写保护
write _ 1602 com(yh+7);//因为LCD模式设置为写数据,指针会自动加一,所以光标需要返回。
打破;
案例7:年-;
if(年==-1)
年= 99;
write_nyr(3,年);
temp=(年)/10*16+(年)% 10;//ds 1302要求的十进制转换成DCB码。
write_1302(0x8e,0x 00);//允许写入,禁止写保护。
write_1302(0x8c,temp);//将调整后的年份数据BCD码写入DS1302中的年份寄存器8cH。
write_1302(0x8e,0x 80);//打开写保护
write _ 1602 com(yh+4);//因为LCD模式设置为写数据,指针会自动加一,所以光标需要返回。
打破;
}
}
}
}
}
// -
Void init() //定时器,计数器设置函数
{
TMOD = 0x 11;//指定定时器/计数器的工作模式为3。
TH0 = 0;//定时器T0 =0的高四位
TL0 = 0;//定时器T0 =0的低四位
EA = 1;//系统允许打开中断。
ET0 = 1;//允许T0中断
TR0 = 1;//打开中断,启动定时器。
}
//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
//***************************************************
void main()
{
LCD _ init();//调用LCD初始化子函数。
ds 1302 _ init();//调用DS1302时钟的初始化子函数。
init();//调用定时器计数器的设置子函数。
led = 0;//打开LCD的背光电源。
蜂鸣器= 0;//蜂鸣器响一次。
延迟(80);
蜂鸣器= 1;
While(1) //无限循环下面的语句:
{
key scan();//调用键盘扫描子函数。
}
}
Void timer0()中断1 //获取并显示日历和时间。
{
//Init _ ds 18b 20();//温度传感器DS18b2的初始化子函数在头文件中。
flag = read temperature();//将运行18b2头文件返回的函数结果发送到变量FLAG显示。
//以秒为单位读取周、月、年、年七个数据(DS1302的读寄存器与写寄存器不同):
Miao = BCD _ Decimal(read _ 1302(0x 81));
fen = BCD _ Decimal(read _ 1302(0x 83));
Shi = BCD _ Decimal(read _ 1302(0x 85));
ri = BCD _ Decimal(read _ 1302(0x 87));
岳= BCD _ Decimal(read _ 1302(0x 89));
nian = BCD _ Decimal(read _ 1302(0x8d));
week = BCD _ Decimal(read _ 1302(0x8b));
//显示温度、秒、小时和分钟数据:
write_temp(12,flag);//显示温度,从第二行第12个字符开始。
write_sfm(8,苗);//秒,从第二行的第八个字开始(调用时每秒显示一次子函数)
write_sfm(5,fen);//分钟,从第二行第五个字符开始。
write_sfm(2,Shi);//小时,从第二行第二个字符开始。
//显示日期、月份和年份数据:
write_nyr(9,ri);//日期,显示在第二行第九个字符之后。
write_nyr(6,岳);//月份,显示在第二行第六个字符之后。
write_nyr(3,年);//年份,从第二行第三个字符开始。
write_week(周);
}