zl程序教程

您现在的位置是:首页 >  系统

当前栏目

【蓝桥杯单片机组模块】7、DS18B20温度传感器模块

2023-09-11 14:20:36 时间

微信搜索ReCclay,也可免费阅读博主蓝桥系列所有文章,后台回复“代码”即可获取蓝桥所有备赛代码!关注博主公众号,还可拥有加入博主粉丝群实时沟通技术难题、免费下载CSDN资源等多项福利,还在等什么呢?快快扫码关注,学习才不会迷路

在这里插入图片描述

这里再向各位同学推荐一个CSDN博主 ReRrain 的蓝桥备赛博客,博主秉持初学者思路,向你讲述自己蓝桥备赛的心路历程,娓娓道来蓝桥备赛经验,个人觉得非常不错,值得细细品读。


导读:《蓝桥杯单片机组》专栏文章是博主2018年参加蓝桥杯的单片机组比赛所做的学习笔记,在当年的比赛中,博主是获得了省赛一等奖,国赛二等奖的成绩。成绩虽谈不上最好,但至少问心无愧。如今2021年回头再看该系列文章,仍然感触颇多。为了能更好地帮助到单片机初学者,今年特地抽出时间对当年的文章逻辑和结构进行重构,以达到初学者快速上手的目的。需要指出的是,由于本人水平有限,如有错误还请读者指出,非常感谢。那么,接下来让我们一起开始愉快的学习吧。

不积跬步无以至千里,不积小流无以成江海。


上一节我们通过PCF8591这个期间入门学习了ADC相关知识,本篇博文我们继续再来学习一下一个常见的温度传感器模块,它使用的通信协议是DS18B20,话不多说,开搞。程序代码可到Github下载<传送门>。

一、基础理论

注意:18B20对时序要求严格,不可被中断打断!一旦打断会出现乱码,显示的温度是乱码。所以切记,操作的时候关EA !

2018年3月30日更:中午吃完饭仔细想想这个里面还是有问题的,关了中断意味着我们的实时任务处理不了了!可能导致部分功能就没法实现了!既然现在面临的问题是:温度显示是乱码。那再想一下,原因还是我们直接从18b20读然后直接实时显示导致的,那我们不实时显示,而是放到缓冲区里面。然后对温度进行合法性检验再从缓冲区里读出显示不也可以嘛!


注意最下面程序中的软件延时操作技巧,IT单片机和12T单片机,关于nop延时,可以看这里。<传送门>

这里写图片描述

一共 2 个字节,LSB 是低字节,MSB 是高字节,其中 MSb 是字节的高位,LSb 是字节的低位。可以看出来,二进制数字,每一位代表的温度的含义,都表示出来了。其中 S表示的是符号位,低 11 位都是 2 的幂,用来表示最终的温度。DS18B20 的温度测量范围是从-55 度到+125 度,而温度数据的表现形式,有正负温度,寄存器中每个数字如同卡尺的刻度一样分布。

这里写图片描述

二进制数字最低位变化 1,代表温度变化 0.0625 度的映射关系。当 0 度的时候,那就是0x0000,当温度 125 度的时候,对应十六进制是 0x07D0,当温度是零下 55 度的时候,对应的数字是 0xFC90。反过来说,当数字是 0x0001 的时候,那温度就是 0.0625 度了。

对应的协议为 1-wire!!!

1.1、初始化

这里写图片描述

和 I 2 C 的寻址类似,1-Wire 总线开始也需要检测这条总线上是否存在 DS18B20 这个器件。如果这条总线上存在 DS18B20,总线会根据时序要求返回一个低电平脉冲,如果不存在的话,也就不会返回脉冲,即总线保持为高电平,所以习惯上称之为检测存在脉冲。

存在脉冲检测过程,首先单片机要拉低这个引脚,持续大概 480us 到 960us 之间的时间即可,我们的程序中持续了 500us。然后,单片机释放总线,就是给高电平,DS18B20 等待大概 15 到 60us 后,会主动拉低这个引脚大概是 60 到 240us,而后 DS18B20 会主动释放总线,这样 IO 口会被上拉电阻自动拉高。

由于 DS18B20 时序要求非常严格,所以在操作时序的时候,为了防止中断干扰总线时序,先关闭总中断。然后第一步,拉低 DS18B20 这个引脚,持续 500us;第二步,IO释放总线,延时 60us;第三步,读取存在脉冲,并且等待存在脉冲结束。

这里写图片描述

1.2、ROM 操作指令

总线上可以挂多个器件,通过不同的器件地址来访问不同的器件。同样,1-Wire 总线也可以挂多个器件,但是它只有一条线,如何区分不同的器件呢?

在每个 DS18B20 内部都有一个唯一的 64 位长的序列号,这个序列号值就存在 DS18B20内部的 ROM 中。开始的 8 位是产品类型编码(DS18B20 是 0x10),接着的 48 位是每个器件唯一的序号,最后的 8 位是 CRC 校验码。DS18B20 可以引出去很长的线,最长可以到几十米,测不同位置的温度。单片机可以通过和DS18B20 之间的通信,获取每个传感器所采集到的温度信息,也可以同时给所有的 DS18B20 发送一些指令。

Skip ROM(跳过 ROM):0xCC。当总线上只有一个器件的时候,可以跳过 ROM,不进行 ROM 检测。

1.3、RAM 存储器操作指令

RAM 读取指令,常用的就两条

Read Scratchpad(读暂存寄存器):0xBE

DS18B20 的温度数据是 2 个字节,我们读取数据的时候,先读取到的低位,然后才是高位!

