DS18B20
DS18B20 介绍
DS18B20 是由 DALLAS 半导体公司推出的一种的“一线总线(单总线)”接口的温度传感器。
特点
- 适应电压范围更宽,电压范围:3.0~5.5V,在寄生电源方式下可由数据线供电。
- 一条口线实现处理器和DS18B20双向通讯。
- 可以组网多点测温,DS18B20 支持多点组网功能,多个DS18B20 可以并联在唯一的三线上,实现组网多点测温。
- DS18B20 在使用中不需要任何外围元件,全部传感元件及转换电路集成,在形如一只三极管的集成电路内。
- 温范围-55℃~+125℃,在-10~+85℃时精度为±0.5℃
- 可编程的分辨率为 9~12 位,对应的可分辨温度分别为 0.5℃、0.25℃、0.125℃ 和 0.0625℃,可实现高精度测温。
- 在 9 位分辨率时最多在 93.75ms 内把温度转换为数字,12 位分辨率时最多在 750ms 内把温度值转换为数字,速度更快。
- 测量结果直接输出数字温度信号,以"一根总线"串行传送给 CPU,同时可传送 CRC 校验码,具有极强的抗干扰纠错能力。
- 负压特性:电源极性接反时,芯片不会因发热而烧毁,但不能正常工作。
元器件结构
外部结构
共三根线,地线,信号线,电源线。
内部结构
ROM 中的 64 位序列号是出厂前被光刻好的,作为该 DS18B20 的地址序列号,用于在多个DS18B20中做区分。
高速缓存
用于存储温度转换后的二进制数。
配置寄存器
用于配置采样的精度。
TM为1表示测试模式,为0表示工作模式,出厂时默认为0。
R1和R0两位用于设置分辨率,可以分别设置为9位,10位,11位,12位。
假设精度为10位就是0-1023。
温度寄存器
温度寄存器处于高速缓存存储器内,用于记录采集的温度。
由低字节和高字节组成。高字节前5位为S,若S为0,则表明温度≥0,若S为1,则表明温度<0;
大于等于零,正数的源码和补码都一样,直接使用即可。
小于零,则需要将其他数值位取反再加1,再使用。
设精度为12位,也就是范围为0-4095,会将传感器测量范围归一化到0-4095区间。对应的精度为0.0625℃。
若采集得到的温度为0000 0101 0101 0000,转换后面11位为十进制就是1360,转换成实际的温度就是1360x0.0625=85,也就是85℃
若采集得到的温度为1111 1100 1001 0000,由于前5位位1,对后11位取反,得到011 0110 1111,转换为十进制就是879,879 x 0.0625=54.93度,也就是-54.93℃。
从存储寄存器读取到的数据就是以上数据。
工作模式
主机控制信号线,向DS18B20写入命令(字节表示),然后DS18B20完成指定动作,数值放在高速缓存寄存器中,然后主机控制信号线,从高速缓存读取数据。
初始化时序
主机设置信号线为低电平0,保持至少480us,产生复位脉冲。(此期间DS18B20使用while等待,检测主机将信号线设置为0,继续下一步准备回复,等待主机释放总线即可。)
主机设置信号线为高电平1,释放总线,等到DS18B20应答。
DS18B20在回复存在脉冲,设置信号线位低电平0,保持60us-240us。(此期间主机使用while等待,检测DS18B20将信号线设置为0。)
DS18B20将信号线设置为高电平1,延时200us,表示回复完毕。(此期间主机收到存在脉冲,使用while等待DS18B20释放信号线。)
保持信号一定时间的目的是为了另一端使用while循环等待期间信号时能检测到。
写时序
写的目的是主机将命令写入DS18B20,让其完成指定动作,写必须一位一位的写完一个字节。
写0步骤:设置信号线为低电平0,并保持60us,设置信号线为高电平1,延时2us。
写1步骤:设置信号线为高电平0,并保持2us,设置信号线为高电平1,延时60us。
写0和写1都要设置为低电平,只不过写0低电平保持时间长,写1高电平保持时间长。
代码如下
void ds18b20_write_byte(u8 dat) //往ds18b20写一个字节,用于写指令,如写启动转换指令或者跳过查询指令
{
u8 i=0;
u8 temp=0;
for(i=0;i<8;i++)//循环8次,每次写一位,且先写低位再写高位
{
temp=dat&0x01;//选择低位准备写入,与00000001做与运算,只得到最低位置结果。
dat>>=1;//将次高位移到低位
if(temp) //写1,如果当前低位为1
{
DS18B20_PORT=0; //拉低电平0,
_nop_();_nop_(); //延迟2us,
DS18B20_PORT=1; //拉高电平
delay_10us(6); //延迟60us
}
else //写0,如果当前低位为0
{
DS18B20_PORT=0; //拉低电平0,
delay_10us(6); //延迟60us
DS18B20_PORT=1; //拉高电平
_nop_();_nop_(); //延迟2us,
}
}
}
读时序
读也只能一位一位的读取。目的是从温度寄存器中读取二进制位的数值。
读一个数步骤
- 主机将信号线设置为低电平0。
- 等待两个指令周期,约2us。
- 主机将信号线设置为高电平1。
- 等待两个指令周期,约2us。
- 读取信号线的电平。
- 延时50us。
主机将信号线发送一个上升沿,则表明从机可以将数值设置到信号线上了。
代码
u8 ds18b20_read_bit(void)//读一位
{
u8 dat=0;
DS18B20_PORT=0; //主机拉低总线电平
_nop_();_nop_(); //延迟2us,主机转变为输入模式,nop表示延时一个指令周期,也就是12个时钟周期,等于1us
DS18B20_PORT=1; //拉高总线电平
_nop_();_nop_(); //等待从机设置总线电平 该段时间不能过长,必须在15us内读取数据
if(DS18B20_PORT)dat=1;//读取当前总线电平
else dat=0;
delay_10us(5); //延时50us
return dat;
}
u8 ds18b20_read_byte(void)
{
u8 i=0;
u8 dat=0;
u8 temp=0;
for(i=0;i<8;i++)//循环8次,每次读取一位,且先读低位再读高位
{
temp=ds18b20_read_bit();
dat=(temp<<7)|(dat>>1);//temp只有0和1,将最低位移动到最高位。
}
//读取方法,将temp放到最高位,dat左移一位后,最高位为0,与temp或运算,最高位由temp决定。
//temp 10000000 dat 00000000->0000000 -> 1000 0000
//temp 10000000 dat 10000000->0100000 -> 1100 0000
//temo 00000000 dat 11000000->0110000 -> 0110 0000
return dat;
}
整个工作流程
复位→发 SKIP ROM 命令(0XCC)→发开始转换命令(0X44)→延时→复位→发送 SKIP ROM 命令(0XCC)→发读存储器命令(0XBE)→连续读出两个字节数据(即温度)→结束
0xcc是跳过ROM查询,因为只有单个ds18b20传感器,不需要区分ds18b20,所以使用0xcc跳过查询命令,直接下一步转换。
0x44是转换命令,命令DS18B20将温度转换到高速缓存中。
0xBE是读暂存器的命令,读取9个字节的暂存器。
数码管实时显示温度代码
ds18b20.h文件
#ifndef _ds18b20_H
#define _ds18b20_H
#include "public.h"
sbit DS18B20_PORT=P3^7;
u8 ds18b20_init(void);
float ds18b20_read_temperture(void);
#endif
ds18b20.c文件
#include"ds18b20.h"
#include"intrins.h"
void ds18b20_reset(void){ //主机产生复位脉冲,进入接收模式。
DS18B20_PORT=0; //拉低DQ
delay_us(55); //保持750us 产生复位脉冲(480us~960us)
DS18B20_PORT=1; //释放 上拉
delay_10us(2); //延时20us 要求时延范围(15us~60us)
}
u8 ds18b20_check(void)//主机等待从机回复,返回0表示成功,返回1表示失败
//主机进入接收模式后检查。 从机必须在200us内回复低电平。
{
u8 time_temp=0;
while(DS18B20_PORT&&time_temp<20) //主机等待从机回复0, 从机感受到复位脉冲后,需要回复存在脉冲,低电平持续时间60us-240us。
{
time_temp++;
delay_10us(1);
}
if(time_temp>=20)return 1; //如果超时则强制返回1
else time_temp=0;
while((!DS18B20_PORT)&&time_temp<20) //主机从机的存在脉冲,等待从机拉高电平,从机也必须在200us内拉高电平。
{
time_temp++;
delay_10us(1);
}
if(time_temp>=20)return 1; //如果超时则强制返回1
return 0;
}
u8 ds18b20_read_bit(void)//读一位
{
u8 dat=0;
DS18B20_PORT=0; //主机拉低总线电平
_nop_();_nop_(); //延迟2us,主机转变为输入模式,nop表示延时一个指令周期,也就是12个时钟周期,等于1us
DS18B20_PORT=1; //拉高总线电平
_nop_();_nop_(); //等待从机设置总线电平 该段时间不能过长,必须在15us内读取数据
if(DS18B20_PORT)dat=1;//读取当前总线电平
else dat=0;
delay_10us(5); //延时50us
return dat;
}
u8 ds18b20_read_byte(void)
{
u8 i=0;
u8 dat=0;
u8 temp=0;
for(i=0;i<8;i++)//循环8次,每次读取一位,且先读低位再读高位
{
temp=ds18b20_read_bit();
dat=(temp<<7)|(dat>>1);//temp只有0和1,将最低位移动到最高位。
}
//读取方法,将temp放到最高位,dat左移一位后,最高位为0,与temp或运算,最高位由temp决定。
//temp 10000000 dat 00000000->0000000 -> 1000 0000
//temp 10000000 dat 10000000->0100000 -> 1100 0000
//temo 00000000 dat 11000000->0110000 -> 0110 0000
return dat;
}
void ds18b20_write_byte(u8 dat) //往ds18b20写一个字节,用于写指令,如写启动转换指令或者跳过查询指令
{
u8 i=0;
u8 temp=0;
for(i=0;i<8;i++)//循环8次,每次写一位,且先写低位再写高位
{
temp=dat&0x01;//选择低位准备写入,与00000001做与运算,只得到最低位置结果。
dat>>=1;//将次高位移到低位
if(temp) //写1,如果当前低位为1
{
DS18B20_PORT=0; //拉低电平,
_nop_();_nop_(); //延迟2us,
DS18B20_PORT=1; //拉高电平
delay_10us(6); //延迟60us
}
else //写0,如果当前低位为0
{
DS18B20_PORT=0; //拉低电平,
delay_10us(6); //延迟60us
DS18B20_PORT=1; //拉高电平
_nop_();_nop_(); //延迟2us,
}
}
}
void ds18b20_start(void)
{
ds18b20_reset();//主机发送复位脉冲
ds18b20_check();//主机等待DS18B20的存在脉冲。
ds18b20_write_byte(0xcc);//SKIP ROM
ds18b20_write_byte(0x44);//温度转换命令0x44,之后温度值以二字节补码形式存放在高速暂存存储器的第0和第1个字节。
}
u8 ds18b20_init(void)
{
ds18b20_reset();
return ds18b20_check();
}
float ds18b20_read_temperture(void)
{
float temp;
u8 dath=0;
u8 datl=0;
u16 value=0;
ds18b20_start();//开始转换
ds18b20_reset();//复位
ds18b20_check();
ds18b20_write_byte(0xcc);//SKIP ROM ,因为只有单个ds18b20传感器,不需要区分ds18b20,所以使用0xcc跳过查询命令,直接下一步转换。
ds18b20_write_byte(0xbe);//读存储器
datl=ds18b20_read_byte();//低字节
dath=ds18b20_read_byte();//高字节
value=(dath<<8)+datl;//合并为16位数据
if((value&0xf800)==0xf800)//判断符号位,负温度
{
value=(~value)+1; //数据取反再加1
temp=value*(-0.0625);//乘以精度
}
else //正温度
{
temp=value*0.0625;
}
return temp;
}
smg.h文件
#ifndef _smg_H
#define _smg_H
#include "public.h"
#define SMG_A_DP_PORT P0 //使用宏定义数码管段码口
//定义数码管位选信号控制脚
sbit LSA=P2^2;
sbit LSB=P2^3;
sbit LSC=P2^4;
extern u8 gsmg_code[17];
void smg_display(u8 dat[],u8 pos);
#endif
smg.c文件
#include "smg.h"
//共阴极数码管显示0~F的段码数据
u8 gsmg_code[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
/*******************************************************************************
* 函 数 名 : smg_display
* 函数功能 : 动态数码管显示
* 输 入 : dat:要显示的数据
pos:从左开始第几个位置开始显示,范围1-8
* 输 出 : 无
*******************************************************************************/
void smg_display(u8 dat[],u8 pos)
{
u8 i=0;
u8 pos_temp=pos-1;
for(i=pos_temp;i<8;i++)
{
switch(i)//位选
{
case 0: LSC=1;LSB=1;LSA=1;break;
case 1: LSC=1;LSB=1;LSA=0;break;
case 2: LSC=1;LSB=0;LSA=1;break;
case 3: LSC=1;LSB=0;LSA=0;break;
case 4: LSC=0;LSB=1;LSA=1;break;
case 5: LSC=0;LSB=1;LSA=0;break;
case 6: LSC=0;LSB=0;LSA=1;break;
case 7: LSC=0;LSB=0;LSA=0;break;
}
SMG_A_DP_PORT=dat[i-pos_temp];//传送段选数据
delay_10us(100);//延时一段时间,等待显示稳定
SMG_A_DP_PORT=0x00;//消音
}
}
public.h文件
#include"public.h"
void delay_10us(u16 ten_us){
while(ten_us--);
}
void delay_ms(u16 ms){
u16 i,j;
for(i=ms;i>0;i--)
for(j=110;j>0;j--);
}
main.c文件
/**************************************************************************************
深圳市普中科技有限公司(PRECHIN 普中)
技术支持:www.prechin.net
PRECHIN
普中
实验名称:DS18B20温度传感器实验
接线说明:
实验现象:下载程序后,插上DS18B20温度传感器,数码管显示检测的温度值
注意事项:注意温度传感器的方向,在接口处我们已经用丝印画了一个凸起,
所以只需要将温度传感器对应插入即可
***************************************************************************************/
#include "public.h"
#include "smg.h"
#include "ds18b20.h"
/*******************************************************************************
* 函 数 名 : main
* 函数功能 : 主函数
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void main()
{
u8 i=0;
int temp_value;
u8 temp_buf[5];
ds18b20_init();//初始化DS18B20
while(1)
{
i++;
if(i%50==0)//间隔一段时间读取温度值,间隔时间要大于温度传感器转换温度时间
temp_value=ds18b20_read_temperture()*10;//保留温度值小数后一位
if(temp_value<0)//负温度
{
temp_value=-temp_value;
temp_buf[0]=0x40;//显示负号
}
else
temp_buf[0]=0x00;//不显示
temp_buf[1]=gsmg_code[temp_value/1000];//百位
temp_buf[2]=gsmg_code[temp_value%1000/100];//十位
temp_buf[3]=gsmg_code[temp_value%1000%100/10]|0x80;//个位+小数点
temp_buf[4]=gsmg_code[temp_value%1000%100%10];//小数点后一位
smg_display(temp_buf,4);
}
}
本文来自博客园,作者:Laplace蒜子,转载请注明原文链接:https://www.cnblogs.com/RedNoseBo/p/17832537.html