带温度显示的万年历_数码管显示(附电路图和源代码)
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
设计报告
设计任务:
设计一个智能化万年历时钟电路,LED数码管作为电路的显示部分,按钮开关作为调时部分,通过与单片机连接数码管动态显示年、月、日、时、分、秒、星期、温度。
并能准确计算闰年闰月的显示。
设计要求:
通过与单片机连接数码管动态显示年、月、日、时、分、秒、星期等功能,并能准确计算闰年闰月的显示,三个个按钮连接P3.0、P3.1、P3.2可以精确调整每一个时间数值,通过对所设计的万年历时钟电路进行实验测试,达到了动态显示时间,随时调整时间等技术所连线路和单片机接口仿真图如图3所示:
图3 仿真按键
4)温度采集部分:
DS18B20温度传感器,测温范围-55℃~+125℃,固有测温分辨率0.5℃。
独特的单线接口方式,DS18B20在与微处理器
连接时仅需要一条口线即可实现微处理器与DS18B20的双向通讯。
DS18B20的采集数据通过DQ传入单片机,单片机读取数据后将数据输出!如图所示
:
程序如下:
ReadOneChar(void)
{
unsigned char i=0;// 定义i用于循环
unsigned char dat = 0;// 读取的8位数据
for (i=8;i>0;i--)//8次循环
{
DQ = 0;// 拉低DQ总线开始读时序
dat>>=1;// dat左移一位
DQ = 1; //释放DQ总线
if(DQ)// 如果DQ=1,执dat|=0x80;(0x80即第7位为1,如果DQ为1,即读取的数据为1,将dat的第7为置1,然后dat>>=1,循环8次结束,dat 即为读取的数据)
//DQ=0,就跳过
dat|=0x80;
Tdelay(4);// 延时以完成此次读时序,之后再读下一数据
}
return(dat); 返回读取的dat
}
//写一个字节
WriteOneChar(unsigned char dat)
{
unsigned char i=0;//
for (i=8; i>0; i--)//
{
DQ = 0;//
DQ = dat&0x01;//
Tdelay(5);//延时以完成此次读时序,之后再读下一数据
DQ = 1;//
dat>>=1;//
}
}
//读取温度
ReadTemperature(void)
{
unsigned char a=0;
unsigned char b=0;
unsigned int t=0;
float tt=0;//
Init_DS18B20();
WriteOneChar(0xCC);// 写指令,跳过ROM,
WriteOneChar(0x44);// 启动温度转换
Init_DS18B20();
WriteOneChar(0xCC);// 写指令,跳过ROM,
WriteOneChar(0xBE);// 写指令,读暂存存储器
a=ReadOneChar();//读低8位
b=ReadOneChar();//读高8位
t=b;//
t<<=8;//
t=t|a;//
tt=t*0.0625;//
t= tt*10+0.5;//
return(t); //获得0.01°C 的精度并返回
}
LED数码管的选择
LED数码管分为共阴和共阳两种,以利用STC89C51的P0口作为LED显示的数据部分,以P2口的七个口作为显示部分的位选,通过三八译码器和4-16译码器扩展为17位的位选分别接在一个四位数码管和13个数码管的位选部分。
详细电路图如图4-5所示:
程序如下:
P2=0xF0;
P0=L1;
delay(1); //yearh P2=0xF1;
P0=L2;
delay(1); //yearh
if(cursor==8)
{
P2=0x1F|a;
P0=L17;
delay(1);
}
else
{
P2=0x1F;
P0=L17;
delay(1);
}//week
if(cursor==6)
{
P2=0xF2|a;
P0=L3;
delay(1);
}
else
{
P2=0xF2;
P0=L3;
delay(1);
} //yearl
if(cursor==6) {
P2=0xF3|a;
P0=L4;delay(1);
}
else
{
P2=0xF3;
P0=L4;
delay(1);
} //yearl
if(cursor==5) {
P2=0xF4|a;
P0=L5;
delay(1);
}
else
{
P2=0xF4;
P0=L5;
delay(1);
} //month
if(cursor==5) {
P2=0xF5|a;
P0=L6;
delay(1);
}
else
{
P2=0xF5;
P0=L6;
delay(1);
} //month
if(cursor==4) {
P2=0xF6|a;
P0=L7;
delay(1);
}
else
{
P2=0xF6;
P0=L7;
delay(1);
} //day
if(cursor==4) {
P2=0xF7|a;
P0=L8;
delay(1);
}
else
{
P2=0xF7;
P0=L8;
delay(1);
} //day
P2=0xFF;
if(cursor==3) {
P2=0xF8|a;
P0=L9;
delay(1);
}
else
{
P2=0xF8;
P0=L9;
delay(1);
} //hour
if(cursor==3) {
P2=0xF9|a;
P0=L10;
delay(1);
else
{
P2=0xF9;
P0=L10;
delay(1);
} //hour
if(cursor==2) {
P2=0xFA|a;
P0=L11;
delay(1);
}
else
{
P2=0xFA;
P0=L11;
delay(1);
} //min
if(cursor==2) {
P2=0xFB|a;
P0=L12;
delay(1);
}
else
{
P2=0xFB;
P0=L12;
delay(1);
} //min
if(cursor==1) {
P2=0xFC|a;
P0=L13;
delay(1);
}
else
{
P2=0xFC;
P0=L13;
delay(1);
} //sec
if(cursor==1)
P2=0xFD|a;
P0=L14;
delay(1);
}
else
{
P2=0xFD;
P0=L14;
delay(1);
} //sec
P2=0xFE;
P0=L15;
delay(1); //temp
P2=0x0F;
P0=L16;
delay(1); //temp
P2=0xFF;
}
图5 日期显示仿真实验
整个电路仿真图如下图6所示所示:
图6 仿真电路图
实物的制作与调试
(1)原理图的绘制与PCB的制作
(2)原理图的绘制
(3)在Protel99se中先新建一个工程,把所需要的元件载入
到文档里面。
(4)按照所设计的电路画原理图
(5)通过电气检查是否有错,并修改完善。
原理图如图7所示:
显示部分
图7 原理图
系统实现:
1、方案设计、方案比较
方案一:采用实时时钟芯片
实时时钟芯片具备年、月、日、时、分、秒计时功能和多点定时功能,计时数据的更新每秒自动进行一次,不需程序干预。
计算机可通过中断或查询方式读取数据进行显示,因此计时功能的实现无需占用CPU的时间,程序简单。
此外,实时时钟芯片多数带有锂电池做后备电源,具备永不停止的计时功能;具有可编程方波输出功能,可用做实时测控系统的采样信号等;有的实时时钟芯片内部还带有非易失性RAM,可用来存放需长期保存但有时也需变更的数据。
由于功能完美,精度高,软件程序设计相对简单,且计时不占用CPU时间,因此,在工业实时测控系统中多采用这一类专用芯片来实现实时时钟功能。
方案二:软件控制
利用单片机内部的定时/计数器进行中断定时,配合软件延时实现时、分、秒的计时,该方案节省硬件成本,且能使设计者对单片机的指令系统能有更深入的了解,从而掌握单片机应用技术MCS-51汇
编语言程序设计方法,因此,本系统设计采用此种软件控制方法来实
现时, STC89C51单片机是低功耗的具有4KB在线可编程FLASH存储器的单片机。
它与通用80C51系列单片机的指令第和引脚兼容。
片内的FLASH集成在一个芯片上,形成了功能强大、使用灵活和具有较高性能价格比的微控制器。
它的功能强大,而且也较容易购买。
总结:所要实现的功能通过单片机编程就可以达到,不需要额外的时钟芯片来增加成本,并使外围电路更加简单明了。
3、实验步骤
(1)、给电路通上电源, LED显示是否通电;
(2)、电路板上分别选择模式、+ 和 - 按键,可以对时间和日期进行任意的调整,数码管分别显示日期和时间;调整模式按键按下表示对时间开始进行调整,通过选位来确定所要调整的位置,分别可以加和减。
(3)、用一个四位数码管和13个数码管,可显示时间和日期。
实验实物图如图11-12所示:
总结:经过测试,我所做的万年历相对稳定,并且能准确的计时以及调整时间,经过这次试验懂得了仿真与实物是有差别的,也学会了很多。
实验总结:
1、这次我的设计的任务是万年历时钟的设计,通过C51芯片程序控制显示万年历。
本次实验是设计一个智能化万年历时钟电路,LED数码管作为电路的显示部分,按钮作为调整时间和日期部分,可任意的对时间进行所需的调整,通过与单片机连接数码管动态显示年、月、日、时、分、秒、星期、温度等功能,并能准确计算闰年闰月的显示。
2、我采用的是12MHZ的晶振,再通过一系列的计算从而实现万年历时钟的基本功能。
在实验调试过程中,出现了很多的问题,仿真时不需要数码管驱动依然能够实现所需的功能,但实验时出现了数码管亮度达不到要求的情况。
我采用了以下方案来驱动数码管:1)74LS138和74HC154作为位选驱动;
2)在P0口接的上拉电阻,在这个过程中又涉及了上拉电阻的大小,开始用10K的电阻,因为电阻过大,使电流不能达
到要求,以至于不能增加数码管的亮度。
最后我们换用1K
的上拉电阻,成功的实现了我们所要得到的结果,数码管
的亮度达到了所需的要求。
3、在做板过程中出现的线断路问题;通过万用表的检测一一排除和焊接!
4、本次实验让自己对单片机的应用有了进一步的了解,对程序也有了更深的体会!
元件清单
附录源程序如下所示:
#define uchar unsigned char
#define uint unsigned int
#define DQ P3_7
#include<AT89X51.H>
uint sec; 初始化秒
uint min=50;//初始化分钟
uint hour=9;// 初始化时
uint day=10;// 初始化天
uint month=6;// 初始化月
uint yearl=11;// 初始化年低位
uint yearh=20;// 初始化年高位
uint week=6;// 初始化星期
uint tcnt; // 定义tcnt变量
uint cursor=0;// 定义cursor变量
uchar a=0xff;定义a变量
uchar code Seg[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};//共阴数码显示码值
void delay(uint t)
{
uint i;
while(t--)
{for (i=0;i<125;i++);}
} //延时函数子函数
void Tdelay(unsigned int i)
{
while(i--);
}
void Kdelay()
{
uchar i,j;//定义I J 变量
for(i=100;i>0;i--)
for(j=248;j>0;j--);
}//延时
Init_DS18B20(void)
{
unsigned char x=0;
DQ = 1; //DQ复位
Tdelay(8); //稍做延时
DQ = 0; //单片机将DQ拉低
Tdelay(80); //精确延时,大于480us
DQ = 1; //拉高总线
Tdelay(14);
Tdelay(20);//延时
}
//读一个字节
ReadOneChar(void)
{
unsigned char i=0;// 定义i用于循环
unsigned char dat = 0;// 读取的8位数据
for (i=8;i>0;i--)//8次循环
{
DQ = 0;// 拉低DQ总线开始读时序
dat>>=1;// dat左移一位
DQ = 1; //释放DQ总线
if(DQ)// 如果DQ=1,执dat|=0x80;(0x80即第7位为1,如果DQ为1,即读取的数据为1,将dat的第7为置1,然后dat>>=1,循环8次结束,dat 即为读取的数据)
//DQ=0,就跳过
dat|=0x80;
Tdelay(4);// 延时以完成此次读时序,之后再读下一数据
}
return(dat); 返回读取的dat
}
//写一个字节
WriteOneChar(unsigned char dat)
{
unsigned char i=0;//
for (i=8; i>0; i--)//
{
DQ = 0;//
DQ = dat&0x01;//
Tdelay(5);//延时以完成此次读时序,之后再读下一数据 DQ = 1;//
dat>>=1;//
}
}
//读取温度
ReadTemperature(void)
{
unsigned char a=0;
unsigned char b=0;
unsigned int t=0;
float tt=0;//
Init_DS18B20();
WriteOneChar(0xCC);// 写指令,跳过ROM,
WriteOneChar(0x44);// 启动温度转换
Init_DS18B20();
WriteOneChar(0xCC);// 写指令,跳过ROM,
WriteOneChar(0xBE);// 写指令,读暂存存储器
a=ReadOneChar();//读低8位
b=ReadOneChar();//读高8位
t=b;//
t<<=8;//
t=t|a;//
tt=t*0.0625;//
t= tt*10+0.5;//
return(t); //获得0.01°C 的精度并返回
}
void display(uchar L1,uchar L2,uchar L3,uchar L4,uchar L5,uchar L6,uchar L7,uchar L8,uchar L9,uchar L10,uchar L11,uchar L12,uchar L13,uchar L14,uchar L15,uchar L16,uchar L17)
/***********动态显示数码管的时间**************/
{
P2=0xF0;
P0=L1;
delay(1); //yearh
P2=0xF1;
P0=L2;
delay(1); //yearh
if(cursor==8)
{
P2=0x1F|a;
P0=L17;
delay(1);
}
else
{
P2=0x1F;
P0=L17;
delay(1);
}//week
if(cursor==6)
{
P2=0xF2|a;
P0=L3;
delay(1);
}
else
{
P2=0xF2;
P0=L3;
delay(1);
} //yearl
if(cursor==6)
{
P2=0xF3|a;
P0=L4;delay(1);
}
else
{
P2=0xF3;
P0=L4;
delay(1);
} //yearl
if(cursor==5) {
P2=0xF4|a;
P0=L5;
delay(1);
}
else
{
P2=0xF4;
P0=L5;
delay(1);
} //month
if(cursor==5) {
P2=0xF5|a;
P0=L6;
delay(1);
}
else
{
P2=0xF5;
P0=L6;
delay(1);
} //month
if(cursor==4) {
P2=0xF6|a;
P0=L7;
delay(1);
}
else
{
P2=0xF6;
P0=L7;
delay(1);
} //day
if(cursor==4) {
P2=0xF7|a;
P0=L8;
delay(1);
}
else
{
P2=0xF7;
P0=L8;
delay(1);
} //day
P2=0xFF;
if(cursor==3) {
P2=0xF8|a;
P0=L9;
delay(1);
}
else
{
P2=0xF8;
P0=L9;
delay(1);
} //hour
if(cursor==3) {
P2=0xF9|a;
P0=L10;
delay(1);
}
else
{
P2=0xF9;
P0=L10;
delay(1);
} //hour
if(cursor==2) {
P2=0xFA|a;
P0=L11;
delay(1);
}
else
{
P2=0xFA;
P0=L11;
delay(1);
} //min
if(cursor==2) {
P2=0xFB|a;
P0=L12;
delay(1);
}
else
{
P2=0xFB;
P0=L12;
delay(1);
} //min
if(cursor==1) {
P2=0xFC|a;
P0=L13;
delay(1);
}
else
{
P2=0xFC;
P0=L13;
delay(1);
} //sec
if(cursor==1) {
P2=0xFD|a;
P0=L14;
delay(1);
}
else
{
P2=0xFD;
P0=L14;
delay(1);
} //sec
P2=0xFE;
P0=L15;
delay(1); //temp
P2=0x0F;
P0=L16;
delay(1); //temp
P2=0xFF;
}
main()
{
uint i;
TMOD=0x02; //设置模式为定时器T0的模式2 (8位自动重装计数初值的计数值)
TH0=0x06; //设置计数器初值,靠TH0存储重装的计数值X0=256-250=6
TL0=0x06;
TR0=1; //启动T0
ET0=1; //开启定时器T0中断允许
EA=1; //开启中断总控制
while(1)
{
P3_0=1;
if(P3_0==0){
delay(10);
if(P3_0==0)//如果按键被按下
{
Kdelay();
if(P3_0==0)//确定按键按下
{
while(P3_0==0); // 等待按键放开
cursor++;
if(cursor>=9){cursor=0;}//如果cursor大于9则cursor=0
if(P1_0==0){cursor=0;}
} }
}
P3_1=1;
if(P3_1==0){
delay(10);
if(P3_1==0) //如果按键被按下
{
Kdelay();
if(P3_1==0) //确定按键按下
{
if(cursor==1)
{
sec++;//如果cursor=1则按键按下秒数加一
if(sec==60)
sec=0;//如果秒数等于60秒则回到0开始
}
if(cursor==2)
{
min++;//如果cursor=2则按键按下分数加一
if(min==60)
min=0; 如果分数等于60分则回到0开始
}
if(cursor==3)
{
hour++;//如果cursor=3则按键按下时数加一
if(hour==24)
hour=0; //如果时数等于24时则回到0开始
}
if(cursor==4)
{
day++;//如果cursor=4则按键按下天数加一
if(day==31)
day=0; //如果天数等于31天则回到0开始
}
if(cursor==5)
{
month++;//如果cursor=5则按键按下月数加一
if(month==13)
month=0; //如果月数等于13月则回到0开始
}
if(cursor==6)
{
yearl++;//如果cursor=6则按键按下年数低位加一
if(yearl==100)
yearl=0; //如果年数等于100则回到0开始
}
if(cursor==7)
{
yearh++;//如果cursor=7则按键按下年数高位加一
if(yearh==30)
yearh=20; //如果年数大于30则回到0开始
}
{
week++;//如果cursor=8则按键按下星期数加一
if(week==8)
week=1; //如果星期数等于8则回到0开始
}
}
while(P3_1==0);}
}
P3_2=1; //写入时先写1
if(P3_2==0){//按键按下
delay(10);//延时10个毫秒
if(P3_2==0)//确定按键按下
{
Kdelay();
if(P3_2==0)
{
if(cursor==1)
{
sec--;//如果cursor=1则按键按下秒数减一
if(sec==0)
sec=59; //如果秒数小于0则回到59开始
}
if(cursor==2)
{
min--;//如果cursor=2则按键按下分数减一
if(min==0)
min=59; //如果分数小于0则回到59开始
}
if(cursor==3)
{
hour--;//如果cursor=3则按键按下时数减一
if(hour==0)
hour=23; //如果时数小于0则回到23开始
}
if(cursor==4)
{
day--;//如果cursor=4则按键按下天数减一
if(day==0)
day=31; //如果天数小于0则回到31开始
}
if(cursor==5)
{
month--;//如果cursor=5则按键按下月数减一
month=12; //如果月数小于0则回到12开始
}
if(cursor==6)
{
yearl--;//如果cursor=6则按键按下年的低位数减一
if(yearl==0)
yearl=99; //如果年数小于0则回到99开始
}
if(cursor==7)
{
yearh--;//如果cursor=7则按键按下年的高位数减一
if(yearh==20)
yearh=30; //如果年数小于0则回到30开始
}
if(cursor==8)
{
week--;//如果cursor=8则按键按下秒星期减一
if(week==0)
week=7; //如果星期数小于0则回到7开始
}
while(P3_2==0);
}
}
}
i=ReadTemperature();
display(Seg[yearh/10],Seg[yearh%10],Seg[yearl/10],Seg[yearl%10],Seg[ month/10],Seg[month%10],Seg[day/10],Seg[day%10],Seg[hour/10],Seg[hou r%10],Seg[min/10],Seg[min%10],Seg[sec/10],Seg[sec%10],Seg[i/100],Seg [i/10%10],Seg[week%10]); // 数据显示
}
}
void t0(void)interrupt 1 using 0 //t0的中断程序
{
tcnt++;
if(tcnt==4000)//定时器的定时计数,4000次250us为1秒
{
tcnt=0;
sec++;
if(sec==60)
{
sec=0; 秒计到60时清0
min++;//分数加一
if(min==60)
{
min=0; //分数计到60时清0
hour++; //时数加一
if(hour==24)
{
hour=0;时数计到24时回到0开始
day++;week++;天数和星期加一
if(month==2&&((yearl==0&&yearh%4==0)||(yearl!=0&&yearl%4==0))&&day== 30)day=1;
else if(month==2&&day==29)day=1;
else
if((month==4||month==6||month==9||month==11)&&day==31)day=1; // 判断闰年
else if(day==32)day=1;//天计到32时清1
if(day==1)
{
month++;//月数加一
if(month==13)
{
month=1;// 月数计到1时清1
yearl++;//年的低位加一
if(yearl==100)
{
yearl=0;//年低位数计到100时清0
yearh++;//高位加一
if(yearh==100)//如果高位年数计到100 {
yearh=20;//高位年数回到20
}
}
}
}
}
}
}
}
}。