Convert Temperature(启动温度转换):0x44

当我们发送一个启动温度转换的指令后,DS18B20 开始进行转换。从转换开始到获取温度,DS18B20 是需要时间的,而这个时间长短取决于 DS18B20 的精度。前边说 DS18B20 最高可以用 12 位来存储温度,但是也可以用 11 位,10 位和 9 位一共四种格式。位数越高,精度越高,9 位模式最低位变化 1 个数字温度变化 0.5 度,同时转换速度也要快一些。

这里写图片描述

其中寄存器 R1 和 R0 决定了转换的位数,出厂默认值就 11,也就是 12 位表示温度,最大的转换时间是 750ms。当启动转换后,至少要再等 750ms 之后才能读取温度,否则读到的温度有可能是错误的值。

1.4、DS18B20 的位读写时序

写相关
这里写图片描述

当要给 DS18B20 写入 0 的时候,单片机直接将引脚拉低,持续时间大于 60us 小于 120us就可以了。图上显示的意思是,单片机先拉低 15us 之后,DS18B20 会在从 15us 到 60us 之间的时间来读取这一位,DS18B20 最早会在 15us 的时刻读取,典型值是在 30us 的时刻读取,最多不会超过 60us,DS18B20 必然读取完毕,所以持续时间超过 60us 即可。

当要给 DS18B20 写入 1 的时候,单片机先将这个引脚拉低,拉低时间大于 1us,然后马上释放总线,即拉高引脚,并且持续时间也要大于 60us。和写 0 类似的是,DS18B20 会在15us 到 60us 之间来读取这个 1

这里写图片描述

读相关
这里写图片描述

当要读取 DS18B20 的数据的时候,我们的单片机首先要拉低这个引脚,并且至少保持1us 的时间,然后释放引脚,释放完毕后要尽快读取。从拉低这个引脚到读取引脚状态,不能超过 15us。大家从图 16-18 可以看出来,主机采样时间,也就是 MASTER SAMPLES,是在 15us 之内必须完成的。

这里写图片描述

常用的带小数的数据处理方法有两种,一种是定义成浮点型直接处理,第二种是定义成整型,然后把小数和整数部分分离出来,在合适的位置点上小数点即可。

特别强调:DS18B20 的时序比较严格,写的过程中最好不要有中断打断,但是在两个“位”之间的间隔,是大于 1 小于无穷的,那在这个时间段,我们是可以开中断来处理其它程序的。

二、动手实验

贴出DS18B20的底层代码…

#include "config.h"

void Delay(u8 us)
{
 	do{
		_nop_();
		_nop_();
		_nop_();
		_nop_();
		_nop_();
		_nop_();
		_nop_();
		_nop_();
	}while(--us);
}

bit Get18B20Ack()
{
	bit ack;
	
	DS18B20_IO = 0;
	Delay(250);
	Delay(250);
	DS18B20_IO = 1;
	Delay(60);
	ack = DS18B20_IO;
	while(!DS18B20_IO);
	
	return ack; 	
}

void DS18B20Write(u8 dat)
{
 	u8 mask;

	for(mask=0x01; mask!=0; mask<<=1)
	{
		DS18B20_IO = 0;
		Delay(2);
	 	if(dat&mask)
		{
		 	DS18B20_IO = 1;
		}
		else
		{
		 	DS18B20_IO = 0;
		}
		Delay(60);
		DS18B20_IO = 1;
	}
}

u8 DS18B20Read()
{
 	u8 mask, dat=0;
	
	for(mask=0x01; mask!=0; mask<<=1)
	{
		DS18B20_IO = 0;
		Delay(2);
		DS18B20_IO = 1;
		Delay(2);
	 	if(DS18B20_IO)
		{
		 	dat |= mask;
		}
		Delay(60);
	}
	
	return dat;	
}

bit Start18B20()
{
 	bit ack;

	ack = Get18B20Ack();
	if(ack == 0)
	{
	 	DS18B20Write(0xCC);
		DS18B20Write(0x44);	
	}

	return ~ack;
}

bit Get18B20Temp(int *temp)
{
 	bit ack;
	u8 LSB, MSB;

	ack = Get18B20Ack();
	if(ack == 0)
	{
	 	DS18B20Write(0xCC);
		DS18B20Write(0xBE);
		LSB = DS18B20Read();
		MSB = DS18B20Read();
		*temp = ((u16)MSB<<8) + LSB;
	}

	return ~ack;
} 

后记

如果想实现,显示小数点后×位,也是可以的。
小数在数码管上的处理,两种思路:

  • 统一定义为整型,最后再加小数点。
  • 还有一种是定义为浮点型,然后扩大相应的倍数再加小数点。(emmm,好像一样。_

这里说一种自己的实现:通过datasheet其实是可以知道它的精度是0.0625的,然后我们如果想取到小数点后两位的话,其实算出来的整数后乘以6.25就行。

这里写图片描述

这里写图片描述

小结:本篇文章主要介绍了单片机学习中的一个重要模块:DS18B20。在该部分学习中并没有什么太难的知识点,反而是一些技巧性的东西比较多,这个多多总结就可以了。

希望大家多多支持我的原创文章。如有错误,请大家及时指正,非常感谢。


微信搜索ReCclay,即可免费阅读博主蓝桥系列所有文章,后台回复“代码”即可获取蓝桥所有备赛代码!关注博主公众号,还可拥有加入博主粉丝群实时沟通技术难题、免费下载CSDN资源等多项福利,还在等什么呢?快快扫码关注,学习才不会迷路

在这里插入图片描述