实验报告多功能万年历.docx
《实验报告多功能万年历.docx》由会员分享,可在线阅读,更多相关《实验报告多功能万年历.docx(27页珍藏版)》请在冰豆网上搜索。
实验报告多功能万年历
单片机实验项目中期报告
多功能万年历
课程名称:
单片机原理及应用
组别:
第二十组
小组成员:
****************
班级:
****************
一、总体设计
由于我们实验是在网上购买的现成的开发板来学习和使用的,故在方案的选择上也只能限于开发板设计好的电路和芯片。
系统分为主控模块、时钟电路模块、温度检测模块,按键扫描模块,LCD显示模块,电源电路、复位电路、晶振电路等模块。
该设计采用STC89C52芯片实现单片机万年历功能。
设计应具有时间显示,年月日显示等功能。
依据需求可扩展实现农历显示功能。
运用proteus进行仿真,实现电路仿真。
运用C语言实现软件相关功能。
焊接并完成作品调试。
二、详细设计
1、各模块、元器件的型号及功能
主控模块采用AT89C52单片机,STC89C52,ATMEL的51系列单片机。
支持串口下载,使用非常方便,且具有很大的价格优势。
缺点是仅支持串口下载,不支持在线下载,使用中会有些不方便。
按键模块用四个按键,用于调整时间,显示模块采用LCD1602,时钟电路模块采用DS1302时钟芯片实现对时间、日期的操作,温度模块使用18B20实现度温度的操作。
2、流程图
3、软件仿真电路图
4、实物连接图
三、目前实现的功能(录制视频)
四、小组分工情况
李彪:
连接电路,进行程序的烧写。
王进:
收集资料,参与相关连接。
于红红:
程序读写,对实物的介绍。
五、进度安排(截止时间12月23日)
项目实验已完成近70%,有些功能还不能实现,有待完善,预计二十号完成。
六、附录(程序)
#include//调用单片机头文件
#defineucharunsignedchar//无符号字符型宏定义变量范围0~255
#defineuintunsignedint//无符号整型宏定义变量范围0~65535
#include"eeprom52.h"
#include"nongli.h"
bitflag_200ms;
bitflag_100ms;
sbitbeep=P3^7;//蜂鸣器定义
bitflag_beep_en;
uintclock_value;//用作闹钟用的
sbitdq=P3^1;//18b20IO口的定义
sbithw_P32=P3^2;//红外遥控IO口的定义
bitflag_jiema_en=0;//红外解码成功标志位
ucharhw_table[4];//红外解码数据缓冲区
uintt_high=300,t_low=100;
uinttemperature;//温度变量
ucharflag_nl;//农历阳历显示标志位
/********红外遥控器按键的操作码**************
红外遥控对应的数据字节hw_table[2]
454647
444043
071509
16190d
0c185e
081c5a
42524a
*******************************************/
ucharmenu_1,menu_2;
ucharkey_time,flag_value;//用做连加的中间变量
bitkey_500ms;
ucharn_nian,n_yue,n_ri;//农历显示的函数
#include"ds1302.h"
#include"lcd1602.h"
/***********100us的延时函数***12M晶振**************/
voiddelay_100us(ucharz)
{//12M
ucharx,y;
for(x=0;xfor(y=0;y<20;y++);
}
/******************把数据保存到单片机内部eeprom中******************/
voidwrite_eeprom()
{
SectorErase(0x2000);
byte_write(0x2000,fen1);
byte_write(0x2001,shi1);
byte_write(0x2002,open1);
byte_write(0x2003,t_high%256);
byte_write(0x2004,t_high/256);
byte_write(0x2005,t_low%256);
byte_write(0x2006,t_low/256);
byte_write(0x2058,a_a);
}
/******************把数据从单片机内部eeprom中读出来*****************/
voidread_eeprom()
{
fen1=byte_read(0x2000);
shi1=byte_read(0x2001);
open1=byte_read(0x2002);
t_high=byte_read(0x2004);
t_high<<=8;
t_high|=byte_read(0x2003);
t_low=byte_read(0x2006);
t_low<<=8;
t_low|=byte_read(0x2005);
a_a=byte_read(0x2058);
}
/**************开机自检eeprom初始化*****************/
voidinit_eeprom()
{
read_eeprom();//先读
if(a_a!
=43)//新的单片机初始单片机内问eeprom
{
fen1=3;
shi1=8;
open1=1;
t_high=350;
t_low=100;
a_a=34;
write_eeprom();//保存数据
}
}
/***********************18b20初始化函数*****************************/
voidinit_18b20()
{
bitq;
dq=1;//把总线拿高
delay_uint
(1);//15us
dq=0;//给复位脉冲
delay_uint(80);//750us
dq=1;//把总线拿高等待
delay_uint(10);//110us
q=dq;//读取18b20初始化信号
delay_uint(20);//200us
dq=1;//把总线拿高释放总线
}
/*************写18b20内的数据***************/
voidwrite_18b20(uchardat)
{
uchari;
for(i=0;i<8;i++)
{//写数据是低位开始
dq=0;//把总线拿低写时间隙开始
dq=dat&0x01;//向18b20总线写数据了
delay_uint(5);//60us
dq=1;//释放总线
dat>>=1;
}
}
/*************读取18b20内的数据***************/
ucharread_18b20()
{
uchari,value;
for(i=0;i<8;i++)
{
dq=0;//把总线拿低读时间隙开始
value>>=1;//读数据是低位开始
dq=1;//释放总线
if(dq==1)//开始读写数据
value|=0x01;
delay_uint(5);//60us读一个时间隙最少要保持60us的时间
}
returnvalue;//返回数据
}
/*************读取温度的值读出来的是小数***************/
uintread_temp()
{
uintvalue;
ucharlow;//在读取温度的时候如果中断的太频繁了,就应该把中断给关了,否则会影响到18b20的时序
init_18b20();//初始化18b20
write_18b20(0xcc);//跳过64位ROM
write_18b20(0x44);//启动一次温度转换命令
delay_uint(50);//500us
init_18b20();//初始化18b20
write_18b20(0xcc);//跳过64位ROM
write_18b20(0xbe);//发出读取暂存器命令
EA=0;
low=read_18b20();//读温度低字节
value=read_18b20();//读温度高字节
EA=1;
value<<=8;//把温度的高位左移8位
value|=low;//把读出的温度低位放到value的低八位中
value*=0.625;//转换到温度值小数
returnvalue;//返回读出的温度带小数
}
/******************1ms延时函数*******************/
voiddelay_1ms(uintq)
{
uinti,j;
for(i=0;ifor(j=0;j<120;j++);
}
/******************写星期函数*******************/
voidwrite_week(ucharhang,ucharadd,ucharweek)//写星期函数
{
if(hang==1)
write_com(0x80+add);
else
write_com(0x80+0x40+add);
switch(week)
{
case1:
write_data('M');//星期数为1时,显示
write_data('O');
write_data('N');
break;
case2:
write_data('T');//星期数据为2时显示
write_data('U');
write_data('E');
break;
case3:
write_data('W');//星期数据为3时显示
write_data('E');
write_data('D');
break;
case4:
write_data('T');//星期数据为4是显示
write_data('H');
write_data('U');
break;
case5:
write_data('F');//星期数据为5时显示
write_data('R');
write_data('I');
break;
case6:
write_data('S');//星期数据为6时显示
write_data('T');
write_data('A');
break;
case7:
write_data('S');//星期数据为7时显示
write_data('U');
write_data('N');
break;
}
}
/*************时钟显示***************/
voidinit_1602_ds1302()
{
write_sfm2_ds1302(1,1,shi);//显示时
write_sfm2_ds1302(1,4,fen);//显示分
write_sfm2_ds1302(1,7,miao);//显示秒
write_week(2,12,week);
//write_sfm1(1,14,week);//显示星期
write_sfm3_18B20(1,11,temperature);//显示温度
if(flag_nl==0)//显示阳历
{
write_sfm2_ds1302(2,2,nian);//显示年
write_sfm2_ds1302(2,5,yue);//显示月
write_sfm2_ds1302(2,8,ri);//显示日
}
else//显示农历
{
write_sfm2_ds1302(2,2,n_nian);//显示年
write_sfm2_ds1302(2,5,n_yue);//显示月
write_sfm2_ds1302(2,8,n_ri);//显示日
}
}
/*************定时器0初始化程序***************/
voidinit_time0()
{
EA=1;//开总中断
TMOD=0X01;//定时器0、工作方式1
ET0=1;//开定时器0中断
TR0=1;//允许定时器0定时
}
/*************闹钟报警函数***************/
voidmenu_dis()
{
staticucharmm,value;
if(flag_100ms==1)//100ms执行一次
{
flag_100ms=0;
if(open1==1)//如果闹钟打开
{
if((miao==0)&&(fen==fen1)&&(shi==shi1))
{
flag_beep_en=1;//有报警打开蜂鸣器响的标志位
}
if(flag_beep_en==1)//闹钟以被打开
{
clock_value++;
if(clock_value<=30)
beep=~beep;//蜂鸣器叫3秒
//1分钟后自动关闭闹钟
value++;
if(value>=10)
{
value=0;
mm++;
if(mm>=60)
{
mm=0;
flag_beep_en=0;
beep=1;
}
}
}
}
}
}
/********************独立按键程序*****************/
ucharkey_can;//按键值
voidkey()//独立按键程序
{
staticucharkey_new;
key_can=20;//按键值还原
P3|=0x78;//对应的按键IO口输出为1
if((P3&0x78)!
=0x78)//按键按下
{
delay_1ms
(1);//按键消抖动
if(((P3&0x78)!
=0x78)&&(key_new==1))
{//确认是按键按下
key_new=0;
switch(P3&0x78)
{
case0x70:
key_can=4;break;//得到按键值
case0x68:
key_can=3;break;//得到按键值
case0x58:
key_can=2;break;//得到按键值
case0x38:
key_can=1;break;//得到按键值
}
//write_sfm2(1,0,key_can);//显示按键值
}
}
else
key_new=1;
}
/**********************设置函数************************/
voidkey_with()
{
if(key_can==1)//设置键
{
menu_1++;
if(menu_1==4)//设置时间
{
menu_2=1;
write_string(1,0,"--W:
");
write_string(2,0,"20--");
}
if(menu_1==2)//设置闹钟
{
menu_2=1;
write_string(1,0,"setclock");
write_string(2,0,"Y00:
00");
}
if(menu_1==3)//设置温度上下限
{
menu_2=1;
write_string(1,0,"setwendu");
write_string(2,0,"H:
.L:
.");
write_zifu(2,6,0xdf);//显示度
write_zifu(2,14,0xdf);//显示度
}
if(menu_1>2)//回到正常显示
{
menu_1=0;
write_guanbiao(1,2,0);//关闭光标
init_1602_dis_csf();//初始化液晶显示
}
}
if(key_can==5)
{
menu_1=0;
write_guanbiao(1,2,0);//关闭光标
init_1602_dis_csf();//初始化液晶显示
}
if(key_can==2)//选择键
{
flag_200ms=1;
if(menu_1==1)//设置时间
{
menu_2++;
if(menu_2>7)
menu_2=1;
}
if(menu_1==2)//设置闹钟
{
menu_2++;
if(menu_2>3)
menu_2=1;
}
}
if(menu_1==1)
{
if(menu_2==1)//设置时
{
if(key_can==3)//加
{
shi+=0x01;
if((shi&0x0f)>=0x0a)
shi=(shi&0xf0)+0x10;
if(shi>=0x24)
shi=0;
}
if(key_can==4)//减
{
if(shi==0x00)
shi=0x24;
if((shi&0x0f)==0x00)
shi=(shi|0x0a)-0x10;
shi--;
}
}
if(menu_2==2)//设置分
{
if(key_can==3)//加
{
fen+=0x01;
if((fen&0x0f)>=0x0a)
fen=(fen&0xf0)+0x10;
if(fen>=0x60)
fen=0;
}
if(key_can==4)//减
{
if(fen==0x00)
fen=0x5a;
if((fen&0x0f)==0x00)
fen=(fen|0x0a)-0x10;
fen--;
}
}
if(menu_2==3)//设置秒
{
if(key_can==3)//加
{
miao+=0x01;
if((miao&0x0f)>=0x0a)
miao=(miao&0xf0)+0x10;
if(miao>=0x60)
miao=0;
}
if(key_can==4)//减
{
if(miao==0x00)
miao=0x5a;
if((miao&0x0f)==0x00)
miao=(miao|0x0a)-0x10;
miao--;
}
}
if(menu_2==4)//设置星期
{
if(key_can==3)//加
{
week+=0x01;
if((week&0x0f)>=0x0a)
week=(week&0xf0)+0x10;
if(week>=0x08)
week=1;
}
if(key_can==4)//减
{
if(week==0x01)
week=0x08;
if((week&0x0f)==0x00)
week=(week|0x0a)-0x10;
week--;
}
}
if(menu_2==5)//设置年
{
if(key_can==3)//加
{
nian+=0x01;
if((nian&0x0f)>=0x0a)
nian=(nian&0xf0)+0x10;
if(nian>=0x9a)
nian=1;
}
if(key_can==4)//减
{
if(nian==0x01)
nian=0x9a;
if((nian&0x0f)==0x00)
nian=(nian|0x0a)-0x10;
nian--;
}
}
if(me