声明:此博客主要参考了原子的教程和该传感器的datasheet,其中程序主要来源于原子,在调试的过程中结合datasheet做了一部分修改。
实现读取的代码工程链接:
链接:工程示例代码
提取码:id0q
一、传感器介绍及其特点
DS18B20 是由 DALLAS 半导体公司推出的一种的“一线总线”接口的温度传感器。与传统的热敏电阻等测温元件相比,它是一种新型的体积小、适用电压宽、与微处理器接口简单的数字化温度传感器。一线总线结构具有简洁且经济的特点,可使用户轻松地组建传感器网络,从而为测量系统的构建引入全新概念。特点如下:
- 测量温度范围为-55 ~ +125℃ 。
- 在-10 ~ +85°C范围内, 精度为±0.5°C。
- 可程序设定 9~12 位的分辨率。
- 3.0 ~ 5.5V 的工作电压范围。
- 自带EEPROM,可用于存储设定分辨率及用户设定的报警温度。
- 转换得到一次数字输出需要750ms(Max)
- 数据线(DQ)也可以用来提供电源(寄生电源,实现方式见datasheet)
直接以“一线总线”的数字方式传输,大大提高了系统的抗干扰性。它能直接读出被测温度,并且可根据实际要求通过简单的编程实现 9 ~ l2 位的数字值读数方式。采用多种封装形式,从而使系统设计灵活、方便。
其ROM 中的 64 位序列号是出厂前被光记好的,它可以看作是该 DS18B20 的地址序列码,每DS18B20 的 64 位序列号均不相同。64 位 ROM 的排列是:前 8 位是产品家族码,接着 48 位是DS18B20 的序列号,最后 8 位是前面 56 位的循环冗余校验码(CRC=X8+X5+X4+1)。ROM 作用是使每一个 DS18B20 都各不相同,这样就可实现一根总线上挂接多个 DS18B20。
可以在总线上只挂载一个DS18B20时使用其的ROM指令来获取这64位的序列号。
一般的电路连接方式如下:
二、通信信号类型的介绍和对应代码的实现
所有的单总线器件要求采用严格的信号时序,以保证数据的完整性。
DS18B20 共有 6 种信号类型:复位脉冲、应答脉冲、写 0、写 1、读 0 和读 1。所有这些信号,除了应答脉冲以外,都由主机发出同步信号。并且发送所有的命令和数据都是字节的低位在前。
2.1、复位脉冲(单片机发送)
单总线上的所有通信都是以初始化序列开始,这里的初始化序列为复位脉冲。
主机输出低电平,保持低电平时间480 ~ 960us,以产生复位脉冲。接着主机释放总线,4.7K的上拉电阻将单总线拉高,并进入接收模式(Rx)。
代码实现
使用的是RT-thread的BSP开发,使用PIN设备框架来实现对IO的控制。
///* 引脚编号,通过查看设备驱动文件drv_gpio.c确定 */
#define DS18B20_DQ 11 /* PA11 */
//复位DS18B20
void DS18B20_Rst(void)
{
rt_pin_mode(DS18B20_DQ, PIN_MODE_OUTPUT);// 引脚为输出模式
rt_pin_write(DS18B20_DQ, PIN_LOW); //拉低DQ
rt_hw_us_delay(750); //拉低750us(480 ~ 960us)
rt_pin_mode(DS18B20_DQ, PIN_MODE_INPUT); //设置为输入,即可释放总线的占用
//进入接收模式,等待应答信号。
}
RT-thread实现微秒延时的方法:微秒延时。
2.2、 应答信号(DS18B20发送)
在接收到单片机发出的复位脉冲后(其实是检测到上升沿),等待15~60 us后,DS18B20拉低总线60~240 us,以产生应答脉冲。接收到此信号说明该通信线挂载有DS18B20。
代码实现
//等待DS18B20的回应
//返回1:未检测到DS18B20的存在 返回0:存在
//等待了30us, 从机回应为108us,正常。
uint8_t DS18B20_Check(void)
{
uint8_t retry=0;
//------------------等待时间----------------------------------
rt_hw_us_delay(15); //15 ~60us 等待
while (rt_pin_read(DS18B20_DQ)&&retry<100) //最多还等待100us
{
retry++;
rt_hw_us_delay(1);
};
if(retry>=100) return 1; //100us未响应,则判断未检测到
else retry=0;
//----------------------从机拉低时间开始----------------------
while (!rt_pin_read(DS18B20_DQ)&&retry<240)
{
retry++;
rt_hw_us_delay(1);
};
if(retry>=240) return 1; //最长拉低240us
return 0;
}
复位与应答的时间序列
2.3、写时序(单片机发送数据)
写时序包括写0时序和写1时序。所有写时序至少需要60us,且在2次独立的写时序之间至少需要1us的恢复时间,两种写时序均起始于主机拉低总线。利用输出低电平的时间长短来实现写1或0。
- 写1时序:主机输出低电平,延时2us,然后释放总线,延时60us。
- 写0时序:主机输出低电平,延时60us,然后释放总线,延时2us。
代码实现
//写一个字节到DS18B20
//dat:要写入的字节
void DS18B20_Write_Byte(uint8_t dat)
{
uint8_t j;
uint8_t testb;
rt_pin_mode(DS18B20_DQ, PIN_MODE_OUTPUT); // DQ引脚为输出模式
for (j=1;j<=8;j++)
{
testb=dat&0x01;
dat=dat>>1;
if (testb) //输出高
{
rt_pin_write(DS18B20_DQ, PIN_LOW); //拉低DQ,主机输出低电平
rt_hw_us_delay(2); //延时2us
rt_pin_write(DS18B20_DQ, PIN_HIGH); //主机输出高电平
rt_hw_us_delay(60); //延时60us
}
else //输出低
{
rt_pin_write(DS18B20_DQ, PIN_LOW); //拉低DQ,主机输出低电平
rt_hw_us_delay(60); //延时60us
rt_pin_write(DS18B20_DQ, PIN_HIGH); //主机输出高电平
rt_hw_us_delay(2); //延时2us
}
}
rt_pin_mode(DS18B20_DQ, PIN_MODE_INPUT); //设置为输入,释放总线
}
2.4、读时序(单片机读取数据)
单总线器件仅在主机发出读时序时,才向主机传输数据,所以,在主机发出读数据命令后,必须马上产生读时序,以便从机能够传输数据。
所有读时序至少需要60us,且在2次独立的读时序之间至少需要1us的恢复时间。每个读时序都由主机发起,至少拉低总线1us。主机在读时序期间必须释放总线,并且在时序起始后的15us之内采样总线状态。
典型的读时序过程为:
- 主机输出低电平,延时2us
- 然后主机转入输入模式,延时12us
- 然后读取单总线当前的电平,然后延时50us
代码实现
//从DS18B20读取一个位
//返回值:1/0
uint8_t DS18B20_Read_Bit(void) // read one bit
{
uint8_t data;
rt_pin_mode(DS18B20_DQ, PIN_MODE_OUTPUT); // DQ引脚为输出模式
rt_pin_write(DS18B20_DQ, PIN_LOW); //拉低DQ,主机输出低电平
rt_hw_us_delay(2); //延时2us
rt_pin_mode(DS18B20_DQ, PIN_MODE_INPUT); //设置为输入,释放总线
rt_hw_us_delay(1);//延时1us
if(rt_pin_read(DS18B20_DQ))
data=1;//读取总线数据
else
data=0;
rt_hw_us_delay(60); //延时60us(读一位至少60us)
return data;
}
//从DS18B20读取一个字节
//返回值:读到的数据
uint8_t DS18B20_Read_Byte(void) // read one byte
{
uint8_t i,j,dat;
dat=0;
for (i=1;i<=8;i++)
{
j=DS18B20_Read_Bit();
dat=(j<<7)|(dat>>1);
}
return dat;
}
读写时间序列(读写一个位作为一个周期,至少60us)
三、温度获取的代码实现
DS18B20的各个ROM命令:datasheet上有说明,或者DS18B20的ROM指令中文
DS18B20的典型温度读取过程为:
- MCU发送复位信号,发SKIP ROM命令(0XCC,匹配指令)。// 每次对设备发指令都需要这两步。
注: 该匹配命令只适合挂载一个设备的情况下,即不需要匹配DS18B20的64位的地址编码。 - 发开始转换命令(0X44),温度一次转换指令,DS18B20内部实现温度转换成数字量。
- 延时一段时间(12bit分辨率时需要750ms)。
- MCU发送复位信号,发送SKIP ROM命令(0XCC)。
- 发读存储器命令(0XBE),读取暂存器内容。
注:读取将从第1个字节开始,一直进行下去,直到第9(CRC)字节读完。如果不想读完所有字节,控制器可以在任何时间发出复位命令来中止读取。其中第0、1个字节分别为温度值的低位、高位。 - 连续读出两个字节数据(即温度)。
- 对得到的温度值进行转换。
转化后得到的12位数据(采用二进制补码的方式),采用如下方法进行温度换算。
- 1、二进制中的前面5位是符号位,如果测得的温度大于0, 这5位为0,只要将测到的数值乘于0.0625即可得到实际温度。
- 2、如果温度小于0,这5位为1,测到的数值需要取反加1再乘于0.0625即可得到实际温度。
温度代码实现
//从ds18b20得到温度值
//精度:0.5度
//返回值:温度值 (-550~1250)
int16_t DS18B20_Get_Temp(void)
{
uint8_t temp; //用来判断符号
uint8_t TL,TH;
uint16_t tem;
rt_base_t level;
level = rt_hw_interrupt_disable(); //API:进入临界区,退出前系统不会发生任务调度
// ds1820 start convert
DS18B20_Rst();
DS18B20_Check();
DS18B20_Write_Byte(0xcc); // skip rom
DS18B20_Write_Byte(0x44); // convert
rt_hw_interrupt_enable(level); //API:退出临界区
rt_thread_mdelay(800); //等待转换完成,至少750ms
level = rt_hw_interrupt_disable(); //API:进入临界区,退出前系统不会发生任务调度
DS18B20_Rst(); //复位
DS18B20_Check();
DS18B20_Write_Byte(0xcc); // skip rom
DS18B20_Write_Byte(0xbe); // 读取命令
TL=DS18B20_Read_Byte();
TH=DS18B20_Read_Byte();
rt_hw_interrupt_enable(level); //API:退出临界区
if(TH>7)
{
TH=~TH;
TL=~TL;
temp=0;//温度为负
}else temp=1;//温度为正
tem=TH; //获得高八位
tem<<=8;
tem+=TL;//获得底八位
tem=(float)tem*0.625;//转换
if(temp)
return tem; //返回温度值
else
return -tem;
}
四、RT-thread实现
其实很简单,就是创建了一个线程,然后在入口函数上调用温度获取函数,得到温度值。
/*
说明:ds18b20温度获取线程的入口函数
*/
void ds18b20_tid_entry(void *parameter)
{
int16_t dat;
while(1)
{
rt_thread_mdelay(1000); //1s读取一次
dat = DS18B20_Get_Temp();
rt_kprintf("temp:%d\n",dat); //读取温度数据并发送到串口。 温度扩大十倍
}
}
void ds18b20_init(void)
{
ds18b20_tid = rt_thread_create("ds18b20_thread", //线程名字
ds18b20_tid_entry, //线程入口函数
RT_NULL, //线程入口参数
THREAD_STACK_SIZE, //堆栈大小,
THREAD_PRIORITY, //线程优先级
THREAD_TIMESLICE); //时间片长度
/* 如果获得线程控制块,启动这个线程 */
if (ds18b20_tid != RT_NULL)
rt_thread_startup(ds18b20_tid);
}
效果如下:(得到的结果是扩大了十倍,由于目的仅仅是测试一下,就懒得美化结果了)
五、使用DS18B20注意事项
- 12bit分辨率的转换时间最大为750ms(别的分辨率看手册),需延时大于此值。
- The power on reset register value is +85°C
- TH, TL, and CONFIG必须同时连续被写(不能只写一个),
- CONFIG 控制分辨率,分辨率越高,转换时间越长(默认12bit,时间为750ms)
- 初始化信号:每次通信必须初始化一次,
过程,主机一个复位脉冲触发,从机用一个脉冲响应,表示线上有ds18b20存在且准备操作。 - Read ROM [33h]
读序列号,要求总线上只有一个从机。 - Match ROM [55h]
匹配序列号 - Skip ROM [CCh]
无需序列号即可读,适用于只有一个从机的情况。 - Write Scratchpad [4Eh]
写TH、TL和CONFIG寄存器,三个必须一起写。 - Convert T [44h]
温度开始转换命令,发送此命令,需要转换时间(12bit 750ms) - 写时序
一位至少60us,且每个写周期至少有1us恢复时间。
ds18b20在检测到DQ下降沿后15~60us内采集该线信号,若为高,则为1,若为低,则为0. - 读时序
从主机将DQ线从高拉低开始,保持最低1us,然后释放改为输入模式,也是从这个下降沿开始的15us,从机输出的电平就是有效值(我们要读的高或者低)。之后从机会释放总线 - the sum of T INIT , T RC(上升时间) , and T SAMPLE must be less than 15 µs(读一位的时间),尽量留给采样最多的时间。