应用最广泛的测温传感器
简介
DS18B20通过1-Wire总线进行通信,根据定义,该总线仅需要一条数据线(和地线)即可与中央微处理器进行通信。它的工作温度范围为 -55°C 至 +125°C,在–10°C 至 +85°C 的范围内精确至 0.5°C。 此外,DS18B20可以直接从数据线获取电源(“寄生电源”),而无需外部电源。
每个DS18B20都有一个唯一的64位串行代码,它允许多个DS18B20在同一条1线总线上工作。 因此,使用一个微处理器控制分布在大面积上的许多DS18B20就很简单,DS18B20也由此成为温控系统中最常用的传感器。
温度测量工作原理
- 使用DS18B20时可以将温度传感器的分辨率配置为9、10、11或12位,分别对应于0.5C,0.25C,0.125C和0.0625C的增量;
- 要启动温度测量和a-D转换,主机必须发出Convert T[44h]命令;
- 转换后,产生的热数据存储在草稿行内存中的2字节温度寄存器中,DS18B20返回到空闲状态。
寄存器格式
- DS18B20输出温度数据以摄氏度校准,温度数据以16位符号扩展2的补码形式存储在温度寄存器中;
- 符号位表示温度是正还是负:正数S=0,负数S=1;
- 如果DS18B20配置为12位分辨率,则温度寄存器中的所有位都将包含有效数据;
- 分辨率位为1,代表加上该位的一个增量。
LS Byte:
bit 7 | bit 6 | bit 5 | bit 4 | bit 3 | bit 2 | bit 1 | bit 0 |
---|---|---|---|---|---|---|---|
2^3 | 2^2 | 2^1 | 2^0 | 2^-1 | 2^-2 | 2^-3 | 2^-4 |
MS Byte
bit 15 | bit 14 | bit 13 | bit 12 | bit 11 | bit 10 | bit 9 | bit 8 |
---|---|---|---|---|---|---|---|
S | S | S | S | S | 2^6 | 2^5 | 2^4 |
温度/DATA关系表(示例)
温度 | 数字信号输出(二进制) | 数字信号输出(十六进制) | 计算过程 |
---|---|---|---|
+125°C | 0000 0111 1101 0000 | 07D0h | 2^0+2^2+2^3+2^4+2^5+2^6=125 |
+85°C | 0000 0101 0101 0000 | 0550h | 2^0+2^2+2^4+2^6=85 |
+25.0625°C | 0000 0001 1001 0001 | 0192h | 2^-4+2^0+2^3+2^4=25.0625 |
+10.125°C | 0000 0000 1010 0010 | 00A2h | 2^-3+2^1+2^3=10.125 |
+0.5°C | 0000 0000 0000 1000 | 0008h | 2^-1=0.5 |
0°C | 0000 0000 0000 0000 | 0000h | 0 |
-0.5°C | 1111 1111 1111 1000 | FFF8h | 2^-1=0.5 |
-10.125°C | 1111 1111 0101 1110 | FF5Eh | 2^-3+2^1+2^3=10.125 |
-25.0625°C | 1111 1110 0110 1111 | FE6Fh | 2^-4+2^0+2^3+2^4=25.0625 |
-55°C | 1111 1100 1001 0000 | FC90h | 2^0+2^2+2^3+2^4+2^5+2^6=125 |
寄存器指令
DS18B20的操作顺序为:
复位指令
ROM指令
DS18B20功能指令
常用ROM指令:
SKIP ROM [CCh]:主机可以使用该命令同时寻址总线上的所有设备,而无需发送任何ROM代码信息。
用法1:通过允许主机从机读取而不发送设备的64位ROM代码来节省时间(只有在总线上只有一个从设备时可用)
1 | ds_write_byte(bus,0xcc); |
用法2:主机可以通过发出Skip ROM命令和随后的Convert T [44h]命令,使总线上的所有DS18B20都同时执行温度转换
1 | ds_write_byte(bus,0xcc); |
常用功能指令:
CONVERT T [44h]:该命令启动一次温度转换。 转换后,产生的热数据被存储在暂存器的2字节温度寄存器中,DS18B20返回其低功耗空闲状态。
**WRITE SCRATCHPAD [4Eh]: **该命令允许主机将3个字节的数据写入DS18B20的暂存器。 第一个数据字节写入TH寄存器(暂存器的字节2),第二个字节写入TL寄存器(字节3),第三个字节写入配置寄存器(字节4)。
READ SCRATCHPAD [BEh] :该命令允许主机读取暂存器的内容。 数据传输从字节0的最低有效位开始,一直到暂存器,直到读取第9个字节(字节8 – CRC)
MSP430程序
<DS18B20.h>:
1 |
|
<DS18B20.c>:
引脚操作函数
1
2
3
4
5
6
7
8
9
10
11void set_ds_output(uint8 bus)
{
switch(bus)
{
case DS18B20_BUS_1:
P7DIR |= BIT2; //P7.3设置为输出
break;
default:
break;
}
}1
2
3
4
5
6
7
8
9
10
11void set_ds_input(uint8 bus)
{
switch(bus)
{
case DS18B20_BUS_1:
P7DIR &= ~BIT2; //P7.3设置为输入
break;
default:
break;
}
}1
2
3
4
5
6
7
8
9
10
11void set_ds_high(uint8 bus)
{
switch(bus)
{
case DS18B20_BUS_1:
P7OUT |= BIT2; //P7.2拉高
break;
default:
break;
}
}1
2
3
4
5
6
7
8
9
10
11void set_ds_low(uint8 bus)
{
switch(bus)
{
case DS18B20_BUS_1:
P7OUT &= ~BIT2; //P7.2拉低
break;
default:
break;
}
}1
2
3
4
5
6
7
8
9
10
11
12
13uint8 read_ds(uint8 bus)
{
uint8 data;
switch(bus)
{
case DS18B20_BUS_1:
data=(P7IN & BIT2)?1:0;
break;
default:
break;
}
return data;
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25void Reset_18b20(uint8 bus)
{
set_ds_output(bus);
set_ds_high(bus);
delay_us(1); //1us
set_ds_low(bus);
delay_us(550); //当总线停留在低电平超过480us,总线上所有器件都将被复位,这里
//延时约530us总线停留在低电平超过480μs,总线上的所有器件都将被复位。
set_ds_high(bus); //产生复位脉冲后,微处理器释放总线,让总线处于空闲状态,原因查18b20中文资料
delay_us(45);; //释放总线后,以便从机18b20通过拉低总线来指示其是否在线
//存在检测高电平时间:15~60us,所以延时44us,进行1-wire presence //detect(单线存在检测)
set_ds_input(bus);
if(read_ds(bus)==0)
ds18b20_flag=1; //detect 18b20 success
else
ds18b20_flag=0; //detect 18b20 fail
delay_us(28); //存在检测低电平时间:60~240us,所以延时约140us
set_ds_output(bus);
set_ds_high(bus); //再次拉高总线,让总线处于空闲状态
delay_us(50);
}
读写操作函数
读/写时间隙:DS1820 的数据读写是通过时间隙处理位和命令字来确认信息交换。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15uint8 ds_read_bit(uint8 bus) //读一位
{
uint8 dat;
set_ds_output(bus);
set_ds_low(bus); //单片机(微处理器)将总线拉低
delay_us(1); //读时隙起始于微处理器将总线拉低至少1us
set_ds_high(bus); //拉低总线后接着释放总线,让从机18b20能够接管总线,输出有效数据
delay_us(1);
//小延时一下,读取18b20上的数据 ,因为从ds18b20上输出的数据
//在读"时间隙"下降沿出现15us内有效
set_ds_input(bus);
dat=read_ds(bus); //主机读从机18b20输出的数据,这些数据在读时隙的下降沿出现15us内有效
delay_us(77); //所有读"时间隙"必须60~120us,这里77us
return(dat); //返回有效数据
}1
2
3
4
5
6
7
8
9
10
11uint8 ds_read_byte(uint8 bus ) //读一字节
{
uint8 value,i,j;
value=0; //给初值
for(i=0;i<8;i++)
{
j=ds_read_bit(bus);
value=(j<<7)|(value>>1); //这一步的说明在一个word文档里面
}
return(value); //返回一个字节的数据
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17void ds_write_bit(uint8 bus,uint8 dat)
{
if(dat) //写 1
{
set_ds_low(bus);
delay_us(2);
//asm("NOP"); //看时序图,至少延时1us,才产生写"时间隙"
set_ds_high(bus); //写时间隙开始后的15μs内允许数据线拉到高电平
delay_us(70); //所有写时间隙必须最少持续60us
}
else //写 0
{
set_ds_low(bus);
delay_us(64); //主机要生成一个写0 时间隙,必须把数据线拉到低电平并保持至少60μs,这里64us
set_ds_high(bus);
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24void ds_write_byte(uint8 bus,uint8 dat) //写一个字节
{
uint8 i;
uint8 onebit; //一定不要忘了,onebit是一位
for(i=1;i<=8;i++)
{
onebit=dat&0x01;
dat=dat>>1;
if(onebit) //写 1
{
set_ds_low(bus);
delay_us(2);
//asm("NOP"); //看时序图,至少延时1us,才产生写"时间隙"
set_ds_high(bus); //写时间隙开始后的15μs内允许数据线拉到高电平
delay_us(70); //所有写时间隙必须最少持续60us
}
else //写 0
{
set_ds_low(bus);
delay_us(64); //主机要生成一个写0 时间隙,必须把数据线拉到低电平并保持至少60μs,这里64us
set_ds_high(bus);
}
}
}
温度功能函数
1
2
3
4
5
6
7
8
9void tem_change(uint8 bus)
{
Reset_18b20(bus);
delay_us(100); //约2ms
ds_write_byte(bus,0xcc);
//跳过ROM代码信息的发送
ds_write_byte(bus,0x44);
//使总线上所有DS18B20都同时执行温度转换
}获取温度函数,返回值为一个十进制的温度值,精度为0.0625
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35float get_temperature(uint8 bus)
{
uint8 a,b;
Reset_18b20(bus);
delay_us(150); //约2ms
ds_write_byte(bus,0xcc);
ds_write_byte(bus,0xbe);
//主机读取暂存器的信息,从字节0的最低有效位开始一直到暂存器直到读取第9个字节(8-0)
//只有在总线上只有DS18B20的时候,[BEh]指令才能跟随在[CCh]指令之后;否则冲突
//在这种情况下,可以允许主机从从机读取数据而不发送设备的64位ROM代码来节省时间
a=ds_read_byte(bus);
b=ds_read_byte(bus);
tempDS18B20=b;
tempDS18B20<<=8;
tempDS18B20=tempDS18B20|a;
biaozhi=0;
if((tempDS18B20&0x8000))
{
biaozhi=1;//设置温度正负的标志
tempDS18B20=(~tempDS18B20+1);
tempDS18B20&=0x07FF;
}
wendu=tempDS18B20*0.0625; //得到真实十进制温度值,因为DS18B20
//可以精确到0.0625度,所以读回数据的最低位代表的是0.0625度
// wendu=wendu*10.0+0.5; //放大十倍,这样做的目的将小数点后第一位
//也转换为可显示数字,同时进行一个四舍五入操作。
//tempDS18B20=(unsigned long int)(wendu*100+0.5);
if(biaozhi)
//tempDS18B20 |= 0x8000;
wendu*=(-1);
Reset_18b20(bus);
return wendu;
}