DS18B20 数字温度传感器的使用和基于RT-thread操作系统的实现

声明:此博客主要参考了原子的教程和该传感器的datasheet,其中程序主要来源于原子,在调试的过程中结合datasheet做了一部分修改。

实现读取的代码工程链接:
链接:工程示例代码
提取码:id0q

一、传感器介绍及其特点

DS18B20
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之内采样总线状态。

典型的读时序过程为:

  1. 主机输出低电平,延时2us
  2. 然后主机转入输入模式,延时12us
  3. 然后读取单总线当前的电平,然后延时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的典型温度读取过程为:

  1. MCU发送复位信号,发SKIP ROM命令(0XCC,匹配指令)。// 每次对设备发指令都需要这两步。
    注: 该匹配命令只适合挂载一个设备的情况下,即不需要匹配DS18B20的64位的地址编码。
  2. 发开始转换命令(0X44),温度一次转换指令,DS18B20内部实现温度转换成数字量。
  3. 延时一段时间(12bit分辨率时需要750ms)。
  4. MCU发送复位信号,发送SKIP ROM命令(0XCC)。
  5. 发读存储器命令(0XBE),读取暂存器内容。
    注:读取将从第1个字节开始,一直进行下去,直到第9(CRC)字节读完。如果不想读完所有字节,控制器可以在任何时间发出复位命令来中止读取。其中第0、1个字节分别为温度值的低位、高位。
  6. 连续读出两个字节数据(即温度)。
  7. 对得到的温度值进行转换。

转化后得到的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注意事项

  1. 12bit分辨率的转换时间最大为750ms(别的分辨率看手册),需延时大于此值。
  2. The power on reset register value is +85°C
  3. TH, TL, and CONFIG必须同时连续被写(不能只写一个),
  4. CONFIG 控制分辨率,分辨率越高,转换时间越长(默认12bit,时间为750ms)
  5. 初始化信号:每次通信必须初始化一次,
    过程,主机一个复位脉冲触发,从机用一个脉冲响应,表示线上有ds18b20存在且准备操作。
  6. Read ROM [33h]
    读序列号,要求总线上只有一个从机。
  7. Match ROM [55h]
    匹配序列号
  8. Skip ROM [CCh]
    无需序列号即可读,适用于只有一个从机的情况。
  9. Write Scratchpad [4Eh]
    写TH、TL和CONFIG寄存器,三个必须一起写。
  10. Convert T [44h]
    温度开始转换命令,发送此命令,需要转换时间(12bit 750ms)
  11. 写时序
    一位至少60us,且每个写周期至少有1us恢复时间。
    ds18b20在检测到DQ下降沿后15~60us内采集该线信号,若为高,则为1,若为低,则为0.
  12. 读时序
    从主机将DQ线从高拉低开始,保持最低1us,然后释放改为输入模式,也是从这个下降沿开始的15us,从机输出的电平就是有效值(我们要读的高或者低)。之后从机会释放总线
  13. the sum of T INIT , T RC(上升时间) , and T SAMPLE must be less than 15 µs(读一位的时间),尽量留给采样最多的时间。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值