本文记录了笔者通过对DS18B20温度传感器的学习,进一步学习1-Wire单总线通信协议的过程和学习总结。
DS18B20的封装
DS18B20只有两种封装,一是To-92,二是8-pin SOIC(150mil)。通常我们使用的多为To-92封装。
DS18B20的特性
根据官方文档,我摘取了几点我觉得重要的特性。
1、采用1-Wire通信协议,只需要一个引脚就可以通信。
2、可由数据线供电(寄生电源),供电范围为3.0V至5.5V。
3、测量温度从-55°C到125°C。华氏当量为-67°F至257°F。
4、在-10°C到85°C温度范围内,测量误差为±0.5°C。
5、温度计分辨率可从9位到12位编程。
6、在12位分辨率下,转换时间不超过750ms。
DS18B20的组成
DS18B20有四个主要的数据组件:
1、64位激光ROM
2、温度传感器
3、非易失性温度报警触发TH和TL
4、配置寄存器
温度与数据转换关系
DS18B20在执行温度转换后,其温度数据以16位带符号扩展的二进制补码格式存储在Scratchpad内存中。
在12位分辨率下,内部数据与温度转换关系如下图。
举个例子,如-25.0625°C。
其二进制码为1111 1110 0110 1111,因为该数据为补码,所以原数据按位取反后再加一得到原码为0000 0001 1001 0001。然后代入各位的权得到1x24+1x23+1x20+1x2-4x0.0625=25.0625。
1-Wire单总线协议程序
该协议由几种类型的信号组成:复位脉冲,存在脉冲,写0,写1,读0,读1。所有这些信号,除了存在脉冲,其他主机发起。
复位脉冲与存在脉冲统称初始化。主机对从机进行每个操作前,均需要初始化。
初始化的时序图如下。
1-Wire单总线通信协议的DQ线既作为输出线也作为输入线。
在通信过程中,要随时切换引脚工作模式,在STM32中可通过库函数很方便地改变模式。当总线作为输出时,需引脚设置为推挽输出模式,当总线作为输入时,需将引脚设置为上拉输入模式(相关程序参考自野火拓展模块DS18B20温度传感器实验例程)。
static void DS18B20_Rst(void)
{
DS18B20_Mode_Out_PP();//将DQ引脚设置为推挽输出模式
DS18B20_DQ_0;//拉低DQ引脚
Delay_us(750);//延时750us 480~960us
DS18B20_DQ_1;//拉高DQ引脚
Delay_us(15);//等待从机响应时间 15~60us
}
static uint8_t DS18B20_Presence(void)
{
uint8_t pulse_time = 0;
DS18B20_Mode_IPU();//将DQ引脚设置为上拉输入模式
while( DS18B20_DQ_IN() && pulse_time<100 )//等待低电平脉冲到来时间 15~60us
{
pulse_time++;
Delay_us(1);
}
if( pulse_time >=100 )//等待时间超时
return 1;
else
pulse_time = 0;
while( !DS18B20_DQ_IN() && pulse_time<240 )//低电平脉冲持续时间 60~240us
{
pulse_time++;
Delay_us(1);
}
if( pulse_time >=240 )//低电平持续时间超时
return 1;
else
return 0;
}
static uint8_t DS18B20_ReadBit(void)//读取一个bit
{
uint8_t dat;
DS18B20_Mode_Out_PP();//将DQ引脚设置为推挽输出模式
DS18B20_DQ_0;
Delay_us(10);//进行读数据操作前,需由主机产生不超过15us的低电平脉冲
DS18B20_Mode_IPU();//将DQ引脚设置为上拉输入模式
if( DS18B20_DQ_IN() == SET )
dat = 1;
else
dat = 0;
Delay_us(45);//整个读数据时间(60~120us)减去前面低电平脉冲时间
return dat;
}
static uint8_t DS18B20_ReadByte(void)//读取一个byte 低位先行
{
uint8_t i, j, dat = 0;
for(i=0; i<8; i++)
{
j = DS18B20_ReadBit();
dat = (dat) | (j<<i);
}
return dat;
}
static void DS18B20_WriteByte(uint8_t dat)//写入一个byte 低位先行
{
uint8_t i, testb;
DS18B20_Mode_Out_PP();//将DQ引脚设置为推挽输出模式
for( i=0; i<8; i++ )
{
testb = dat&0x01;
dat = dat>>1;//写1/0时间 高低电平持续时间 60~120us
if (testb)
{
DS18B20_DQ_0;
Delay_us(8);//写入1前 需要先拉低总线 1~15us
DS18B20_DQ_1;
Delay_us(70);
}
else
{
DS18B20_DQ_0;
Delay_us(70);
DS18B20_DQ_1;
Delay_us(2);//恢复到下一个周期 需重信拉高总线 1us~无穷
}
}
}
FUNCTIONS | VALUE |
---|---|
Read ROM | 0x33 |
Match ROM | 0x55 |
Skip ROM | 0xCC |
Search ROM | 0xF0 |
Alarm Search | 0xEC |
Write Scratchpad | 0x4E |
Read Scratchpad | 0xBE |
Copy Scratchpad | 0x48 |
Convert T | 0x44 |
Recall E2 | 0xB8 |
Read Power Supply | 0xB4 |
static void DS18B20_SkipRom ( void )
{
DS18B20_Rst();
DS18B20_Presence();
DS18B20_WriteByte(0XCC);//写入0xCC 执行skipROM操作
}
float DS18B20_GetTemp_SkipRom ( void )
{
uint8_t tpmsb, tplsb;
short s_tem;
float f_tem;
DS18B20_SkipRom ();
DS18B20_WriteByte(0X44);//转换命令
DS18B20_SkipRom ();
DS18B20_WriteByte(0XBE);//读取命令
tplsb = DS18B20_ReadByte();//低位先行
tpmsb = DS18B20_ReadByte();
s_tem = tpmsb<<8;
s_tem = s_tem | tplsb;
if( s_tem < 0 )
f_tem = (~s_tem+1) * (-0.0625);//负数二进制补码 取反加一后为原码
else
f_tem = s_tem * 0.0625;
return f_tem;
}
另外在存在多个从机的情况下,可以采用Match ROM的模式与不同从机进行通信。其64位激光ROM组成为:
在匹配ROM模式下,读取温度数据步骤如下。
static void DS18B20_MatchRom ( void )
{
DS18B20_Rst();
DS18B20_Presence();
DS18B20_WriteByte(0X55);//匹配ROM命令
}
float DS18B20_GetTemp_MatchRom ( uint8_t * ds18b20_id )
{
uint8_t tpmsb, tplsb, i;
short s_tem;
float f_tem;
DS18B20_WriteByte(0x33);//读ROM命令 低位先行
for ( i = 0; i < 8; i ++ )
ds18b20_id [ uc ] = DS18B20_ReadByte();
DS18B20_MatchRom ();//匹配ROM
for(i=0;i<8;i++)
DS18B20_WriteByte ( ds18b20_id [ i ] ); //写入ID数据
DS18B20_WriteByte(0X44);//转换命令
DS18B20_MatchRom ();//匹配ROM
for(i=0;i<8;i++)
DS18B20_WriteByte ( ds18b20_id [ i ] ); //写入ID数据
DS18B20_WriteByte(0XBE);
tplsb = DS18B20_ReadByte();
tpmsb = DS18B20_ReadByte();
s_tem = tpmsb<<8;
s_tem = s_tem | tplsb;
if( s_tem < 0 )
f_tem = (~s_tem+1) * (-0.0625);
else
f_tem = s_tem * 0.0625;
return f_tem;
}
DS18B20可通过改变便笺存储器中一个8bits大小的配置寄存器中对应两位二进制的值,进而改变分辨率大小。
便笺存储器的结构如下图。
配置寄存器的结构如下图。
R1R0值对应分辨率如下表。