带温度显示的万年历_数码管显示(附电路图和源代码)

带温度显示的万年历_数码管显示(附电路图和源代码)


2024年4月14日发(作者:)

设计报告

设计任务:

设计一个智能化万年历时钟电路,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);// 延时以完成此次读时序,之后再读下一数据

2

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所示:

3

程序如下:

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)

4

{

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;

5

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);

6

}

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)

7

{

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所示所示:

8

图6 仿真电路图

实物的制作与调试

(1) 原理图的绘制与PCB的制作

(2) 原理图的绘制

(3) 在Protel99se中先新建一个工程,把所需要的元件载入

到文档里面。

(4) 按照所设计的电路画原理图

(5) 通过电气检查是否有错,并修改完善。

原理图如图7所示:

显示部分

9

图7 原理图

系统实现:

1、方案设计、方案比较

方案一:采用实时时钟芯片

实时时钟芯片具备年、月、日、时、分、秒计时功能和多点定时

功能,计时数据的更新每秒自动进行一次,不需程序干预。计算机可

通过中断或查询方式读取数据进行显示,因此计时功能的实现无需占

用CPU的时间,程序简单。此外,实时时钟芯片多数带有锂电池做后

备电源,具备永不停止的计时功能;具有可编程方波输出功能,可用

做实时测控系统的采样信号等;有的实时时钟芯片内部还带有非易失

性RAM,可用来存放需长期保存但有时也需变更的数据。由于功能完

美,精度高,软件程序设计相对简单,且计时不占用CPU时间,因此,

在工业实时测控系统中多采用这一类专用芯片来实现实时时钟功能。

方案二:软件控制

利用单片机内部的定时/计数器进行中断定时,配合软件延时实

现时、分、秒的计时,该方案节省硬件成本,且能使设计者对单片机

的指令系统能有更深入的了解,从而掌握单片机应用技术MCS-51汇

编语言程序设计方法,因此,本系统设计采用此种软件控制方法来实

10

现时, STC89C51单片机是低功耗的具有4KB在线可编程FLASH存储

器的单片机。它与通用80C51系列单片机的指令第和引脚兼容。片内

的FLASH集成在一个芯片上,形成了功能强大、使用灵活和具有较高

性能价格比的微控制器。它的功能强大,而且也较容易购买。

总结:所要实现的功能通过单片机编程就可以达到,不需要额外

的时钟芯片来增加成本,并使外围电路更加简单明了。

3、实验步骤

(1)、给电路通上电源, LED显示是否通电;

(2)、电路板上分别选择模式、+ 和 - 按键,可以对时间和日

期进行任意的调整,数码管分别显示日期和时间;调整模式按键按下

表示对时间开始进行调整,通过选位来确定所要调整的位置,分别可

以加和减。

(3)、用一个四位数码管和13个数码管,可显示时间和日期。

实验实物图如图11-12所示:

11

总结:经过测试,我所做的万年历相对稳定,并且能准确的计时

以及调整时间,经过这次试验懂得了仿真与实物是有差别的,也学会

了很多。

实验总结:

1、这次我的设计的任务是万年历时钟的设计,通过C51芯片程序控

制显示万年历。本次实验是设计一个智能化万年历时钟电路,LED数

码管作为电路的显示部分,按钮作为调整时间和日期部分,可任意的

对时间进行所需的调整,通过与单片机连接数码管动态显示年、月、

日、时、分、秒、星期、温度等功能,并能准确计算闰年闰月的显示。

2、我采用的是12MHZ的晶振,再通过一系列的计算从而实现万年历

时钟的基本功能。在实验调试过程中,出现了很多的问题,仿真时不

需要数码管驱动依然能够实现所需的功能,但实验时出现了数码管亮

度达不到要求的情况。我采用了以下方案来驱动数码管:

1) 74LS138和74HC154作为位选驱动;

2) 在P0口接的上拉电阻,在这个过程中又涉及了上拉电阻的

大小,开始用10K的电阻,因为电阻过大,使电流不能达

到要求,以至于不能增加数码管的亮度。最后我们换用1K

的上拉电阻,成功的实现了我们所要得到的结果,数码管

12

的亮度达到了所需的要求。

3、在做板过程中出现的线断路问题;通过万用表的检测一一排除和

焊接!

4、本次实验让自己对单片机的应用有了进一步的了解,对程序也有了

更深的体会!

元件清单

元件名称 数量

数码管 17 个

74HC138 1 个

74HC154 1 个

STC89C5 1 个

排阻 1 个

按钮 3 个

电阻 4 个

12M晶振 1 个

DS18B20 1 个

30P电容 2 个

附录 源程序如下所示:

#define uchar unsigned char

#define uint unsigned int

#define DQ P3_7

#include

uint sec; 初始化秒

uint min=50;//初始化分钟

uint hour=9;// 初始化时

uint day=10;// 初始化天

uint month=6;// 初始化月

13

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次循环

{

14

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;//

15

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)

{

16

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);

17

} //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);

}

18

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;

19

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)

20

{

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开始

}

21

if(cursor==8)

{

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则按键按下月数减一

22

if(month==0)

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

23

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

}

}

}

}

}

}

}

}

}

24


发布者:admin,转转请注明出处:http://www.yc00.com/news/1713092904a2181542.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信