AT89C51单片机的多点温度测量

更新时间:2023-05-21 21:40:01 阅读量: 实用文档 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

单片机应用系统设计

课 题:AT89C51单片机的多点温度测量

姓 名:

班 级: 学 号:

指导老师: 日 期:

一、绪论

在现代工业控制中和智能化仪表中,对于温度的控制,恒温等有较高的要求,如对食品的管理,冰箱的恒温控制,而且现在越来越多的地方用到多点温度测量,比如冰箱的保鲜层和冷冻层是不同的温度这就需要多点的测量和显示可以让用户直观的看到温度值,并根据需要调节冰箱的温。它还在其他领域有着广泛的应用,如:消防电气的非破坏性温度检测,电力、电讯设备之过热故障预知检测,空调系统的温度检测。。。。。。温度检测系统应用十分广阔。

本设计采用DALLAS最新单线数字温度传感器DS18B20 简介新的"一线器件"体积更小、适用电压更宽、更经济DALLAS 半导体公司的数字化温度传感器DS18B20是世界上第一片支持"一线总线",测量温度范围为-55°C~+125°C,在-10~+85°C范围内,精度为±0.5°C

二、设计过程及工艺要求

1、基本功能

(1)检测两点温度

(2)两秒间隔循环显示温度 2、主要技术参数

测温范围:-30℃到+99℃

测量精度: 0.0625℃ 显示精度: 0.1℃

显示方法:LCD循环显示 3、系统设计

系统使用AT89C51单片机对两个DS18B20进行数据采集,并通过1602LCD液晶显示器显示所采集的温度。

DS18B20以单总线协议工作,51单片机首先分别发送复位脉冲,使信号上所有的DS18B20芯片都被复位,程序先跳过ROM,启动DS18B20进行温度变换,再读取存储器的第一位和第二位读取温度,通过I/O口传到1602LCD显示。

1 2 3

图(1)DS18B20引脚图 引脚定义如图(1): (1) GND为电源地;

(2) DQ为数字信号输入/输出端;

(3) Vcc为外接供电电源输入端(在寄生电源接线方式时接地)。 4、设计原理框图

图(2)原理框图 三、硬件设计

本系统硬件部分由三个模块组成:

1、 单片机最小系统:12M晶振、复位电路、AT89C51单片机 2、 2个DS18B20温度传感器

3、 一个LCD显示屏(配合排阻)

DS18B20内部结构

(1) DS18B20的内部结构如下图所示。

图(3) DS18B20内部结构图

DS18B20有4个主要的数据部件:

① 64位激光ROM。64位激光ROM从高位到低位依次为8位CRC、48位序列号和8位家族代码(28H)组成。 ② 温度灵敏元件。

③ 非易失性温度报警触发器TH和TL。可通过软件写入用户报警上下限值。

④ 配置寄存器。配置寄存器为高速暂存存储器中的第五个字节。DS18B20在0工作时按此寄存器中的分辨率将温度转换成相应精度的数值,其各位定义如图(4)所示。

LSB

MSB DS18B20配置寄存器结构图 图(4)

其中,TM:测试模式标志位,出厂时被写入0,不能改变;R0、R1:温度计分辨率设置位,其对应四种分辨率如下表所列,出厂时R0、R1置为缺省值:R0=1,R1=1(即12位分辨率),用户可根据需要改写配置寄存器以获得合适的分辨率。

配置寄存器与分辨率关系表 :

图(5) (2) 高速暂存存储器

高速暂存存储器由9个字节组成,其分配如下图所示。当温度转换命令发布后,经转换所得的温度值以二字节补码形式存放在高速暂存存储器的第0和第1个字节。单片机可通过单线接口读到该数据,读取时低位在前,高位在后,数据格式如图所示。对应的温度计算:当符号位S=0时,直接将二进制位转换为十进制;当S=1时,先将补码变为原码,再计算十进制值。 MSB

LSB DS18B20 存储器映像图

图(

6)

温度值格式图DS18B20 温度数据表:

图(7)

典型对应的温度值表:

图(8)典型对应的温度值表 单片机最小系统:

图(9)单片机最小系统

LCD显示屏电路:

图(10)LCD显示屏电路

具体总体电路图如下:

图(11)总体硬件图

四、软件设计

1、主程序方案

主程序调用了4个子程序和一个欢迎开机画面的程序,4个子程序分别是液晶初始化、DS18B201的初始化、DS18B202的初始化、和液晶显示数据的程序。

(1) 液晶初始化程序:8位数据端口,2行显示,5*7点阵、开启显示, 无光标、清屏、AC

递增, 画面不动。

