ReCclay
认证:VIP会员
所在专题目录 查看专题
【蓝桥杯单片机组模块】3、上手 CT107D 外设驱动之数码管模块
【蓝桥杯单片机组模块】4、按键模块
【蓝桥杯单片机组模块】5、EEPROM模块
【蓝桥杯单片机组模块】6、AD/DA转换模块
【蓝桥杯单片机组模块】7、DS18B20温度传感器模块
【蓝桥杯单片机组模块】8、DS1302时钟模块
作者动态 更多
【FPGA基础】基于 Pango Design Suite(PDS) 的FPGA开发流程
2021-05-14 11:22
【FPGA基础】基于Quartus Prime 17.1 的FPGA开发流程
2021-05-08 17:49
【AD快速入门】8051最小系统绘制
2021-04-22 10:03
蓝桥嵌入式之 ADC电压采集与显示
2021-04-14 11:48
蓝桥嵌入式之 实时时钟RTC
2021-04-13 14:50

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

导读:《蓝桥杯单片机组》专栏文章是博主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。在该部分学习中并没有什么太难的知识点,反而是一些技巧性的东西比较多,这个多多总结就可以了。

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

声明:本内容为作者独立观点,不代表电子星球立场。未经允许不得转载。授权事宜与稿件投诉,请联系:editor@netbroad.com
觉得内容不错的朋友,别忘了一键三连哦!
赞 355
收藏 341
关注 431
成为作者 赚取收益
全部留言
0/200
  • dy-i2UfRuvP 2021-05-19 13:22
    精彩,很多东西还没接触到
    回复
  • dy-iipPZRPN 2021-05-13 22:45
    对我很有帮助
    回复
  • dy-3EbVR6Ei 2021-05-13 22:36
    思路清晰,受益匪浅
    回复
  • dy-Xq2JxpfN 2021-05-13 22:18
    学习了
    回复
  • dy-9g42stbW 2021-05-13 22:10
    佩服楼主
    回复
  • dy-mLj7kl5v 2021-05-13 20:43
    对我很有帮助
    回复
  • dy-apcih3c1 2021-05-13 20:26
    思路清晰,受益匪浅
    回复
  • dy-k78ZHtFD 2021-05-13 20:09
    学习了
    回复
  • dy-nAWdnPGS 2021-05-13 18:55
    请教一下
    回复
  • dy-prSX6RBY 2021-05-13 18:48
    比论文强一万倍
    回复
  • dy-jqGVYqsF 2021-05-13 16:53
    学习了
    回复
  • dy-VIQ9auhf 2021-05-13 15:06
    请教一下
    回复
  • dy-7mura2gg 2021-05-13 14:50
    精彩,很多东西还没接触到
    回复
  • dy-YN3DYTeH 2021-05-13 14:41
    学习了
    回复
  • dy-9hjGevyn 2021-05-13 13:58
    对我很有帮助
    回复
  • dy-H1WY5jXH 2021-05-13 13:25
    感谢分享
    回复
  • dy-wVQjSHHX 2021-05-13 13:09
    不亚于看了一篇高质量论文
    回复
  • dy-88VlYaFf 2021-05-12 15:53
    感谢分享
    回复
  • dy-9QTV6UZW 2021-05-12 15:30
    对我很有帮助
    回复
  • dy-WYS5BCmB 2021-05-12 15:16
    什么时候更新
    回复