DS18B20是Dallas半导体公司的一款数字温度传感器芯片;
DS18B20是一款支持 1-wire总线接口的温度传感器;
DS18B20能测量的温度范围-55℃--125℃,精度是±0.5℃;
DS18B20可以将分辨率设定为9到12位;
DS18B20的工作电压范围3--5.5V
单片机的P4.1引脚用来接DS18B20的数据引脚
sbit DS = P4^1;
以下是友台半导体的DS18B0结构图,内部有9个模块
高速暂存器就是用来存各种数据的,一共可以存9个字节的数据,存的就是下面5、6、7、8、9这几个模块的数据。
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
几个温度所对应的补码
Byte2对应的是TH,也就是高温报警值,用户自己设置
Byte3对应的是TL,也就是低温报警值,用户自己设置
Byte4对应的计时配置寄存器的值;
配置寄存器是用来配置温度的分辨率,可以把温度的分辨率配置为9bit、10bit、11bit、12bit,分别对应的实际温度分辨率为0.5℃、0.25℃、0.125℃、0.0625摄氏度。默认是12位分辨率(0.0625摄氏度)
配置寄存器的内容是这样的
温度的精度和配置
有两个Byte,也是留给用户自己用的,不同厂家的设计可能不一样
CRC发生器产生校验码,存在Byte8,是64位ROM中的前56位编码的校验码,由CRC
初始化就是先把总线拉高;
然后检查总线上是否存在DS18B20 ,如果有的话,总线会返回一个低电平脉冲,如果没有DS18B20,那总线一直就是高电平,似乎有点像IIC通讯的应答信号。
这个ROM指令就是查询DS18B20 的64位序列号,相当于设备地址,在多个DS18B20总线连接,需要区分每个DS18B20设备。如果是单个的18B20就不需要查询这个序列号了。你不查询也要发一条指令0xCC,表示跳过ROM指令。
ROM指令有哪些
void DS18b20_Init(void)
{
bit flag=1;
while (flag)
{
while (flag)
{
DQ = 1;
delay(1);
DQ = 0; //MCU拉低总线480us以上
delay(50); // 大约550us
DQ = 1; // MCU释放总线,等待DS18B20的应答
delay(6); // 等待66us左右才开始读DS18B20的应答
flag = DQ; // MCU读总线,只有读到低电平,才表示成功,跳出循环
}
delay(45); //延时500us
flag = ~DQ;//初始化成功了还是要释放总线,把总线拉高
}
DQ=1;
}
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只能一个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就是1us
DQ = 0; //MCU把总线拉低
nops(); //拉低持续4us
DQ = Dat & 0x01; //最低位移出
delay(6); //不管是0还是1,都持续66us左右
Dat >>= 1; //右移一位
}
DQ = 1;
delay(1);
}
/**
* 从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位
}