【蓝桥杯】单片机学习(12)——温度传感器DS18B20
1、DS18B20简介DS18B20本身就是一个温度传感器,只需要将DS18B20的数据引脚和单片机的一个I/O口接上,单片机通过1-Wire协议与DS18B20进行通信,读出温度。CT107D开发板相关模块电路图如下:2、DS18B20的温度转换规则DS18B20可以直接读出数字的温度数值。温度传感器的精度为用户可编程的9、10、11或12位,分别以0.5℃,0.25℃,0.125℃和0.062
温度传感器DS18B20
1、DS18B20简介
DS18B20本身就是一个温度传感器,只需要将DS18B20的数据引脚和单片机的一个I/O口接上,单片机通过1-Wire协议与DS18B20进行通信,读出温度。
CT107D开发板相关模块电路图如下:
2、DS18B20的温度转换规则
DS18B20可以直接读出数字的温度数值。温度传感器的精度为用户可编程的9、10、11或12位,分别以0.5℃,0.25℃,0.125℃和0.0625℃增量递增。在上电状态下默认精度为12位。也就是温度每变化0.0625度,二进制数字变化1。转换的精度由配置寄存器决定,如下:(R1R0出厂默认11)

DS18B20启动后保持低功耗等待状态,当需要执行温度测量和AD转换时,总线控制器必须发出[44h]命令,启动温度转换,即Write18b20(0x44)。转换完以后,产生的温度数据以两个字节的形式被存储到 高速暂存器 的温度寄存器中(先低后高),DS18b20继续保持等待状态。
DS18B20的温度数据格式如下,转化后得到12位数据,存储在DS18B20的两个8位的RAM中。MSB里面存储的是高字节,LSB里面存储的是低字节。 高字节的前5位是符号位,如果测得的温度大于0,这5位为‘0’,只要将测到的数值乘以0.0625即可得到实际温度;如果温度小于0,这5位为‘1’,测到的数值需要先减1再取反再乘以0.0625即可得到实际温度。

温度/数据关系转换表如下:

3、ROM & RAM操作指令
(1)ROM指令表
| 指令 | 约定代码 | 功能 |
|---|---|---|
| Read ROM | 33H | 读DS18B20温度传感器ROM的编码,即64位地址 |
| Match ROM | 55H | 后跟64位ROM序列,让总线控制器在多点总线上匹配某一特定的DS18B20。匹配后的从机才能响应后续命令,其余不匹配的从机等待复位脉冲。总线上有单个或多个器件时都可使用该命令。 |
| Skip ROM | CCH | 当只有一个从机时,忽略64位ROM地址,直接向DS18B20发出温度转换命令。 |
| Search ROM | F0H | 用于确定挂在同一总线上DS18B20的个数和识别64位ROM地址,为操作各器件做准备。 |
| Alarm ROM | ECH | 执行后,温度超过上限或下限的片子做出响应。 |
当我们只挂了一个DS18B20时,只需要写一条关于ROM的指令,即Write18b20(0xcc);。
(2)RAM指令表
| 指令 | 约定代码 | 功能 |
|---|---|---|
| 启动温度转换(Convert T) | 44H | 启动DS18B20进行温度转换,从转换到获取温度的时间取决于DS18B20的精度,12位转换最长750ms,结果存入9字节RAM。 |
| 读暂存器 | BEH | 读9字节RAM的内容 |
| 写暂存器 | 4EH | 发出向内部RAM的3、4字节写上、下限温度数据命令,后面紧跟着传送两字节数据 |
| 复制暂存器 | 48H | 将RAM中第3、4字节的内容复制到EEPROM中 |
| 重调E2PROM | B8H | 将EEPROM内容恢复到RAM中的3、4字节 |
| 读供电方式 | B4H | 读DS18B20的供电模式,寄生供电时DS18B20发送“0”,外接电源供电时DS18B20发送“1”。 |
4、通过单线总线端口访问DS18B20过程
(1)初始化
类似于I2C的寻址,1-Wire总线开始也需要检测这条总线上是否存在DS18B20这个器件。如果存在,总线会根据时序要求返回一个低电平;如果不存在,则不返回,即总线保持高电平。该过程称为检测存在脉冲。
获取存在脉冲有两个作用:①检测是否存在DS18B20 ②通过这个过程通知DS18B20做准备,单片机要对它进行操作。
检测存在脉冲的时序图如下:
整个过程描述如下:①单片机拉低这个引脚,持续480~960us (以持续500us为例) ②单片机释放总线,即拉高电平。 ③15 ~60us后,如果DS18B20这个器件存在,就会主动拉低这个引脚,返回一个低脉冲(为了确保读到这个脉冲,选择延时60us,但不能超过75us)④持续60 ~240us后,DS18B20释放总线,I0端口被上拉电阻拉高。
对应的程序如下:
//软件延时函数,延时时间为(t*10)us
void DelayX10us(u8 t)
{
do{
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
} while(--t);
}
bit Init_18b20()
{
bit initflag;
EA = 0;
DQ = 0; //读写之前都要将该引脚拉低
DelayX10us(50); //延时500us
DQ = 1;
DelayX10us(6); //延时60us
initflag = DQ; //读取存在脉冲,0存在,1不存在
while(!DQ); //等待存在脉冲结束,即DQ = 1
EA = 1; //打开使能总中断
return initflag;
}
注:需要说明的是,DS18B20对时序的要求非常严格,所以在开始对某一位操作前要先关闭中断,防止中途受到干扰。但是位与位之间的间隔是可以无穷大的,完全可以在完成一位的操作之后,去干别的事情,结束之后再回来操作下一位。
(2)ROM操作指令
先只学习一条总线上只接一个器件的情况,此时只需要直接跳过ROM,不进行ROM检测。用到的语句如下:
Write18b20(0xcc);//跳过ROM操作
(3)RAM操作指令
常用到的两条如下:
Write18b20(0x44);//启动一次温度转换
Write18b20(0xbe);//发送读指令
(4)DS18b20的位写时序
DS18b20的位写入时序:

