基于51单片机+DS18B20温度测温器+LCD1602显示

DS18B20相关介绍

学习视频推荐

我看的是B站的从零学电子。网址

DS18B20特性

1.独特的单总线接口,就需一条线则可实现双向通信(测温)
2.测温范围:-55℃~+125℃,可通过编程设定9—12位分辨率,对应分辨温度分别为0.5、0.25、0.125、0.0625℃。
3.支持多点组网(可连接多个DS18B20温度传感器),多个DS18B20可以并联(3或2线)实现多个组网测温,但注意超过8个要解决好供电问题,否则电压过低会导致传输不稳定,从而数据不准确。
4.工作电压:3.0~5.5V (寄生电源方式下可由数据线供电)
5.在使用过程中不需要外围电路,全部传感元件及转换电路都在芯片内了。(上拉电阻
6.测温结果直接是数字量输出,单总线串行传送方式,同时可传送CRC校验码(校验数据采集是否正确),具有极强的抗干扰和纠错能力。
7.在9位分辨率时最多在93.75ms内把温度转换为数字,12位分辨率时最多在750ms内把温度值转换为数字。
8.负压特性:电源极性接反时,芯片不会因发热而烧毁, 但不能正常工作。

封装形式与引脚说明

在这里插入图片描述

供电方式(外部电源供电、寄生电源供电、寄生电源强上拉)

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

内部结构

DS18B20内部结构如图所示,其中与操作有关的是:64位光刻ROM、温度传感器、9个字节的RAM存储器、EEPROM(温度报警寄存器TH和TL、配置寄存器)。
在这里插入图片描述
光刻ROM中64位序列号是出厂前就光刻好的,相当地址序列号。排列是低位开始,低8位(产品类型标号),接着48位(自身序列号,)相当于身份证号、最高8位(前面56位的循环亢余校验码)。
如果一条总线挂接多个DS18B20需要MCU(微控制器)通过单总线对多个DS18B20进行寻址。
在这里插入图片描述

在这里插入图片描述

温度存储格式及配置寄存器(模式和分辨率)

DS18B20温度传感器进行测温,测温是以16位的二进制形式提供。
存放格式:
在这里插入图片描述
16位中 低4位是温度的小数部分、最高5位是温度的正负(全为0为正,全为1为负),中间的7位则是温度的整数部分。小数部分十进制等于16进制乘0.0625。

例子:
在这里插入图片描述
注意:如果是负数温度,那么得按位取反+1。
比如数据为 1111 1100 1001 0000
首先低4位都为0.所以温度小数部分为0。最高5位为1,所以温度是负数,所以我们得按位取反才是正确的数, 温度的整数部分为 100 1001——>按位取反得:011 0110 再+1 则结果是 011 0111 ——>0x37(16进制)——>55℃(十进制)

配置寄存器

TMR1R011111

TM:测试模式位,用于设置是在工作方式还是测试模式。在DS18B20出厂时该位设为0,用户不要改动。
R1 R0:分辨率设置

R1R0分辨率/位温度最大转向时间/ms
00993.75
0110187.5
1011375
1112750
DS18B20指令(ROM指令操作)
序号指令代码说明
1读取ROM33H读DS18B20的64位序列号(只能适用于总线上只有一个DS18B20)
2符合 ROM55H匹配指令,发出64位ROM编码,与总线上一个或多个DS18B20匹配,完全对应则响应。(单个或多个均可)
3跳过 ROMCCH忽略64位ROM地址,直接向DS18B20发温度变换指令,适用于单片机工作。(适用于单个DS18B20)。
4搜索 ROMF0H用于确定挂接在总线上DS18B20个数和 识别64位ROM地址(一般用于多个DS18B20)。
5报警搜索命令ECH执行后搜索温度超过设定值上限或下限才做出响应。
6写暂存器4EH在该写暂存器指令后向DS18B20的暂存器TH.TL以及配置寄存器中写入数据。
7读暂存器BEH发送该指令后DS18B20将从一个字节开始,依次送出9个字节的内容。如果不想读完所有字节。控制器可以在任何时间发出复位指令中止读取或直接不读取。
8复制暂存器48H将TH.TL和配置寄存器的内容拷贝到EEPROM中,如果使用寄生电源,总线控制器必须在这条指令发出后10us内启动强上拉并保持至少10ms时间。
9启动温度转换指令44H温度转换完成后存放在第1个和第2个字节中,如果是寄生电源,总线必须在发出这条指令后的10us内启动强上拉。
10复制EEPROM指令B8H把TH.TL和配置寄存器的值拷贝回暂存器。这种拷贝操作在DS18B20上电时自动执行,上电后,暂存器里就存了有效数据。
11读供电方式指令B4H发给DS18B20后,再发出读时间间隙,后返回电源模式:0为寄生电源、1为外部电源。

注:每个指令在写都是 低位在前 高位在后 DS18B20发送也是先发低位,再发高位。
比如发送跳过ROM指令(CCH) 二进制位:1100 1100 。发送顺序为
0、0 、1、1、 0、 0、 1、 1 。

指令的使用

多个DS18B20情况: 对某一个操作时,主机先逐个与DS18B20挂接-搜索ROM——(F0H),发出匹配ROM指令(55H),紧接着提供64位序列号,之后操作就是针对DS18B20的了。

单个DS18B20情况: 不需要搜索ROM指令,读ROM指令以及匹配ROM等操作,直接跳过ROM指令(CCH),温度转换(44H),读温度操作(8EH)。

注意事项

一、 DS18B20硬件是简单,但软件就比较复杂,特别是时序要求。
二、 连接DS18B20线长限制:部分资料显示:
采用普通信号电缆传输超50m时,测温数据不稳定。
采用带屏蔽层双绞线电缆,正常通讯距离可达到150m。
采用每米绞合次数更多的带屏蔽层双绞线电缆时,通讯距离进一步加长。
三、 距离长了测温要考虑总线分布电容和阻抗匹配问题。
在测温程序设计中,一般如果硬件没什么问题,可以采用延时来跳过检测,但是如果要检测是否有应答要注意不要进入了死循环。

时序图

初始化

在这里插入图片描述

/*DS18B20初始化函数*/
void initDs18b20()
{
	DS18B20 = 1;
	delay20us();
	DS18B20 = 0;   //拉低电平 
	delay480us();  //480us-960us之间均可
	DS18B20 = 1;   //拉高电平
	delay50us();   //等待15us-60us
	if(DS18B20 == 1) //如果未响应
	{
		ds18b20Flag = 1; //DS18B20未响应 标志位置1
	}
	delay240us();	
}
写时序(写0或1)

在这里插入图片描述

/*DS18B20写命令函数*/
void ds18b20WriteData(unsigned char com)
{
	unsigned char i;
	for(i=0;i<8;i++)
	{
		DS18B20 = 0; //拉低电平
		//延时至少1us
		DS18B20 = com&0x01;
		delay60us(); //至少60us直到周期结束
		DS18B20 = 1;
		com = com>>1; //右移一位
	}		
}
读时序(读0或1)

在这里插入图片描述

/*DS18B20读数据函数*/
unsigned char ds18b20ReadData()
{
	unsigned char i;
	unsigned char dat = 0; //接收数据

	for(i=0;i<8;i++)
	{
		DS18B20 = 0;  //拉低电平至少1us
		dat=dat>>1;	  //右移一位
		DS18B20 = 1; //释放总线
		if(DS18B20 == 1) //如果是1
		{
			dat = dat|0x80;
		}
		delay45us(); //保持45us
		DS18B20 = 1; //释放总线
	}
	return dat;
}

程序代码

每一次进行写ROM相关命令都记得初始化。
对于单个DS18B20我们可以直接跳过ROM指令 直接温度转换。读取温度

步骤:
1.初始化
2.跳过ROM指令
3.启动温度转换(需要时间)
4.延时(等待温度转换)
5.初始化 (记得每写ROM相关命令记得需要从初始化开始)
6.读取温度
7.显示温度

LCD1602显示温度

main.c(主函数)
#include <reg52.h>
#include "delay.h"
#include "lcd1602.h"

sbit DS18B20 = P3^7; //DS18B20引脚
unsigned char ds18b20Flag; //DS18B20是否响应标志位
unsigned char temperature[2] = {'\0'}; //存放温度整数和小数
unsigned char code array[14] = {"DS18B20 error!"};
unsigned char code array1[5] = {"Temp:"};

/*DS18B20初始化函数*/
void initDs18b20()
{
	DS18B20 = 1;
	delay20us();
	DS18B20 = 0;   //拉低电平 
	delay480us();  //480us-960us之间均可
	DS18B20 = 1;   //拉高电平
	delay50us();   //等待15us-60us
	if(DS18B20 == 1) //如果未响应
	{
		ds18b20Flag = 1; //DS18B20未响应 标志位置1
	}
	delay240us();	
}

	
/*DS18B20写命令函数*/
void ds18b20WriteData(unsigned char com)
{
	unsigned char i;
	for(i=0;i<8;i++)
	{
		DS18B20 = 0; //拉低电平
		//延时至少1us
		DS18B20 = com&0x01;
		delay60us();
		DS18B20 = 1;
		com = com>>1;
	}		
}

/*DS18B20读数据函数*/
unsigned char ds18b20ReadData()
{
	unsigned char i;
	unsigned char dat = 0; //接收数据

	for(i=0;i<8;i++)
	{
		DS18B20 = 0;  //拉低电平至少1us
		dat=dat>>1;	  //右移一位
		DS18B20 = 1; //释放总线
		if(DS18B20 == 1)
		{
			dat = dat|0x80;
		}
		delay45us(); //保持45us
		DS18B20 = 1; //释放总线
	}
	return dat;
}

/*读取温度函数*/
void readTemperature()
{
	unsigned char temperatureLow;  //温度低字节
	unsigned char temperatureHigh; //温度高字节
	unsigned char tempFlag = 0; //温度正负标志位
	unsigned char disposeValue; //处理值
	

	initDs18b20();	//初始化DS18B20
	ds18b20WriteData(0xcc); //跳过ROM
	ds18b20WriteData(0x44); //启动温度转换指令
	//延时一段时间
	delay800ms();
	
	initDs18b20(); //每一次写命令都需要初始化
	ds18b20WriteData(0xcc); //跳过ROM
	ds18b20WriteData(0xbe); //读暂存器内容
	
	temperatureLow = ds18b20ReadData();	 //获取温度的第一个字节
	temperatureHigh = ds18b20ReadData(); //获取温度的第二个字节
	
	disposeValue = (temperatureHigh<<4)|(temperatureLow>>4);  //获取温度整数部分
	if(disposeValue>=128)  //温度是负数
	{
		disposeValue = ~disposeValue+1;
		tempFlag = 1;
	}
	temperature[0] = disposeValue; //温度整数
	temperature[1] = temperatureLow & 0x0f; //温度小数 
		
}

void displayTemperature()
{
	write_com(0x85);
	write_data((temperature[0]/100) + 0x30); //温度百位
	write_com(0x86);
	write_data((temperature[0]/10%10) + 0x30); //温度十位
	write_com(0x87);
	write_data((temperature[0]%10) + 0x30);   //温度个位

	write_com(0x88);
	write_data('.');

	write_com(0x89);
	write_data((temperature[1]*10/16) + 0x30);	//小数第一位
//	write_data((tempterature[1]*625/1000));
	write_com(0x8a);
	write_data((temperature[1]*100/16%10) + 0x30);	//小数第二位
//	write_data((tempterature[1]*625/100%10));

	/* 显示 ℃ */
	write_com(0x8b);
	write_data(0xdf);
	write_com(0x8c); 
	write_data('C');
}


void main()
{
	unsigned char i;

	init_lcd(); //初始化1602
	write_com(0x80);
	for(i=0;i<5;i++)
	{
		write_data(array1[i]);
	}
	while(1)
	{
		readTemperature();	  //读取温度
			
		if(ds18b20Flag == 1)  //如果初始化错误
		{
			for(i=0;i<14;i++)
			{
				write_com(0x80);
				write_data(array[i]);	//显示DS18B20 error!
			}
		}
		else
		{
			displayTemperature(); //温度显示
		}
				
	}
}

项目展示

在这里插入图片描述

如果觉得这篇文章对你有用。欢迎大家点赞、评论哈哈
需要整个工程代码,欢迎大家打赏,评论区留上你的邮箱 或者+我Q:844797079 or vx or qq。o( ̄︶ ̄)o
在这里插入图片描述

继续加油!!!

  • 199
    点赞
  • 1216
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 210
    评论
下面是基于51单片机DS18B20温度传感器的温度测量和LCD1602显示的代码: ```c #include <reg52.h> #include <intrins.h> #define DQ P2_0 // DS18B20数据线连接到单片机的P2.0口 #define LCD P0 // LCD1602数据线连接到单片机的P0口 sbit rs = P3^5; // LCD1602的RS引脚连接到单片机的P3.5口 sbit rw = P3^6; // LCD1602的RW引脚连接到单片机的P3.6口 sbit en = P3^7; // LCD1602的EN引脚连接到单片机的P3.7口 typedef unsigned char uchar; typedef unsigned int uint; uchar code table[] = "Temperature:"; // 温度显示的字符串 void delay(uint x) // 短暂延时函数 { uint i, j; for (i = x; i > 0; i--) for (j = 110; j > 0; j--); } void init_ds18b20() // 初始化DS18B20 { uchar i; DQ = 1; delay(1); DQ = 0; delay(80); DQ = 1; delay(20); i = DQ; delay(20); } void write_ds18b20(uchar dat) // 向DS18B20写入一个字节的数据 { uchar i; for (i = 0; i < 8; i++) { DQ = 0; _nop_(); DQ = dat & 0x01; delay(6); DQ = 1; dat >>= 1; } } uchar read_ds18b20() // 从DS18B20读取一个字节的数据 { uchar i, dat = 0; for (i = 0; i < 8; i++) { dat >>= 1; DQ = 0; _nop_(); DQ = 1; delay(1); if (DQ) dat |= 0x80; delay(6); } return dat; } int get_temperature() // 获取温度数据 { uchar i; int temp = 0; init_ds18b20(); write_ds18b20(0xcc); // 跳过ROM操作 write_ds18b20(0x44); // 启动温度转换 delay(100); init_ds18b20(); write_ds18b20(0xcc); write_ds18b20(0xbe); // 读取温度数据 temp |= read_ds18b20(); temp |= (read_ds18b20() << 8); return temp; } void write_lcd1602(uchar dat, uchar cmd) // 向LCD1602写入一个字节的数据或指令 { rw = 0; LCD = cmd; rs = 0; en = 1; _nop_(); en = 0; delay(5); rs = 1; LCD = dat; en = 1; _nop_(); en = 0; delay(5); } void init_lcd1602() // 初始化LCD1602 { write_lcd1602(0x38, 0); write_lcd1602(0x0c, 0); write_lcd1602(0x06, 0); write_lcd1602(0x01, 0); } void main() { int temp; uchar i; init_lcd1602(); while (1) { temp = get_temperature(); write_lcd1602(0x80, 0); // 设置光标位置为第一行第一列 for (i = 0; i < 12; i++) // 显示温度字符串 write_lcd1602(table[i], 1); write_lcd1602((temp >> 8) + '0', 1); // 显示温度的高八位 write_lcd1602((temp & 0xff) / 10 + '0', 1); // 显示温度的低八位的十位 write_lcd1602((temp & 0xff) % 10 + '0', 1); // 显示温度的低八位的个位 delay(500); // 延时一段时间再进行下一次温度测量和显示 } } ``` 这段代码通过DS18B20温度传感器获取温度数据,然后通过LCD1602显示显示温度数据。在主函数中,我们不断循环获取温度数据并进行显示。需要注意的是,DS18B20的数据线连接到单片机的P2.0口,而LCD1602的数据线连接到单片机的P0口。在代码中使用了一些简单的函数来实现DS18B20的读写和LCD1602的初始化和写入数据。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 210
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

皮卡丘吉尔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值