考虑到DS1820测量温度的整数部分以0.25℃、0.75℃为进位界限的关系,实际温度Ts可用下式计算:
表1.部分温度值对应的二进制温度数据。
温度/℃
二进制表示
十六进制表示
+125
0000011111010000
07D0H
+85
0000010101010000
0550H
+25.0625
0000000110010000
0191H
+10.125
0000000010100001
00A2H
+0.5
0000000000000010
0008H
0
0000000000001000
0000H
-0.5
1111111111110000
FFF8H
-10.125
1111111101011110
FF5EH
-25.0625
1111111001101111
FE6FH
-55
1111110010010000
FC90H
六.系统整体硬件电路
根据设计要求与设计思路,硬件电路设计框图如图6.1所示,在仿真软件Proteus上完成。
其中LED数码管以动态扫描法实现温度显示,由四个PNP型晶体管Q2,Q3,Q4,Q5和八个电阻组成,基极与单片机的P1.0,P1.1,P1.2连接。
DS18B20的数据I/O端与单片机P3.6引脚连接。
外部晶振为12MHz。
蜂鸣器通过Q1放大后与引脚P1.7相连。
图中有三个独立式按键可以分别调整温度计的上下限报警设置,图中蜂鸣器可以在被测温度不在上下限范围内时,发出报警鸣叫声音,同时LED数码管将没有被测温度值显示,这时可以调整报警上下限,从而测出被测的温度值。
图中的按健复位电路是上电复位加手动复位,使用比较方便,在程序跑飞时,可以手动复位,这样就不用在重起单片机电源,就可以实现复位。
图6.1系统总体硬件电路
七.系统程序设计
数字式温度计的应用程序主要包括主程序,温度检测程序,温度转换程序,LED显示程序等。
系统的主程序主要用来初始化一些系统参数,对DS18B20的配置数据进行一系列的设定。
温度检测程序是对DS18B20的状态不断地查询,读出RAM中的9字节,在读出时需进行CRC校验,校验有错时不进行温度数据的改写,读取当前的温度值后,进行温度转化程序,对温度符号处理和温度值的BCD码处理,进行温度值正负的判定,将其段码送至显示缓冲区,以备定时扫描服务程序处理。
LED显示程序主要对显示缓冲器中的显示数据进行刷新操作,当最高显示位为0时,将符号显示位移入下一位。
总程序程序代码见附录一
开始
显示缓冲区初始化
复位DS18B20
发跳过ROM命令
发温度转换命令
延时
复位DS18B20
发跳过ROM命令
发读存储器命令
读温度数据
温度符号判定
将温度转换为BCD码
更新显示缓冲区
八.测量及其结果分析
1.Proteus仿真结果
软件方面,在Proteus编译下进行,源程序编译及仿真调试。
在软件中选定传感器后可对其进行环境温度设置,如图8.1.1,将环境温度设为34.9。
图8.1.1
然后点击软件执行键,按操作步骤实施后,观察LED数码管示数,此时示数如图8.1.2。
图8.1.2
可见本次软件测试结果良好。
2.硬件测试结果
在硬件测试方面,检查电路板及焊接的质量情况,在检查无误后通电检查LED显示器。
其中DS18B20实物图为8.2.1
在室温下,LED显示器示数如图8.2.2,为26.4摄氏度
图8.2.2
用手盖住温度传感器后,LED显示器示数如图8.2.3,为29.7摄氏度。
比较可知,硬件调试结果也达到了要求。
九.设计心得体会
本次课设对我来说是一次难得的经历,首先是第一次接触了仿真软件Proteus,在使用时经历了很多次失败,因为这款软件与以前使用的各种软件有很多不同,使用时不停出错,接线时由于元件放置不合理而接的杂乱无章;输入源程序时还较为顺利,显示结果比较满意。
其次是程序设计,我们在参考别人成功先例的基础上根据自己设计的需要编制程序,其中历经不少曲折,最后我的收获是,编程一定要细心,针对每一个细节,稍有疏忽,程序就不能正常工作。
最后是单片机实践操作,由于我自己已买了一块开发板,所以硬件调试比较顺利,效果也不错,就是DS18B20温度传感器灵敏度不太高,示数变化不大。
另外,我前期花了一些时间专门学习这块芯片,了解了DS18B20的工作原理的时序图。
在这次的实践与学习中,尽管期间困难重重,但我还是从中学习了不少新的知识与技能和解决困难的方法,也终于体验到了经历困难到最终获得成功的那种无以言表的喜悦之情,总之,本次课设是我收获最多的一次,也希望自己在以后的各项研究活动中能坚持这种精神。
十.参考文献
[1]单片机原理与接口技术<第二版)牛昱光李晓林电子工业出版社.2018.7
[2]单片机系统设计与应用实例.韩志军机械工业出版社.2009.10
[3]《DS18B20数据手册》
附录一源程序
#include
#include"DS18B20.h"
#defineuintunsignedint
#defineucharunsignedchar//宏定义
#defineSETP3_1//定义调整键
#defineDECP3_2//定义减少键
#defineADDP3_3//定义增加键
#defineBEEPP3_7//定义蜂鸣器
bitshanshuo_st。
//闪烁间隔标志
bitbeep_st。
//蜂鸣器间隔标志
sbitDIAN=P2^7。
//小数点
ucharx=0。
//计数器
signedcharm。
//温度值全局变量
ucharn。
//温度值全局变量
ucharset_st=0。
//状态标志
signedcharshangxian=38。
//上限报警温度,默认值为38
signedcharxiaxian=15。
//下限报警温度,默认值为5
ucharcodeLEDData[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90}。
/*****延时子程序*****/
voidDelay(uintnum>
{
while(--num>。
}
/*****初始化定时器0*****/
voidInitTimer(void>
{
TMOD=0x1。
TH0=0x4c。
TL0=0x00。
//50ms<晶振12M)
}
/*****定时器0中断服务程序*****/
voidtimer0(void>interrupt1
{
TH0=0x4c。
TL0=0x00。
x++。
}
/*****外部中断0服务程序*****/
voidint0(void>interrupt0
{
EX0=0。
//关外部中断0
if(DEC==0&&set_st==1>
{
shangxian--。
if(shangxianshangxian=xiaxian。
}
elseif(DEC==0&&set_st==2>
{
xiaxian--。
if(xiaxian<0>xiaxian=0。
}
}
/*****外部中断1服务程序*****/
voidint1(void>interrupt2
{
EX1=0。
//关外部中断1
if(ADD==0&&set_st==1>
{
shangxian++。
if(shangxian>99>shangxian=99。
}
elseif(ADD==0&&set_st==2>
{
xiaxian++。
if(xiaxian>shangxian>xiaxian=shangxian。
}
}
/*****读取温度*****/
voidcheck_wendu(void>
{
uinta,b,c。
c=ReadTemperature(>-5。
//获取温度值并减去DS18B20的温漂误差
a=c/100。
//计算得到十位数字
b=c/10-a*10。
//计算得到个位数字
m=c/10。
//计算得到整数位
n=c-a*100-b*10。
//计算得到小数位
if(m<0>{m=0。
n=0。
}//设置温度显示上限
if(m>99>{m=99。
n=9。
}//设置温度显示上限
}
/*****显示开机初始化等待画面*****/
Disp_init(>
{
P2=0xbf。
P1=0xfe。
Delay(200>。
P2=0xbf。
P1=0xfd。
Delay(200>。
P2=0xbf。
P1=0xfb。
Delay(200>。
P2=0xbf。
P1=0xf7。
//第四
Delay(200>。
P1=0xff。
//关闭显示
}
/*****显示温度子程序*****/
Disp_Temperature(>//显示温度
{
P2=0xc6。
//显示C
P1=0xf7。
//
Delay(300>。
P2=LEDData[n]。
//显示个位
P1=0xfb。
//
Delay(300>。
P2=LEDData[m%10]。
//显示小数点
DIAN=0。
P1=0xfd。
Delay(300>。
P2=LEDData[m/10]。
//显示百位
P1=0xfe。
Delay(300>。
P1=0xff。
//关闭显示
}
/*****显示报警温度子程序*****/
Disp_alarm(ucharbaojing>
{
P2=0xc6。
//显示C
P1=0xf7。
Delay(200>。
P2=LEDData[baojing%10]。
//显示十位
P1=0xfb。
Delay(200>。
P2=LEDData[baojing/10]。
//显示百位
P1=0xfd。
Delay(200>。
if(set_st==1>P2=0x89。
elseif(set_st==2>P2=0xc7。
//上限H、下限L标示
P1=0xfe。
Delay(200>。
P1=0xff。
}
/*****报警子程序*****/
voidAlarm(>
{
if(x>=10>{beep_st=~beep_st。
x=0。
}
if((m>=shangxian&&beep_st==1>||(m>BEEP=0。
elseBEEP=1。
}
/*****主函数*****/
voidmain(void>
{
uintz。
InitTimer(>。
//初始化定时器
EA=1。
//全局中断开关
TR0=1。
ET0=1。
//开启定时器0
IT0=1。
IT1=1。
check_wendu(>。
check_wendu(>。
for(z=0。
z<300。
z++>
{
Disp_init(>。
}
while(1>
{
if(SET==0>
{
Delay(2000>。
do{}while(SET==0>。
set_st++。
x=0。
shanshuo_st=1。
if(set_st>2>set_st=0。
}
if(set_st==0>
{
EX0=0。
//关闭外部中断0
EX1=0。
//关闭外部中断1
check_wendu(>。
Disp_Temperature(>。
Alarm(>。
//报警检测
}
elseif(set_st==1>
{
BEEP=1。
//关闭蜂鸣器
EX0=1。
//开启外部中断0
EX1=1。
//开启外部中断1
if(x>=10>{shanshuo_st=~shanshuo_st。
x=0。
}
if(shanshuo_st>{Disp_alarm(shangxian>。
}
}
elseif(set_st==2>
{
BEEP=1。
//关闭蜂鸣器
EX0=1。
//开启外部中断0
EX1=1。
//开启外部中断1
if(x>=10>{shanshuo_st=~shanshuo_st。
x=0。
}
if(shanshuo_st>{Disp_alarm(xiaxian>。
}
}
}
}
/*****END*****/
DS18B20.h:
#include
#defineDQP3_6//定义DS18B20总线I/O
/*****延时子程序*****/
voidDelay_DS18B20(intnum>
{
while(num-->。
}
/*****初始化DS18B20*****/
voidInit_DS18B20(void>
{
unsignedcharx=0。
DQ=1。
//DQ复位
Delay_DS18B20(8>。
//稍做延时
DQ=0。
//单片机将DQ拉低
Delay_DS18B20(80>。
//精确延时,大于480us
DQ=1。
//拉高总线
Delay_DS18B20(14>。
x=DQ。
//稍做延时后,如果x=0则初始化成功,x=1则初始化失败
Delay_DS18B20(20>。
}
/*****读一个字节*****/
unsignedcharReadOneChar(void>
{
unsignedchari=0。
unsignedchardat=0。
for(i=8。
i>0。
i-->
{
DQ=0。
//给脉冲信号
dat>>=1。
DQ=1。
//给脉冲信号
if(DQ>
dat|=0x80。
Delay_DS18B20(4>。
}
return(dat>。
}
/*****写一个字节*****/
voidWriteOneChar(unsignedchardat>
{
unsignedchari=0。
for(i=8。
i>0。
i-->
{
DQ=0。
DQ=dat&0x01。
Delay_DS18B20(5>。
DQ=1。
dat>>=1。
}
}
/*****读取温度*****/
intReadTemperature(void>
{
unsignedchara=0。
unsignedcharb=0。
intt=0。
floattt=0。
Init_DS18B20(>。
WriteOneChar(0xCC>。
//跳过读序号列号的操作
WriteOneChar(0x44>。
//启动温度转换
Init_DS18B20(>。
WriteOneChar(0xCC>。
//跳过读序号列号的操作
WriteOneChar(0xBE>。
//读取温度寄存器
a=ReadOneChar(>。
//读低8位
b=ReadOneChar(>。
//读高8位
t=b。
t<<=8。
t=t|a。
tt=t*0.0625。
t=tt*10+0.5。
//放大1