过程描述如下:在给DS18b20写数据之前,单片机要先把引脚拉低,持续一段时间(程序中是两个_nop_),而后DS18b20会在60秒之内读完这位数据。然后释放总线(拉高引脚)
代码如下:
//向DS18B20写入一个字节,dat为待写入字节
void Write18b20(u8 dat)
{
u8 i;
EA = 0;
for(i=0;i<8;i++)
{
DQ = 0;
_nop_(); //产生2us低电平脉冲
_nop_();
DQ = dat & 0x01; //先读取的是低位
DelayX10us(6);
dat>>=1; //次低位移到最低位,等待读取
DQ = 1;
}
EA = 1;
}
(5)DS18b20的位读时序
DS18b20的位读时序图如下:

过程描述如下:在读取DS18B20数据之前,单片机首先要拉低这个引脚,并且至少保持1us。而后释放这个引脚(拉高电平),尽快读取。从拉低这个引脚到读取不能超过15us。再延时60us,确保读取完毕。
代码如下:
//从DS18B20读取一个字节,返回值为读到的字节
u8 Read18b20()
{
u8 i,dat;
EA = 0;
for(i=0;i<8;i++)
{
DQ = 0;
_nop_();
_nop_();
DQ = 1;
_nop_();
_nop_();
dat >>= 1;
if(DQ == 1)
{
dat |= 0x80;//先读的是低位,依次右移
}
DelayX10us(6);
}
EA = 1;
return dat;
}
5、ds18b20.h + ds18b20.c
ds18b20.h
#ifndef __DS18B20_H
#define __DS18B20_H
#include "system.h"
sbit DQ = P1^4;
void DelayX10us(u8 t);
bit Init_18b20();
void Write18b20(u8 dat);
u8 Read18b20();
bit Start18b20();
u8 TempGet();
#endif
ds18b20.c
#include "ds18b20.h"
#include "intrins.h"
//软件延时函数,延时时间为(t*10)us
void DelayX10us(u8 t)
{
do{
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
}while(--t);
}
bit Init_18b20()
{
bit initflag;
EA = 1;
DQ = 0; //读写之前都要将该引脚拉低
DelayX10us(50); //延时500us
DQ = 1;
DelayX10us(6); //延时60us
initflag = DQ; //读取存在脉冲,0存在,1不存在
while(!DQ); //等待存在脉冲结束,即DQ = 1
EA = 1; //打开使能总中断
return initflag;
}
//向DS18B20写入一个字节,dat为待写入字节
void Write18b20(u8 dat)
{
u8 i;
EA = 0;
for(i=0;i<8;i++) //低位在前,逐位移除
{
DQ = 0;
_nop_(); //产生2us低电平脉冲
_nop_();
DQ = dat & 0x01; //先读取低位
DelayX10us(6);
dat>>=1;
DQ = 1;
}
EA = 1;
}
//从DS18B20读取一个字节,返回值为读到的字节
u8 Read18b20()
{
u8 i,dat;
EA = 0;
for(i=0;i<8;i++) //低位在前,诸位读取
{
DQ = 0;
_nop_();
_nop_();
DQ = 1;
_nop_();
_nop_();
dat >>= 1;
if(DQ == 1)
{
dat |= 0x80;//先读的是低位,依次右移
}
DelayX10us(6);
}
EA = 1;
return dat;
}
bit Start18b20()
{
bit ack;
ack = Init_18b20(); //执行总线复位,获取18b20的应答
if(ack == 0) //如果18B20应答正确,启动一次转换
{
Write18b20(0xcc); //跳过RAM操作
Write18b20(0x44); //启动一次温度转换
}
return ~ack; //ack == 0表示操作成功,返回值对其取反
}
u8 TempGet()
{
bit ack;
u8 LSB,MSB,temp;
ack = Init_18b20(); //执行总线复位,获取18b20的应答
if(ack == 0) //如果18B20应答正确,启动一次转换
{
Write18b20(0xcc); //跳过RAM操作
Write18b20(0xbe); //发送读命令
LSB = Read18b20();
MSB = Read18b20();
temp = (MSB<<4)|(LSB>>4);
}
return temp;
}
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐


所有评论(0)