导读:《蓝桥杯单片机组》专栏文章是博主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。在该部分学习中并没有什么太难的知识点,反而是一些技巧性的东西比较多,这个多多总结就可以了。
希望大家多多支持我的原创文章。如有错误,请大家及时指正,非常感谢。