一、DS18B20
DS18B20是Dallas半导体公司的一款数字温度传感器芯片;
DS18B20是一款支持 1-wire总线接口的温度传感器;
DS18B20能测量的温度范围-55℃--125℃,精度是±0.5℃;
DS18B20可以将分辨率设定为9到12位;
DS18B20的工作电压范围3--5.5V
二、DS18B20与STC89C51的连接
单片机的P4.1引脚用来接DS18B20的数据引脚
sbit DS = P4^1; 三、DS18B20的内部构成
以下是友台半导体的DS18B0结构图,内部有9个模块
1、电源与寄生电源
2、ROM:存DS18B20 的系列号,也就是那个64位的编码,
3、存储器控制逻辑
4、Scratchpad(高速暂存器)
高速暂存器就是用来存各种数据的,一共可以存9个字节的数据,存的就是下面5、6、7、8、9这几个模块的数据。
5、温度传感器
Byte0和Byte1存的是温度,就是传感器已经换算好的数字温度,Byte0是温度的低8位,Byte1是温度的高8位,上电默认的温度是0550 = 0000 0101 0101 0000 =1360, 因为默认的分辨率是12位(0.0625℃),所以开机默认的温度是1360*0.0625 ==85℃。
DS18B20采用16位补码的形式来存储温度数据,单位是摄氏度。两个字节一共是8*2=16位,温度的换算表格如下所示:
高字节的5个S是符号位,S=1表示温度为正,S=0表示温度为负;
12位分辨率,最后一位是1/16==0.0625,所以最小的温度分辨率是0.0625℃;
11位分辨率,最后一位是1/8==0.125,所以最小的温度分辨率是0.125℃;
10位分辨率,最后一位是1/4==0.25,所以最小分辨率是0.25℃;
9位分辨率,最后一位是1/2==0.5,所以最小分辨率是0.5℃;
正温度的读取
因为存的温度是补码,正数的原码和补码是一样的,直接读数
比如+85摄氏度:0000 0101 0101 0000 = 1360; 1360*0.0625 =85
比如+25.0625摄氏度:0000 0001 1001 0001 = 401;401*0.0625=25.0625
负温度的读取
因为存的温度是补码,负数的补码转化为原码步骤:先取反,再+1
比如-55摄氏度的补码是:1111 1100 1001 0000(高5位是符号位);
所以真实的补码为100 1001 0000;
补码取反之后,再+1;011 0110 1111+1=011 0111 0000 = 880;
880*0.0625 == 55
几个温度所对应的补码
6、报警触发寄存器
Byte2对应的是TH,也就是高温报警值,用户自己设置
Byte3对应的是TL,也就是低温报警值,用户自己设置
7、配置寄存器
Byte4对应的计时配置寄存器的值;
配置寄存器是用来配置温度的分辨率,可以把温度的分辨率配置为9bit、10bit、11bit、12bit,分别对应的实际温度分辨率为0.5℃、0.25℃、0.125℃、0.0625摄氏度。默认是12位分辨率(0.0625摄氏度)
配置寄存器的内容是这样的
温度的精度和配置
8、用户Byte
有两个Byte,也是留给用户自己用的,不同厂家的设计可能不一样
9、CRC
CRC发生器产生校验码,存在Byte8,是64位ROM中的前56位编码的校验码,由CRC
四、DS18B20的处理序列,也就是工作步骤
1、初始化DS18B20
初始化就是先把总线拉高;
然后检查总线上是否存在DS18B20 ,如果有的话,总线会返回一个低电平脉冲,如果没有DS18B20,那总线一直就是高电平,似乎有点像IIC通讯的应答信号。
2、执行ROM指令:
这个ROM指令就是查询DS18B20 的64位序列号,相当于设备地址,在多个DS18B20总线连接,需要区分每个DS18B20设备。如果是单个的18B20就不需要查询这个序列号了。你不查询也要发一条指令0xCC,表示跳过ROM指令。
ROM指令有哪些
3、执行DS18B20功能指令
4、DS18B20 初始化的C语言实现
void DS18b20_Init(void)
{bit flag=1;while (flag){while (flag){DQ = 1;delay(1);DQ = 0; //MCU拉低总线480us以上delay(50); // 大约550usDQ = 1; // MCU释放总线,等待DS18B20的应答delay(6); // 等待66us左右才开始读DS18B20的应答flag = DQ; // MCU读总线,只有读到低电平,才表示成功,跳出循环}delay(45); //延时500usflag = ~DQ;//初始化成功了还是要释放总线,把总线拉高}DQ=1;
} 5、DS18B20数据读取
DS18B0的数据线只有1根,在这一根线上完成读和写,那就需要的时序更加严格,资源少,命就得硬。
DS18B20的读写时序
MCU 往DS18B20写一个BIT的“0”:
MCU把总线拉低,拉低时间要持续到60--120us之间,然后释放总线(释放总线,上拉电阻就把总线拉高了)。
MCU往DS18B20写一个BIT的“1”:
MCU把总线拉低,,拉低时间要大于1us,然后在15us内拉高总线。
MCU从DS18B20中读一个BIT的:
MCU先把总线拉低,DS18B20检测到总线被拉低1us后,边开始往外送数据,如果送出的是“0”,DS18B20就把总线拉低,一直到读周期结束;如果送出的是“1”,就释放总线,让上拉电阻 把总线拉高。
读一个BIT的周期至少是60us,
往DS18B20中写一个字节的数据
/*** 往DS18B20总写一个字节的数据* 因为DS18B20只能一个BIT一个BIT的写,所以要写一个字节就需要循环8次
*/
void write_byte(unsigned char Dat)
{unsigned char i;for (i=0; i<8; i++){DQ = 1;//MCU把总线拉高_nop_(); //延时1us,STC89C52单片机,晶振12MHz,一个nop就是1usDQ = 0; //MCU把总线拉低nops(); //拉低持续4usDQ = Dat & 0x01; //最低位移出delay(6); //不管是0还是1,都持续66us左右Dat >>= 1; //右移一位}DQ = 1;delay(1);
} 从DS18B20 中读一个字节
/*** 从DS18B20中读一个字节的数据* 因为DS18B20只能一个BIT一个BIT的读,所以要读一个字节就需要循环8次
*/
unsigned char read_byte(void)
{unsigned char i, Dat=0;for (i=0; i<8; i++){DQ=1; //MCU把总线拉高,还没开始读_nop_(); //Dat >>= 1;//每次循环数据右移1位DQ = 0; //MCU把总线拉低,nops(); //拉低尺寸4us左右DQ = 1; //MCU再把总线拉高,也相当于释放总线,总线的电平高低由DS18B20来控制了nops(); //再等待4us左右就开始读DS18B20吐出的数据if (DQ)Dat|=0x80; //一个BIT一个BIT的读delay(6); //延时66us就差不多了}DQ=1; //读完成之后把总线拉高,因为空闲的时候总线hi高电平return(Dat);//返回一个字节的数据
} 读温度
/*** 读出温度
*/
void read_temp(void)
{DS18b20_Init(); // 器件初始化write_byte(0xCC); // 发Skip ROM命令write_byte(0x44); // 启动温度转换DS18b20_reset();//器件再初始化write_byte(0xCC); // 发Skip ROM命令write_byte(0xBE); // 发读命令temp_data[0]=read_byte(); //读温度低8位temp_data[1]=read_byte(); //读温度高8位
}