资源描述
基于C51的DS18B20多点测温系统
2013-07-22
目录
摘 要 3
第一章 绪论 4
1.1 开发背景及意义 4
第二章 系统硬件设计 5
2.1 单片机 5
2.2 DS18B20温度测量模块 5
2.3 液晶显示模块 8
2.4串口通讯模块 9
第三章 系统软件设计 10
3. 1系统初始化 10
3.2 温度测量程序 11
第四章 系统仿真调试 12
4.1 系统仿真调试 12
附录 14
摘 要
本文介绍了基于温度传感器DS18b20与AT89C52单片机组成的多点温度分布式测温系统。设计了其系统构成和软件方案。该系统面向实际需求,设定DS18b20温度范围为-55℃~+125℃,采用LCD1602液晶显示屏,显示两路温度传感器的测量温度值。同时通过串口通讯与PC机进行通讯。传输采集到的温度值。
实际应用表明。该系统结构简单,抗干扰能力强,适合于恶劣环境下现场温度的测量,可应用于仓库测温、楼宇空调控制和生产过程监控等领域。
关键词:DS18b20,分布式,1602 串口通
第一章 绪论
1.1 开发背景及意义
温度的测量和控制在储粮仓库、智能楼宇空调控制及其他的工农业生产和科学研究中应用广泛。传统的温度检测是使用诸如热电偶、热电阻、半导体pn结之类的模拟传感器,经信号取样电路、放大电路和模数转换电路处理,获取表示温度值的数字信号,再交由微处理器。因为检测环境复杂,测量点多,信号传输距离远及各种干扰的影响,使得传统测量系统的稳定性和可靠性下降。
近年来随着单片机的发展和传感器技术的革新,温度检测领域也完成了从模拟信号到数字信号的转变。DS18b20温度传感器的广泛应用更是推动了这一领域的发展。另外液晶显示模块具有体积小、功耗低、显示内容丰富、超薄轻巧等优点在各类仪表和显示系统中得到越来越多的应用,现在也是单片机应用设计中最常用的信息显示模块。综合以上产品的发展特点,希望温度检测系统在未来的发展中有更广阔的应用空间并且具有更好的现场测量优越性。
第二章 系统硬件设计
本系统通过DS18B20温度传感器采集温度值,经由单片机处理由液晶显示模块显示当前温度值,并经过串口通信将温度传送到PC上
2.1 单片机
本系统采用AT89C52单片机作为微处理器。AT89C52单片机是ATMEL公司89系列单片机的一种8位Flash单片机。它最大的特点是片内含有8k可重复编程的Flash存储器,可进行1000次的擦写操作。另外AT89c52单片机采用ATMEL高密度非易失存储器制造技术制造,与工业标准的MCS-51指令集和输出管脚相兼容,并且其兼具省电耐用、性能稳定的特点,因此成为单片机市场的主流产品。本系统采用晶振根据需要确定系统工作频率为11.0592Mhz。
图2.1单片机结构图
2.2 DS18B20温度测量模块
DS18b20是美国DALLAS公司推出的单总线数字化测温集成电路,它具有独特的单线接口方式,将非电模拟量温度值转换为数字信号串行输出仅需占用1位I/O端口,能够直接读取被测现场的温度值。它体积小,电压适用范围宽(3v~5v),且可通过编程实现9~12位的温度读数,即具有可调的温度分辨率,因此实用性和可靠性较高,应用广泛。以下是DS18b20的内部结构图
图2.2.1 DS18b20的内部结构图
DS18B20有4个主要的数据部件:
① 64位激光ROM。64位激光ROM从高位到低位依次为8位CRC、48位序列号和8位家族代码(28H)组成。
② 温度灵敏元件。
③ 非易失性温度报警触发器TH和TL。可通过软件写入用户报警上下限值。
④ 配置寄存器。配置寄存器为高速暂存存储器中的第五个字节。DS18B20在0工作时按此寄存器中的分辨率将温度转换成相应精度的数值。
DS18B20的测温范围为-55℃~+125℃,在-10℃~+85℃范围内,精度为±0.5℃。在电压低于3.4v时精度误差较大。
根据其时序特点以下是DS18B20与AT89C52单片机构成的温度监测系统如下
图2.2.2温度监测系统
DS18b20的典型应用
在本系统中两个温度传感器与单片机连接方式如下:
图2.2.3 传感器与单片机连接图
本系统为多点温度测试。DS18B20采用外部供电方式,理论上可以在一根数据总线上挂256个DS18B20,但实际应用中发现,如果挂接20个以上的DS18B20就会产生功耗问题。另外单总线长度也不宜超过0.5M,否则会影响到数据的传输。在本电路板的设计中考虑到初步实践的准确性,暂使用2个DS18B20分别连接单片机的p2.6口。
对DS18B20的设计,需要注意以下问题
(1)对硬件结构简单的单线数字温度传感器DS18B20 进行操作,需要用较为复杂的程序完成。编制程序时必须严格按芯片数据手册提供的有关操作顺序进行,读、写时间片程序要严格按要求编写。尤其在使用DS18B20 的高测温分辨力时,对时序及电气特性参数要求更高。
(2)实际应用时,要注意单线的驱动能力,不能挂接过多的DS18B20,同时还应注意最远接线距离。另外还应根据实际情况选择其接线拓扑结构。
2.3 液晶显示模块
本系统使用的是1602液晶显示模块。1602液晶显示器以其微功耗、体积小、显示内容丰富、超薄轻巧、位数多、程序简单的诸多优点,在各类仪表和低功耗系统中得到广泛的应用。根据显示内容可以分为字符型液晶,图形液晶。根据显示容量又可以分为单行16字,2行16字,两行20字等等。
在本系统中使用的是字符型两行16字液晶显示器。在与单片机连接时使用接口电路(排针)相连,为并行通信。以下是1602液晶显示器外型图和液晶显示的典型应用。
图2.3.1 液晶显示器外形图
1602液晶显示采用标准的16脚接口,其中:(模块背面有标注)
图2.3.2 串口通讯
第1脚:VSS为地电源
第2脚:VDD接5V正电源
第3脚:V0为液晶显示器对比度调整端,接正电源时对比度最弱,接地电源时对比度最高,对比度过高时会产生“鬼影”,使用时可以通过一个10K的电位器调整对比度
第4脚:RS为寄存器选择,高电平时选择数据寄存器、低电平时选择指令寄存器。
第5脚:RW为读写信号线,高电平时进行读操作,低电平时进行写操作。当RS和RW共同为低电平时可以写入指令或者显示地址;当RS为高电平、RW为低电平时可以写入数据。
第6脚:E端为使能端,当E端由高电平跳变成低电平时,液晶模块执行命令。
第7~14脚:D0~D7为8位双向数据线。
第15~16脚:空脚
1602液晶模块内部的字符发生存储器(CGROM)已经存储了不同的点阵字符图形,这些字符有,阿拉伯数字、英文字母的大小写、常用的符号、和日文假名等,每一个字符都有一个固定的代码,其中数字与字母同ASCII码兼容。
2.4串口通讯模块
UART是一种通用串行数据总线,用于异步通信。该总线双向通信,可以实现全双工传输和接收。实现单片机和PC机的通讯工作,接一个MAX232 实现电平转化。电路图如下:
第三章 系统软件设计
图3 系统流程图
整个系统的功能是由硬件电路配合软件来实现的,当硬件基本定型后,软件的功能也就基本定下来了。本系统主程序主要包括三个子程序,分别为液晶显示子程序,温度测量子程序,串口通讯子程序。主体软件架构如左图:
3. 1系统初始化
系统初始化主要包括UART初始化,液晶显示初始化,温度传感器初始化。
UART初始化包括定义定时器/计数器和串行口的工作方式,定义T1为自动重装8位计数器。液晶显示初始化主要是确定液晶显示器的工作方式、显示开关、光标开关等。
温度传感器初始化包括一个由总线控制器发出的复位脉冲和跟有其后由传感器发出的存在脉冲。存在脉冲是让总线控制器知道DS18b20在总线上且已准备好操作。一个复位脉冲跟着一个存在脉冲表明DS18b20已经准备好发送和接收数据。以下是初始化序列图。
图3.1.1 初始化序列图
3.2 温度测量程序
温度测量程序主要是DS18b20与单片机之间的ROM操作命令和DS18b20的数据读写操作命令。
当单片机对DS18B20进行初始化,检测到一个存在脉冲后,发出匹配ROM命令,然后发送ROM码。
图3.2.1 DS18b20基本工作流程
第四章 系统仿真调试
4.1 系统仿真调试
在keil开发环境下不能进行有效的仿真调试,所以在系统中采用protues单片机仿真工具进行仿真调试。下图为protues仿真读取温度后在LCD1602液晶屏上的显示结果。
图4.1..1 protues仿真图
上位机用串口调试软件来仿真,安装了虚拟串口驱动软件和PROTEUS进行调试仿真。虚拟串口驱动软件用了VSPD 软件。VSPD软件在Window操作系统上增加了一对在逻辑上交叉相互的虚拟串口,使串口调试助手能够和PROTEUS中的单片机串口相连。VSPD软件界面如下:
图4.1.2VSPD软件界面
串口仿真结果如下:
在串口调试助手上显示两个温度传感器采集到的温度
图4.1.2温度传感器采集
附录
温度采集体统原理图
PCB图
源代码
1602函数部分:
#define Port P1
sbit RS = P2^0; //定义端口
sbit RW = P2^1;
sbit E = P2^2;
/****************************************************************
微秒延时函数
****************************************************************/
void delay_us(unsigned int n) //延时 如果需要高精度延时
{
if (n == 0)
{
return ;
}
while (--n);
}
/****************************************************************/
/* 毫秒函数声明 */
/****************************************************************/
void delay_ms(unsigned char i)
{
unsigned int b;
while(i--)
for (b = 1; b < 1000 ; b++) ;
}
/****************************************************************/
/* 写入命令函数 */
/***************************************************************/
void LCD_write_com(unsigned char com)
{
RS = 0;
RW = 0;
E = 1;
Port = com;
delay_us(10);
E = 0;
}
/****************************************************************/
/* 写入数据函数 */
/****************************************************************/
void LCD_write_Data(unsigned char Data)
{
RS = 1 ;
RW = 0 ;
E = 1 ;
Port = Data;
delay_us(10);
E = 0;
}
/****************************************************************/
/* 写入字符串函数 */
/****************************************************************/
void LCD_write_str(unsigned char x,unsigned char y,unsigned char *s)
{
if (y == 0)
{
LCD_write_com(0x80 + x);
}
else
{
LCD_write_com(0xc0 + x);
}
while (*s)
{
LCD_write_Data( *s);
s++;
}
}
/****************************************************************/
/* 初始化函数 */
/****************************************************************/
void LCD_init(void)
{
delay_ms(40);
LCD_write_com(0x38); /*显示模式设置*/
delay_ms(5);
LCD_write_com(0x38);
delay_ms(5);
LCD_write_com(0x38);
delay_ms(5);
LCD_write_com(0x38);
LCD_write_com(0x08); /*显示关闭*/
LCD_write_com(0x01); /*显示清屏*/
LCD_write_com(0x06); /*显示光标移动设置*/
delay_ms(5);
LCD_write_com(0x0C); /*显示开及光标设置*/
}
/***********************************************************
函数名: Display_F
函数说明:打印整数型数据,没有地址
传入参数:用于Display_float使用
传出参数:无
返回值: 无
**********************************************************/
void Display_F(unsigned int num)
{
unsigned char sever_num[6],i = 0;
if(num == 0)
LCD_write_Data(0x30);
else
{
while(num != 0)
{
sever_num[i++] = num % 10 + 0x30 ;
num /= 10 ;
}
while(i--)
{
LCD_write_Data(sever_num[i]);
delay_us(500);
}
}
}
/***********************************************************
函数名: Display_float
函数说明:打印浮点型数据,
传入参数:打印地址x,y,数据num,小数点后面打印length位
传出参数:无
返回值: 无
**********************************************************/
void Display_float(unsigned char x,unsigned char y,float numf,unsigned char length)
{
unsigned long Int_num;
unsigned int temp = 1;
unsigned char i = 0;
for (i = 0 ; i < length ; i++)
{
numf *= 10 ;
temp *= 10 ;
}
if (y == 0)
LCD_write_com(0x80 + x);
else
LCD_write_com(0xc0 + x);
Int_num = (long)numf;
Display_F(Int_num / temp);
LCD_write_Data('.');
Display_F(Int_num % temp);
}
DS18B20函数部分:
bit flag = 0;
sbit dat=P2^6;
uchar xl[2][8] = {
{0x28,0x30,0xc5,0xb8,0x00,0x00,0x00,0x8e},
{0x28,0x31,0xc5,0xb8,0x00,0x00,0x00,0xb9}
}; //两路DS18B20 ROM码
void dsdelay(uchar z) //误差 0us
{
unsigned char a,b;
for(z;z>0;z--)
for(b=1;b>0;b--)
for(a=2;a>0;a--);
}
void delay(unsigned int z)//延时函数
{
uchar x,y;
for(x=z;x>0;x--)
for(y=101;y>0;y--);
}
///////////////////////////////////////////////DS18B20函数部分////////////
void dsinit()//DS18B20初始化
{
dat=1;
dsdelay(4);
dat=0; //给一个脉冲信号
dsdelay(50);//低脉冲信号要保持480us——960us
dat=1;//拉高
dsdelay(9);//略微延时
delay(1);
}
uchar read()//DS18B20 读一个字节
{
uchar i,k;
for (i=8;i>0;i--)
{
dat = 0; // 给脉冲信号
k>>=1;//将读到的一位数向后移一位
dat = 1; // 给脉冲信号
if(dat) k|=0x80;//如果 读到的是1,则,k和0x80进行或运算,首位变成1
dsdelay(4);//每位读取中间间隔大于1us
}
return(k);
}
void write(uchar date)//DS18B20 写一个字节
{
uchar i,k;
k=date;
for(i=0;i<8;i++)
{
dat = 0;
dat = k&0x01;
dsdelay(7);
dat = 1;
k>>=1;
dsdelay(1);
}
}
float read_tempe(uchar num)//从DS18B20存储器中读书温度
{
int t;
float tt;
uchar a,b,i;
dsinit();//每次对DS18B20输入指令都要先进行初始化操作
write(0x55);//写序号列号
for (i = 0 ; i < 8 ; i++)
{
write(xl[num][i]) ;
}
write(0x44); // 启动温度转换
dsinit();
write(0x55);//写序号列号
for (i = 0 ; i < 8 ; i++)
{
write(xl[num][i]) ;
}
write(0xBE); //读取温度寄存器等(共可读9个寄存器) 前两个就是温度
a=read();//读出温度的低八位
b=read();//读出温度的高八位
t=b;
t<<=8;//t是int,16位,讲高八位移到前面
t=t|a;//将温度的高位与低位合并
if ((b & 0x80 )== 0)//判断正负温度
{
tt=t*0.0625;//将带有小数点位的十六进制数化为十进制
flag = 0;
}
else
{
tt=(~t + 1 )* 0.0625;
flag = 1;
}
return(tt);
}
UART函数部分:
void InitUART(void)//UART 初始化
{
TMOD = 0X20; //11.0592M 9600
SCON = 0X50;
TH1 = 0xfd;
TL1 = 0xfd;
PCON = 0X00;
EA = 1;
ES = 1;
TR1 = 1;
}
void Send(unsigned char C)//UART 发送
{
SBUF = C;
while(TI == 0);
TI = 0;
}
主函数部分:
uchar lable[]="TEMPE: 'C";//初始显示
void Send_Tempe( float tempe,unsigned char num)//串口发送采集到的温度
{
unsigned long t ;
unsigned char i ;
unsigned char tt[]="NUM 0 TEMPE 12.50'C\n";
tt[4] = num +0x30;
tempe = tempe * 100 ;
t = (unsigned int) tempe;
tt[17] = t%10+0x30;
t = t/10 ;
tt[16] = t%10+0x30;
t = t/10 ;
tt[14] =t%10+0x30;
t = t/10 ;
tt[13] =t%10 +0x30;
if(flag == 1)
tt[12] = '-';
for(i = 0 ; i < 22 ; i++)
Send(tt[i]);
}
void main()
{
float tempe;
unsigned char i;
InitUART() ;
LCD_init() ;
LCD_write_str(0,0, lable);
LCD_write_str(0,1, lable);
while(1)
{
for (i = 0; i < 2;i++ )
{
tempe = read_tempe(i);
if(flag == 1)
LCD_write_str(6,i, "-");
else
LCD_write_str(6,i, " ");
Display_float(7,i,tempe,2);
Send_Tempe(tempe,i) ;
delay(10000);
}
}
(注:专业文档是经验性极强的领域,无法思考和涵盖全面,素材和资料部分来自网络,供参考。可复制、编制,期待你的好评与关注)
展开阅读全文