(2) 分别对两个DS18B20温度传感器初始化程序:初始化,读写一个字节, (3) 液晶显示的子程序:确定液晶字符的输入位置,将字符输出到液晶显示

(4) 液晶显示温度程序:先读DS18B20当前温度,将温度转化成液晶字符显示。

将各个功能程序以子程序的形式写好,当写主程序的时候,只需要调用子程序调用指令使得程序结构清晰,无论是修改还是维护都比较方便。将功能程序段写成子程序的形式,除了方便调用之外,还有一个好处那就是以后写程序的时候如果要用到,就可以直接调用这个单元功能模块。 2、流程图

主程序流程图:

图(11)主程序流程图

图(12)液晶初始化流程图

图(13)DS13B20的读取数据流程图

五、调试仿真

开机画面:

14)液晶显示流程图

图(

图(15)开机画面

保持两秒后显示第一个温度:

图(16)显示第一个温度

保持两秒后显示第二个传感器测量的温度:

图(17)显示第二个温度

如此循环显示两个温度,仿真成功。

六、设计总结

AT89C51的时钟为12M,I/O口可达32个,较高的时钟频率和丰富的I/O,都为实现电路功能提供了非常有利的条件。同时也AT89S51内含4KB FLASH ROM,开发环境友好,易用,方便,加上Proteus仿真大大加快本系统设计开发。在此次设计中学会了对Proteus的基本使用,对里面一些基本元件的英文,如电阻RES、电容CAP、晶振CRYSTAL等,学会了连线和运行。

在设计过程中也遇到一些问题,由于LCD是现实的字符型数据,数字不能直接送去显示,所有对于数字的显示首先要转换为字符格式,方法为:数字+‘0’;对于温度传感器的小数处理也遇到一些问题,两个选的是12位,精度为0.0625,DS18B20的温度寄存器里低八位的低四位为小数部分,小数的值为0.0625*低八位的低四位,但是由于单片机的数据处理能力较差,不能处理小数的乘法运算,用上方法就显示错误,后来想到可以把小数先变成整数处理,令低八位的低四位为t,小数后的第一位=625*t/1000,然后将这个数字在小数点后显示即可。

其实该本设计还有很多的不足,本实验是用单片机的多个I/O口来驱动多路,DS18B20是一总线结构,每一个DS18B20 在其ROM 中都存有一个其唯一的48位序列号,在出厂前已写入片内RMO中,主机在进行操作程序前必须逐一接入18B20 用读ROM(33H)命令将该18B20 的序列号读出并登录.当主机需要对众多在线的DS18B20 的某一个进行操作,首先要发出匹配ROM 命令(55H),紧接着主机提供64位序列(包括该DS8B20的48位序列号),之后操作就是针对该DS18B20的.而所谓跳过ROM 命令.即为:之后的操作是对所有DS18B20 的,所以可

以在一根总线上挂多个DS18B20。

七、主要参考资料:

[1] 林志琦.基于Proteus的单片机可视化软硬件仿真[M].北京:北京航空航天大学出版社,2006.9

[2] 周润景,张丽娜.基于PROTEUS的电路及单片机系统设计与仿真[M].北京:北京航空航天大学出版社,2006.5

[3] 张靖武,周灵彬.单片机系统的PROTEUS设计与仿真[M].北京:电子工业出版社,2007.4 [4] 周润景,张丽娜.PROTEUS入门实用教程[M].北京:机械工业出版社,2007.9

[5] 楼然苗,李光飞.51系列单片机设计实例[M].北京:北京航空航天大学出版社,2003.3 [6] 楼然苗,李光飞.单片机课程设计指导[M].北京:北京航空航天大学出版社,2007.7 [7]. 贾东耀,汪仁煌. 数字温度传感器在仓库温度检测系统的应用[J]. 传感器世界,2001 [8] DALLAS DS18B20数据手册[Z].http://

八、附源程序代码

#include <REG51.H> #include <intrins.h> #include <math.h>

#define uint unsigned int #define uchar unsigned char

uchar temp_value; //温度值 uchar TempBuffer[7];

void show_time(); //液晶显示程序 uchar temp_value1; //温度值 uchar TempBuffer1[7]; char xiaoshu=0; char xiaoshu1=0; void show_time1();

/***********1602液晶显示部分子程序****************/

char done,count,temp,flag,up_flag,down_flag;

//Port Definitions********************************************************** sbit LcdRs = P2^0; sbit LcdRw = P2^1; sbit LcdEn = P2^2; sfr DBPort = 0x80; //P0=0x80,P1=0x90,P2=0xA0,P3=0xB0.数据端口 sbit DQ = P1^7; //温度传送数据IO口 sbit DQ1=P1^6; //内部等待函

************************************************************************** unsigned char LCD_Wait(void)

{ LcdRs=0; LcdRw=1; _nop_(); LcdEn=1; _nop_(); LcdEn=0; return DBPort; } //向LCD写入命令或数************************************************************ #define LCD_COMMAND 0 // Command #define LCD_DATA 1 // Data #define LCD_CLEAR_SCREEN 0x01 // 清屏 #define LCD_HOMING 0x02 // 光标返回原点 void LCD_Write(bit style, unsigned char input) { LcdEn=0; LcdRs=style; LcdRw=0; _nop_(); DBPort=input; _nop_();//注意顺序 LcdEn=1; _nop_();//注意顺序 LcdEn=0; _nop_(); LCD_Wait(); }

//设置显示模式************************************************************ #define LCD_SHOW 0x04 //显示开 #define LCD_HIDE 0x00 //显示关

#define LCD_CURSOR 0x02 //显示光标 #define LCD_NO_CURSOR 0x00 //无光标

#define LCD_FLASH 0x01 //光标闪动 #define LCD_NO_FLASH 0x00 //光标不闪动

void LCD_SetDisplay(unsigned char DisplayMode) { LCD_Write(LCD_COMMAND, 0x08|DisplayMode); }

//设置输入模式************************************************************ #define LCD_AC_UP 0x02 #define LCD_AC_DOWN 0x00 // default

#define LCD_MOVE 0x01 // 画面可平移 #define LCD_NO_MOVE 0x00 //default

void LCD_SetInput(unsigned char InputMode) { LCD_Write(LCD_COMMAND, 0x04|InputMode); }

//初始化LCD************************************************************ void LCD_Initial() { LcdEn=0; LCD_Write(LCD_COMMAND,0x38); //8位数据端口,2行显示,5*7点阵 LCD_Write(LCD_COMMAND,0x38); LCD_SetDisplay(LCD_SHOW|LCD_NO_CURSOR); //开启显示, 无光标 LCD_Write(LCD_COMMAND,LCD_CLEAR_SCREEN); //清屏 LCD_SetInput(LCD_AC_UP|LCD_NO_MOVE); //AC递增, 画面不动 }

//液晶字符输入的位置************************ void GotoXY(unsigned char x, unsigned char y) { if(y==0) LCD_Write(LCD_COMMAND,0x80|x); if(y==1) LCD_Write(LCD_COMMAND,0x80|(x-0x40)); }

//将字符输出到液晶显示 void Print(unsigned char *str) { while(*str!='\0') { LCD_Write(LCD_DATA,*str); str++; } }

/***********ds18b20子程序*************************/

/***********ds18b20延迟子函数(晶振12MHz )*******/

void delay_18B20(unsigned int i) {

while(i--); }

/**********ds18b20初始化函数**********************/

void Init_DS18B20(void) { unsigned char x=0; DQ = 1; //DQ复位 delay_18B20(8); //稍做延时 DQ = 0; //单片机将DQ拉低 delay_18B20(80); //精确延时 大于 480us DQ = 1; //拉高总线 delay_18B20(14); x=DQ; //稍做延时后 如果x=0则初始化成功 x=1则初始化失败 delay_18B20(20); }

/***********ds18b20读一个字节**************/ unsigned char ReadOneChar(void) { uchar i=0; uchar dat = 0; for (i=8;i>0;i--) { DQ = 0; // 给脉冲信号 dat>>=1; DQ = 1; // 给脉冲信号 if(DQ) dat|=0x80; delay_18B20(4); }

return(dat); }

/*************ds18b20写一个字节****************/

void WriteOneChar(uchar dat) {

unsigned char i=0; for (i=8; i>0; i--) { DQ = 0; DQ = dat&0x01;

delay_18B20(5); DQ = 1; dat>>=1; } }

/**************读取ds18b20当前温度************/ void ReadTemp(void) { unsigned char a=0; unsigned char b=0; char t; long tt; Init_DS18B20(); WriteOneChar(0xCC); // 跳过读序号列号的操作 WriteOneChar(0x44); // 启动温度转换 delay_18B20(100); // this message is wery important Init_DS18B20(); WriteOneChar(0xCC); //跳过读序号列号的操作 WriteOneChar(0xBE); //读取温度寄存器等(共可读9个寄存器) delay_18B20(100); a=ReadOneChar(); //读取温度值低位 b=ReadOneChar(); //读取温度值高位 temp_value=b<<4; temp_value+=(a&0xf0)>>4; t=a&0x0f; tt=t*625; xiaoshu=tt/1000; }

void temp_to_str() //温度数据转换成液晶字符显示 {

TempBuffer[0]=temp_value/10+'0'; //十位 TempBuffer[1]=temp_value%10+'0'; //个位 TempBuffer[2]='.';

TempBuffer[3]=xiaoshu+'0'; TempBuffer[4]=0xdf; TempBuffer[5]='C'; TempBuffer1[6]='\0'; }

void Delay1ms(unsigned int count) { unsigned int i,j; for(i=0;i<count;i++) for(j=0;j<120;j++);

前两个就是温度

}

void show_time() //液晶显示程序 {

ReadTemp(); //开启温度采集程序 temp_to_str(); GotoXY(0,0); Print("first");

GotoXY(0,1);//温度数据转换成液晶字符 Print("temp:");

GotoXY(6,1); //液晶字符显示位置 Print(TempBuffer); //显示温度 Delay1ms(400); //扫描延时 }

/***********ds18b20子程序*************************/

/***********ds18b20延迟子函数(晶振12MHz )*******/

/**********ds18b20初始化函数**********************/

void Init_DS18B201(void) { unsigned char x=0; DQ1 = 1; //DQ复位 delay_18B20(8); //稍做延时 DQ1 = 0; //单片机将DQ拉低 delay_18B20(80); //精确延时 大于 480us DQ1 = 1; //拉高总线 delay_18B20(14); x=DQ1; //稍做延时后 如果x=0则初始化成功 x=1则初始化失败 delay_18B20(20); }

/***********ds18b20读一个字节**************/

unsigned char ReadOneChar1(void) { uchar i=0; uchar dat = 0; for (i=8;i>0;i--) { DQ1 = 0; // 给脉冲信号 dat>>=1;

DQ1 = 1; // 给脉冲信号 if(DQ1) dat|=0x80; delay_18B20(4); }

return(dat); }

/*************ds18b201写一个字节****************/

void WriteOneChar1(uchar dat) {

unsigned char i=0; for (i=8; i>0; i--) { DQ1 = 0; DQ1 = dat&0x01; delay_18B20(5); DQ1 = 1; dat>>=1; } }

/**************读取ds18b201当前温度************/

void ReadTemp1(void) { unsigned char a=0; unsigned char b=0; unsigned char t=0; long tt; Init_DS18B201(); WriteOneChar1(0xCC); // 跳过读序号列号的操作 WriteOneChar1(0x44); // 启动温度转换 delay_18B20(100); // this message is wery important Init_DS18B201(); WriteOneChar1(0xCC); //跳过读序号列号的操作 WriteOneChar1(0xBE); //读取温度寄存器等(共可读9个寄存器)度 delay_18B20(100); a=ReadOneChar1(); //读取温度值低位

前两个就是温

b=ReadOneChar1(); //读取温度值高位 temp_value1=b<<4; temp_value1+=(a&0xf0)>>4; t=a&0x0f; tt=t*625;

xiaoshu1=tt/1000; }

void temp_to_str1() //温度数据转换成液晶字符显示 {

TempBuffer1[0]=temp_value1/10+'0'; //十位 TempBuffer1[1]=temp_value1%10+'0'; //个位 TempBuffer1[2]='.';

TempBuffer1[3]=xiaoshu1+'0';

TempBuffer1[4]=0xdf; //温度符号 TempBuffer1[5]='C'; TempBuffer1[6]='\0'; }

void show_time1() //液晶显示程序 {

ReadTemp1(); //开启温度采集程序 temp_to_str1(); GotoXY(0,0); Print("second");

GotoXY(0,1);//温度数据转换成液晶字符 Print("temp:");

GotoXY(6,1); //液晶字符显示位置 Print(TempBuffer1); //显示温度

Delay1ms(400); //扫描延时 }

main() { LCD_Initial(); //液晶初始化 Init_DS18B20( ) ; //DS18B20初始化 Init_DS18B201( ); GotoXY(2,0); Print("welcome!"); GotoXY(1,1);

Print("design by zw!"); ReadTemp(); ReadTemp1();

Delay1ms(2000);

LCD_Write(LCD_COMMAND,LCD_CLEAR_SCREEN); while(1) {

show_time(); //液晶显示数据 // flag=0;

Delay1ms(2000); LCD_Write(LCD_COMMAND,LCD_CLEAR_SCREEN); show_time1(); // flag=0; Delay1ms(2000);

LCD_Write(LCD_COMMAND,LCD_CLEAR_SCREEN); } }

本文来源:https://www.bwwdw.com/article/76m4.html

Top