DS18B20介绍
DS18B20是一种单总线数字温度传感器,测试温度范围-55℃-125℃,具有体积小,硬件开销低,抗干扰能力强,精度高的特点。单总线通信,意味着没有时钟线,只有一根通信线。单总线读写数据是靠控制起始时间和采样时间来完成,所以时序要求很严格,这也是DS18B20驱动编程的难点。
DS18B20引脚
三根线:
两个引脚一个是电源一个是低
典型原理图
64 位ROM。它的内容是64 位序列号,它可以被看作是该DS18B20 的地址序列码,其作用是使每个DS18B20 都各不相同,这样就可以实现一根总线上挂接多个DS18B20 的目的。这个就是传感器的身份证号码
64位的数居组成类型
暂存器结构
以上是内部9 个字节的暂存单元。
byte0~byte1 是温度存储器,用来存储转换好的温度。
Byte1是高位,Byte0是低位:图中例子是
字节2~3 是用户用来设置最高报警和最低报警值。这个可以用软件来实现。
设置门限值
字节4 是配置寄存器,用来配置转换精度,让它工作在9~12 位。
调节精度
字节5~7 保留位。【0xFF 0x0C 0x10】
字节8 CRC校验位。是64位ROM中的前56位编码的校验码。由CRC发生器产生。
温度数据的格式
温度寄存器由两个字节组成,分为低8位和高8位。一共16位。
其中,第0位到第3位,存储的是温度值的小数部分。
第4位到第10位存储的是温度值的整数部分。
第11位到第15位为符号位。全0表示是正温度,全1表示是负温度。
配置寄存器
存储器的第 4 位为配置寄存器,其组织见下图 。用户可以通过按表 3 所示设置 R0和 R1 位来设定 DS18B20 的精度。上电默认设置:R1=1,R0=1(12 位精度)。注意:精度和转换时间之间有直接的关系。暂存器的位 7 和位 0-4 被器件保留,禁止写入;在读回数据时,它们全部表现为逻辑 1
精度配置跟转换时间对应关系
精度值:
9-bit 0.5℃
10-bit 0.25℃
11-bit 0.125℃
12-bit 0.0625℃
温度数据对应关系
注意:如果温度是一个负温度,要将读到的数据减1再取反
因为负数是以补码的形式存储的
温度解析说明
当五个符号位S=0时,温度为正值,直接将后面的11位二进制转换为十进制,再乘以0.0625(12位分辨率),就可以得到温度值;
当五个符号位S=1时,温度为负值,先将后面的11位二进制补码变为原码(符号位不变,数值位取反后加1),再计算十进制值。再乘以0.0625(12位分辨率),就可以得到温度值;
例如:
+125℃的数字输出07D0(00000111 11010000)
转换成10进制是2000,对应摄氏度:0.0625x2000=125°C
-55℃的数字输出为 FC90。
首先取反,然后+1,转换成原码为:11111011 01101111
数值位转换成10进制是870,对应摄氏度:-0.0625x870=-55°C
————————————————
版权声明:本文为CSDN博主「Z小旋」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:/as480133937/article/details/112604303
unsigned int Templ,Temp2,Temperature; //Templ低八位,Temp2高八位unsigned char Minus Flag=0; //负温度标志位if(Tenp2&0xFC)//判断符号位是否为1{Minus Flag=l; //负温度标志位置1Temperature=((Temp2<<8)|Temp1); //高八位第八位进行整合Temperature=((Temperature)+1); //讲补码转换为原码,求反,补1Temperature*=0.0625;//求出十进制}else //温度为正值{Minus Flag=0; //负温度标志位置0Temperature =((Temp2<<8) |Temp1)*0.0625;}
单总线协议
初始化时序
初始化时序包括:主机发出的复位脉冲和从机发出的应答脉冲。主机通过拉低单总线480-960μs产生复位脉冲;然后由主机释放总线,并进入接收模式。主机释放总线时,会产生一由低电平跳变为高电平的上升沿,单总线器件检测到该上升沿后,延时15~60μs,接着单总线器件通过拉低总线60~240μsμ来产生应答脉冲。主机接收到从机的以应答脉冲后,说明有单总线器件在线,到此初始化完成。然后主机就可以开始对从机进行ROM命令和功能命令操作
位写入时序
写时序:当主机把数据线从逻辑高电平拉到逻辑低电平的时候,写时序开始。有两种写时序:写1的时序和写0时序。所有写时序必须最少持续60us,两个写周期间至少要有1us的恢复时间。
DQ引脚上的电平变低后,DS18B20在一个15us到60us的时间窗口内对DQ引脚采样。如果DQ引脚是高电平,就是写1,如果DQ引脚是低电平,就是写0。
主机要生成一个写1的时间序,必须把数据线拉到低电平然后释放,在写时序开始后的15us内允许数据线拉到高电平。
主机要生成一个写0的时间序,必须把数据线拉到低电平并保持60us。
总结
总线在千15us都是拉低,写0是的后半段是低电平,写1的后半段是高电平(释放总线)
位读取时序
读时隙由主机拉低总线电平至少1μs然后再释放总线,读取DS18B20发送过来的1或者0
DS18B20在检测到总线被拉低1微秒后,便开始送出数据,若是要送出0就把总线拉为低电平直到读周期结束。若要送出1则释放总线为高电平
注意:所有读时隙必须至少需要60us,且在两次独立的时隙之间至少需要1ps的恢复时间
同时注意:主机只有在发送读暂存器命令(0xBE)或读电源类型命令(0xB4)后,立即生成读时隙指令,DS18B20才能向主机传送数据。 也就是先发读取指令,再发送读时隙
最后一点: 写时序注意是先写命令的低字节,比如写入跳过ROM指令0xCC(11001100),写的顺序是“零、零、壹、壹、零、零、壹、壹”,
读时序时是先读低字节,在读高字节,也就是先读取高速暂存器的第0个字节(温度的低8位),在读取高速暂存器的第1个字节(温度的高8位) 我们正常使用DS18B20读取温度读取两个温度字节即可
参考历程1 51版本【未进行验证】
sbit DQ=P1^0;//定义DS18b20的管脚/*****延时子程序*****/void delay(unsigned int t){for(;t>0;t--);}/*****初始化DS18B20*****/unsigned char Init_DS18B20(void){unsigned char x=0;DQ = 1;//DQ复位delay(8); //稍做延时DQ = 0;//单片机将DQ拉低delay(80); //精确延时,大于480usDQ = 1;//拉高总线delay(8);x = DQ;//稍做延时后,如果x=0则初始化成功,x=1则初始化失败delay(4);return x;}/*****读一个字节*****/unsigned char ReadOneChar(void){unsigned char i=0;unsigned char dat = 0;for (i=8;i>0;i--){DQ = 0;// 给脉冲信号dat>>=1;DQ = 1;// 给脉冲信号if(DQ)dat|=0x80;delay(4);}return(dat);}/*****写一个字节*****/void WriteOneChar(unsigned char dat){unsigned char i=0;for (i=8; i>0; i--){DQ = 0;DQ = dat&0x01;delay(4);DQ = 1;dat>>=1;}delay(4);}/*****读取温度*****/int ReadTemperature(void){unsigned char a=0;unsigned char b=0;unsigned int t=0;t=Init_DS18B20();if(t) return Real_temp;WriteOneChar(0xCC); //跳过读序号列号的操作WriteOneChar(0x44); //启动温度转换t=Init_DS18B20();if(t) return Real_temp;WriteOneChar(0xCC); //跳过读序号列号的操作WriteOneChar(0xBE); //读取温度寄存器a=ReadOneChar();//读低8位b=ReadOneChar();//读高8位t=b;t<<=8;t=t|a;if(t<=0||t>0x900) return Real_temp;t=t*0.625+0.5;return(t);}
参考例程2 STM32代码
#include "ds18b20.h"#include "delay.h"//复位DS18B20void DS18B20_Rst(void) {DS18B20_IO_OUT(); //SET PG11 OUTPUTDS18B20_DQ_OUT=0; //拉低DQdelay_us(750); //拉低750usDS18B20_DQ_OUT=1; //DQ=1 delay_us(15);//15US}//等待DS18B20的回应//返回1:未检测到DS18B20的存在//返回0:存在u8 DS18B20_Check(void) {u8 retry=0;DS18B20_IO_IN();//SET PG11 INPUT while (DS18B20_DQ_IN&&retry<200){retry++;delay_us(1);}; if(retry>=200)return 1;else retry=0;while (!DS18B20_DQ_IN&&retry<240){retry++;delay_us(1);};if(retry>=240)return 1; return 0;}//从DS18B20读取一个位//返回值:1/0u8 DS18B20_Read_Bit(void) {u8 data;DS18B20_IO_OUT();//SET PG11 OUTPUTDS18B20_DQ_OUT=0; delay_us(2);DS18B20_DQ_OUT=1; DS18B20_IO_IN();//SET PG11 INPUTdelay_us(12);if(DS18B20_DQ_IN)data=1;else data=0; delay_us(50); return data;}//从DS18B20读取一个字节//返回值:读到的数据u8 DS18B20_Read_Byte(void){u8 i,j,dat;dat=0;for (i=1;i<=8;i++) {j=DS18B20_Read_Bit();dat=(j<<7)|(dat>>1);} return dat;}//写一个字节到DS18B20//dat:要写入的字节void DS18B20_Write_Byte(u8 dat){u8 j;u8 testb;DS18B20_IO_OUT();//SET PG11 OUTPUT;for (j=1;j<=8;j++) {testb=dat&0x01;dat=dat>>1;if (testb) {DS18B20_DQ_OUT=0;// Write 1delay_us(2); DS18B20_DQ_OUT=1;delay_us(60); }else {DS18B20_DQ_OUT=0;// Write 0delay_us(60); DS18B20_DQ_OUT=1;delay_us(2);}}}//开始温度转换void DS18B20_Start(void) {DS18B20_Rst(); DS18B20_Check(); DS18B20_Write_Byte(0xcc);// skip romDS18B20_Write_Byte(0x44);// convert} //初始化DS18B20的IO口 DQ 同时检测DS的存在//返回1:不存在//返回0:存在u8 DS18B20_Init(void){GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOG, ENABLE); //使能PORTG口时钟 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;//PORTG.11 推挽输出GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOG, &GPIO_InitStructure);GPIO_SetBits(GPIOG,GPIO_Pin_11); //输出1DS18B20_Rst();return DS18B20_Check();} //从ds18b20得到温度值//精度:0.1C//返回值:温度值 (-550~1250) short DS18B20_Get_Temp(void){u8 temp;u8 TL,TH;short tem;DS18B20_Start (); // ds1820 start convertDS18B20_Rst();DS18B20_Check(); DS18B20_Write_Byte(0xcc);// skip romDS18B20_Write_Byte(0xbe);// convert TL=DS18B20_Read_Byte(); // LSB TH=DS18B20_Read_Byte(); // MSB if(TH>7){TH=~TH;TL=~TL; temp=0;//温度为负 }else temp=1;//温度为正 tem=TH; //获得高八位tem<<=8; tem+=TL;//获得底八位tem=(float)tem*0.625;//转换if(temp)return tem; //返回温度值else return -tem; }#ifndef __DS18B20_H#define __DS18B20_H #include "sys.h" //IO方向设置#define DS18B20_IO_IN() {GPIOG->CRH&=0XFFFF0FFF;GPIOG->CRH|=8<<12;}#define DS18B20_IO_OUT() {GPIOG->CRH&=0XFFFF0FFF;GPIOG->CRH|=3<<12;}IO操作函数 #defineDS18B20_DQ_OUT PGout(11) //数据端口PA0 #defineDS18B20_DQ_IN PGin(11) //数据端口PA0 u8 DS18B20_Init(void);//初始化DS18B20short DS18B20_Get_Temp(void);//获取温度void DS18B20_Start(void);//开始温度转换void DS18B20_Write_Byte(u8 dat);//写入一个字节u8 DS18B20_Read_Byte(void);//读出一个字节u8 DS18B20_Read_Bit(void);//读出一个位u8 DS18B20_Check(void);//检测是否存在DS18B20void DS18B20_Rst(void);//复位DS18B20 #endif
开发板代码验证
开发板代码进行了稍微修改
#include "ds18b20.h"#include "systick.h"/*****************************************************@函数功能: 复位DS18B20@函数参数: None@函数返回值:None@注意事项: None*****************************************************/void DS18B20_Rst(void) {DS18B20_IO_OUT(); //SET PG11 OUTPUTDS18B20_DQ_OUT_L; //拉低DQsys_tick_us(750); //拉低750usDS18B20_DQ_OUT_H; //DQ=1 sys_tick_us(15);//15US}/*****************************************************@函数功能: 等待DS18B20的回应@函数参数: None@函数返回值:返回0:存在 返回1:未检测到DS18B20的存在@注意事项: None*****************************************************/u8 DS18B20_Check(void) {u8 retry=0;DS18B20_IO_IN();//SET PG11 INPUT while (DS18B20_DQ_IN&&retry<200){retry++;sys_tick_us(1);}; if(retry>=200)return 1;else retry=0;while (!DS18B20_DQ_IN&&retry<240){retry++;sys_tick_us(1);};if(retry>=240)return 1; return 0;}/*****************************************************@函数功能: 从DS18B20读取一个位@函数参数: None@函数返回值:返回值:1/0@注意事项: None*****************************************************/u8 DS18B20_Read_Bit(void) // read one bit{u8 data;DS18B20_IO_OUT();//SET PG11 OUTPUTDS18B20_DQ_OUT_L; sys_tick_us(2);DS18B20_DQ_OUT_H; DS18B20_IO_IN();//SET PG11 INPUTsys_tick_us(12);if(DS18B20_DQ_IN)data=1;else data=0; sys_tick_us(50); return data;}/*****************************************************@函数功能:从DS18B20读取一个字节@函数参数: None@函数返回值:读到的数据@注意事项: None*****************************************************/u8 DS18B20_Read_Byte(void) // read one byte{u8 i,j,dat;dat=0;for (i=1;i<=8;i++) {j=DS18B20_Read_Bit();dat=(j<<7)|(dat>>1);} return dat;}/*****************************************************@函数功能: 写一个字节到DS18B20@函数参数: dat 要写入的字节@函数返回值:None@注意事项: None*****************************************************/void DS18B20_Write_Byte(u8 dat){u8 j;u8 testb;DS18B20_IO_OUT();//SET PG11 OUTPUT;for (j=1;j<=8;j++) {testb=dat&0x01;dat=dat>>1;if (testb) {DS18B20_DQ_OUT_L;// Write 1sys_tick_us(2); DS18B20_DQ_OUT_H;sys_tick_us(60); }else {DS18B20_DQ_OUT_L;// Write 0sys_tick_us(60); DS18B20_DQ_OUT_H;sys_tick_us(2);}}}/*****************************************************@函数功能: 开始温度转换@函数参数: None@函数返回值:None@注意事项: None*****************************************************/void DS18B20_Start(void)// ds1820 start convert{DS18B20_Rst(); DS18B20_Check(); DS18B20_Write_Byte(0xcc);// skip romDS18B20_Write_Byte(0x44);// convert} /*****************************************************@函数功能: 初始化DS18B20的IO口 DQ 同时检测DS的存在@函数参数: None@函数返回值:返回1:不存在 返回0:存在 @注意事项: None*****************************************************/u8 DS18B20_Init(void){GPIO_InitTypeDef GPIO_InitStructure;RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG, ENABLE);//使能GPIOG时钟//GPIOG9GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//普通输出模式GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//50MHzGPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉GPIO_Init(GPIOG, &GPIO_InitStructure);//初始化DS18B20_Rst();return DS18B20_Check();} /*****************************************************@函数功能: 从ds18b20得到温度值@函数参数: None@函数返回值:温度值 (-550~1250)@注意事项: 精度:0.1C*****************************************************/short DS18B20_Get_Temp(void){u8 temp;u8 TL,TH;short tem;DS18B20_Start ();// ds1820 start convertDS18B20_Rst();DS18B20_Check(); DS18B20_Write_Byte(0xcc);// skip romDS18B20_Write_Byte(0xbe);// convert TL=DS18B20_Read_Byte(); // LSB TH=DS18B20_Read_Byte(); // MSB if(TH>7){TH=~TH;TL=~TL; temp=0;//温度为负 }else temp=1;//温度为正 tem=TH; //获得高八位tem<<=8; tem+=TL;//获得底八位tem=(double)tem*0.625;//转换if(temp)return tem; //返回温度值else return -tem; }