DS18B20 是由 DALLAS 半导体公司推出的一种的“一线总线”接口的温度传感器。与传
统的热敏电阻等测温元件相比,它是一种新型的体积小、适用电压宽、与微处理器接口简单的
数字化温度传感器。一线总线结构具有简洁且经济的特点,可使用户轻松地组建传感器网络,
从而为测量系统的构建引入全新概念,测量温度范围为-55~+125℃ ,精度为±0.5℃。现场温
度直接以“一线总线”的数字方式传输,大大提高了系统的抗干扰性。它能直接读出被测温度,
并且可根据实际要求通过简单的编程实现 9~l2 位的数字值读数方式。它工作在 3—5. 5 V 的电
压范围,采用多种封装形式,从而使系统设计灵活、方便,设定分辨率及用户设定的报警温度
存储在 EEPROM 中,掉电后依然保存
其内部结构如下所示
DS18B20的通讯方式是单总线的,一般而言,我们遇到的封装都是如下
其中DQ就是主要的通讯线路,对DS的读取和写入都需要主机来控制DQ线路的DQ高低电平的时间来确定,具体如下
一般而言,DQ线需要接一个上拉电阻,所以,才写操作的最后一步都需要将总线拉高
向DS写0需要总线拉低至少60US最多120US就算完成,也就是说,1-->0(持续60-120us)-->1 写入了0
像DS写入1需要总线拉低最少1us最多15US,然后总线拉高,拉高时间至少15us,一般40us以上即可 1->0(1-15us,推荐5us)-->1(持续15us以上,推荐40us)
由此可见,DS的总线采样实在总线拉低之后的15us开始的
读取DS分别为读取1和读取0,但是这两者时序是统一的
首先总线拉低至少1us,最多15us,还是选择2us,然后释放总线(也就是说进入输入模式),等待15us以上的事件,然后采样,高电平为1低电平为0
1-->0(持续2us,最多15us)-->等待15us以上60us以下-->采样总线电平,得到1或者0,记得采样完成之后切换到输出模式将总线拉高便于下一次使用
DS18B20的命令
DS1820有三个主要数字部件:1)64位激光ROM,2)温度传感器,3)非易失性温度报警触发器TH和TL
启动温度转换的命令是0X44,读取命令是0XBE
所以一般而言,对于DS的驱动包含以下几步
复位-->发 SKIP ROM 命令(0XCC)-->发开始转换命令(0X44)-->延时-->复
位-->发送 SKIP ROM 命令(0XCC)-->发读存储器命令(0XBE)-->连续读出两个字节数据(即
温度)-->结束
我们在读取的时候只读取两个字节的原因在于DS的存储器布局
前两个就是我们需要的温度,当然也可以读取全部的,扩展驱动达到其他目的
以下是驱动代码,STM32驱动代码中使用了位段操作
#ifndef __Ds18b20H #define __Ds18b20H #include "ioremap.h" #include "delay.h" #include "uart.h" //IO方向设置 #define Ds18b20IO_IN() {GPIOG->CRH&=0XFFFF0FFF;GPIOG->CRH|=8<<12;} #define Ds18b20IO_OUT() {GPIOG->CRH&=0XFFFF0FFF;GPIOG->CRH|=3<<12;} ////IO操作函数 #define Ds18b20DQ_OUT PGout(11) //数据端口 PG11 #define Ds18b20DQ_IN PGin(11) //数据端口 PG11 u8 Ds18b20Init(void); //初始化DS18B20 short Ds18b20GetTemp(void); //获取温度 void Ds18b20Start(void); //开始温度转换 void Ds18b20WriteByte(u8 dat);//写入一个字节 u8 Ds18b20ReadByte(void); //读出一个字节 u8 Ds18b20ReadBit(void); //读出一个位 u8 Ds18b20Check(void); //检测是否存在DS18B20 void Ds18b20Rst(void); //复位DS18B20 void Ds18b20Show(void); #endif
#include "ds18b20.h" //复位DS18B20 void Ds18b20Rst(void) { Ds18b20IO_OUT(); //SET PA0 OUTPUT Ds18b20DQ_OUT=0; //拉低DQ DelayUs(750); //拉低750us Ds18b20DQ_OUT=1; //DQ=1 DelayUs(15); //15US } //等待DS18B20的回应 //返回1:未检测到DS18B20的存在 //返回0:存在 u8 Ds18b20Check(void) { u8 retry=0; Ds18b20IO_IN();//SET PA0 INPUT while (Ds18b20DQ_IN&&retry<200) { retry++; DelayUs(1); }; if(retry>=200)return 1; else retry=0; while (!Ds18b20DQ_IN&&retry<240) { retry++; DelayUs(1); }; if(retry>=240)return 1; return 0; } //从DS18B20读取一个位 //返回值:1/0 u8 Ds18b20ReadBit(void) // read one bit { u8 data; Ds18b20IO_OUT();//SET PA0 OUTPUT Ds18b20DQ_OUT=0; DelayUs(2); Ds18b20DQ_OUT=1; Ds18b20IO_IN();//SET PA0 INPUT DelayUs(12); if(Ds18b20DQ_IN)data=1; else data=0; DelayUs(50); return data; } //从DS18B20读取一个字节 //返回值:读到的数据 u8 Ds18b20ReadByte(void) // read one byte { u8 i,j,dat; dat=0; for (i=1;i<=8;i++) { j=Ds18b20ReadBit(); dat=(j<<7)|(dat>>1); } return dat; } //写一个字节到DS18B20 //dat:要写入的字节 void Ds18b20WriteByte(u8 dat) { u8 j; u8 testb; Ds18b20IO_OUT();//SET PA0 OUTPUT; for (j=1;j<=8;j++) { testb=dat&0x01; dat=dat>>1; if (testb) { Ds18b20DQ_OUT=0;// Write 1 DelayUs(2); Ds18b20DQ_OUT=1; DelayUs(60); } else { Ds18b20DQ_OUT=0;// Write 0 DelayUs(60); Ds18b20DQ_OUT=1; DelayUs(2); } } } //开始温度转换 void Ds18b20Start(void)// ds1820 start convert { Ds18b20Rst(); Ds18b20Check(); Ds18b20WriteByte(0xcc);// skip rom Ds18b20WriteByte(0x44);// convert } //初始化DS18B20的IO口 DQ 同时检测DS的存在 //返回1:不存在 //返回0:存在 u8 Ds18b20Init(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); //输出1 Ds18b20Rst(); return Ds18b20Check(); } //从ds18b20得到温度值 //精度:0.1C //返回值:温度值 (-550~1250) short Ds18b20GetTemp(void) { u8 temp; u8 TL,TH; short tem; Ds18b20Start (); // ds1820 start convert Ds18b20Rst(); Ds18b20Check(); Ds18b20WriteByte(0xcc);// skip rom Ds18b20WriteByte(0xbe);// convert TL=Ds18b20ReadByte(); // LSB TH=Ds18b20ReadByte(); // MSB if(TH>7) { TH=~TH; TL=~TL; temp=0;//温度为负 }else temp=1;//温度为正 tem=TH; //获得高八位 tem<<=8; tem+=TL;//获得底八位 tem=(short)((float)tem*0.625);//转换 if(temp)return tem; //返回温度值 else return -tem; } void Ds18b20Show(void) { short t = 0; t = Ds18b20GetTemp(); printf("ds18b20 temp is %d ",t); }