精华内容
下载资源
问答
  • ds18b20温度传感器程序

    2012-07-03 22:37:10
    M0516上实现ds18b20温度传感器程序,测试已通过.
  • stm32f103读取DS18B20温度传感器程序
  • 分享一个基于STM32的DS18B20温度传感器程序,通过单总线方式读取,可以通过简单修改直接一直到51等平台。
  • DS18B20温度传感器程序

    2011-08-26 17:02:58
    温度传感器程序,利用DS18B20进行温度测量的程序,可以在此基础上惊醒功能扩充,有什么不懂的可以问我
  • DS18B20是单线接口数字温度传感器,具体特征如下图。 DS18B20包括寄生电源电路、64位ROM和单线接口电路、暂存器、EEPROM、8位CRC生成器和温度传感器等。寄生电源电路可以实现外部电源供电和单线寄生供电,64位ROM中...
  • 本人编写的51的ds18b20温度传感器程序,100%可用
  • easyarm1138 矩阵键盘 5110液晶 ds18b20温度传感器程序IAR 编译通过 板子测试 嘻嘻 条理清晰 并且配套字模软件 和位图显示功能 50分都值
  • 总线形式的访问多个DS18B20温度传感器程序程序已经测试过,试过7个DS18B20正常访问。要连接多个DS18B20要考虑其供电,最好单独供电。 用的AT89S52的单片机,程序注释里有硬件连接。
  • 用于温度传感器模块,库函数版本IAR,stvp程序例程
  • 简单粗暴的使用单从机模式下的DS18B20

            网上关于DS18B20的资料很多,但是光有程序,没有讲解,导致身边很多同学即使拿到源码也无从下手,故写此篇文章,一方面接收DB18B20,一方结合原理详细讲解源码的意义。

    器件原理:

    原理图:

            基本上所有的重要信息都在这张图上啦。很独特的一个点就是数据输入输出是共用一个管脚DQ的。
    对于唯一的数据口,需要一定的执行顺讯:

    执行序列


    如图,每一次操作都必须满足上述顺序,若是缺少或者混乱,器件将不会返回值。

        初始化:

           通过单总线的所有执行操作处理都从一个初始化序列开始。初始化序列包括一个从总线控制器发出的复位脉冲和其后由从机发出的存在脉冲,存在脉冲让总线控制器知道DB18B20存在且已经做好操作准备。

        ROM指令:

           这里采用单从机模式(只有一个DB18B20),只挑取几个比较重要的指令做以说明

          READ ROM[33h](读取ROM指令):

             只有在总线上存在单只DS18B20的时候才能使用这条命令。该命令允许总线控制器在不使用搜索ROM指令的情况下读取从机的64位片序列码。如果总线上有不止一只从机,当所有从机试图同时传送信号时就会发生数据冲突。

           SKIP ROM[CCh](忽略ROM指令) :     

              这条指令允许总线控制器不用提供64位ROM编码就是用功能指令。例如,总线控制器可以先发出一条忽略ROM指令,然后发出温度转换指令[44h],从而完成温度转换操作。注意:当只有一直从机在总线上时,无论如何,忽略ROM指令之后只能跟着发出一条读取暂存器指令[BEh]。

            功能指令:

            在总线控制器发给欲连接的DS18B20一条ROM指令后,跟着可以发送一条DS18B20功能指令。这些命令允许总线控制器读写DS18B20的暂存器,发起温度转换和识别电源模式。

           CONVERT T[44h](温度转换指令):

              这条命令用以启动一次温度转换。温度转换指令被执行,产生的温度转换结果数据以2个字节的形式被存储在告诉暂存器中,而后DS18B20保存等待状态。如果DS18B20以外部电源供电,总线控制器在发出该命令后跟着发出读时序,DS18B20如果处于转换中,将在总线上返回0,若温度转换完成,则返回1。

            READ SCRATCHPAD(读取暂存器指令): 

            这条命令读取暂存器的内容。读取将从字节0开始,一直进行下去,直到第9字节(字节8)读完,如果不想读完所有字节,控制器可以在任何时间发出复位命令来终止读取。


    时序:

            时序对于器件来说是很重要的,如果时序不对,器件就不能正常工作。 

          复位序列:复位和存在脉冲:

            和DS18B20间 的任何通讯都需要以初始化序列开始。一个复位脉冲跟着一个存在脉冲表明DS18B20已经准备好发送和接收数据。在初始化序列期间,总线控制器拉低总线并保持480us以发出(TX)一个复位脉冲,然后释放总线,进入接受状态(RX)。单总线由5K上拉电阻拉倒高电平。当DS18B20探测到I/O引脚上的上升沿后,等待15~60us,然后发出一个由60~240us低电平信号构成的存在脉冲。
            初始化时序见图:


          写时序:

            DS18B20的数据读写是通过时序处理位来确认信息交换的。有两种写时序:写1时序和写0时序。总线控制器通过写1时序写逻辑1到DS18B20,写0时序写逻辑0到DS18B20。所有写时序必须最少持续60us,包括两个写周期之间至少1us的恢复时间。当总线控制器把数据线从逻辑高电平拉到低电平的时候,写时序开始。
           总线控制器要生产一个写时序,必须把数据线拉到低电平然后释放,在写时序开始后的15us释放总线。当总线被释放的时候,5K的上拉电阻将拉高总线。总控制器要生成一个写0时序,必须把数据线拉到低电平并持续保持(至少60us)。
           总线控制器初始化写时序后,DA18B20在一个15us到60us的窗口内对I/O线采样。如果线上是高电平,就是写1。如果线上是低电平,就是写0。
           写时序如图:

          读时序:

           总线控制器发起读时序时,DS18B20仅被用来传输数据给控制器。因此,总线控制器在发出读暂存器指令[BEh]或读电源模式指令[B4H]后必须立刻开始读时序,DS18B20可以提供请求信息。除此之外,总线控制器在发出发送温度转换指令[44h]或召回EEPROM指令[B8h]之后读时序,详见DS18B20功能指令节。
          所有读时序必须最少60us,包括两个读周期间至少1us的恢复时间。当总线控制器把数据线从高电平拉到低电平时,读时序开始,数据线必须至少保持1us,然后总线被释放。在总线控制器发出读时序后,DS18B20通过拉高或拉低总线上来传输1或0.当传输逻辑0结束后,总线将被释放,通过上拉电阻回到上升沿状态。从DS18B20输出的数据在读时序的下降沿出现后15us内有效。因此,总线控制器在读时序开始后必须停止把I/O脚驱动为低电平15us,以读取I/O脚状态。
           读时序如图:

         操作举例:

              
            看了那么多的原理,肯定很多同学都忍不住要想知道如何具体操作的啦,下面就对源码详细解释。

    源码详解:

               无论给出什么样的源码,同学们都不可能直接使用,肯定要对其中关键的端口或者信号量加以修改,所以这里就给出核心代码,只要在理解原理的基础上适当的加以裁剪就可以使用。
    library IEEE;  
    use IEEE.STD_LOGIC_1164.ALL;  
    use IEEE.STD_LOGIC_ARITH.ALL;  
    use IEEE.STD_LOGIC_UNSIGNED.ALL;  
    
    entity ds18B20 is  
    port(clk : in std_logic;   ---50MHz 
         dq  : inout std_logic;  --DQ数据输出输入端
         rst: in std_logic; 
         
    LED : out std_logic;    --指示灯,标志程序进行到哪一步
    LED2 : out std_logic; 
    LED3 : out std_logic;  
        
    dataout1,dataout2,dataout3 : out std_logic_vector(6 downto 0 ));  --数据输出端
    end ds18B20;  
    
    architecture Behavioral of ds18B20 is  
    
    TYPE  STATE_TYPE  is (RESET,CMD_CC,WRITE_BYTE,WRITE_LOW,WRITE_HIGH,READ_BIT, 
    <span style="white-space:pre">				</span>CMD_44,CMD_BE,WAIT800MS,GET_TMP,WAIT4MS);   --状态机  
    signal STATE: STATE_TYPE:=RESET;   --初始化状态机
    signal clk_temp : std_logic:='0';  --监测总线上的数据
    signal clk1m : std_logic; --分频后得到的1M时钟 
    
    signal cp: std_logic;  -- 为时序而产生的1ms时钟
    begin  
    ----------分频程序,分到1MHz----------------
    ClkDivider:process (clk,clk_temp)  
    begin  
    if rising_edge(clk) then  
       if (count = 24) then  
          count <= 0;  
          clk_temp<= not clk_temp;  
       else  
          count <= count +1;  
       end if;  
    end if;   
       clk1m<=clk_temp;  
    end Process;  
    ----------为时序产生1ms时钟----------------
    
    process (clk1m)  
    variable n: integer range 0 to 12000:=0;
    begin             -----cp 1ms 
    if rising_edge(clk1m) then  
       n:=n+1;
       if (n>12000) then n:=0;  cp<=not cp;  end if;
        end if;  
    end Process;  
    
    STATE_TRANSITION:process(STATE,clk1m)    --重头戏,状态机开始啦
    begin 
    if rising_edge(clk1m) then  
      if(rst='0') then  
        STATE<=RESET; 
      else 
        case STATE is  
         when RESET=>  --如果处在复位状态
         LED2<='0'; 
         LED3<='0'; 
         if (cnt>=0 and cnt<500) then -- 500μs的复位低电平
           dq<='0';   --dq作为输出
           cnt<=cnt+1;  
           STATE<=RESET;  --在一定时序内保持复位状态  
         elsif (cnt>=500 and cnt<510) then 
           dq<='Z';  --高阻态再输入下一级电路的话,对下级电路无任何影响,和没接一样,高阻态可以应用在inout端口里面,这样在inout没有输出的时候就弄个高阻态,这样就其电平就可以由外面的输入信号决定了
           cnt<=cnt+1; 
           STATE<=RESET;  --拉高dq
         elsif (cnt>=510 and cnt<750) then   -- 240μs
           temp<=dq;  --dq作为输入(对于控制器来说是输入,对于DS18b20来说是输出,这个道理大家应该都明白吧)
           if(cnt=580) then 
             temp<=dq; 
             if(temp='1') then  --如果temp为1说明DS18B20存在(因为检测到了存在脉冲)
               LED<='0'; 
             else 
               LED<='1'; 
             end if; 
           end if; 
           cnt<=cnt+1;  
           STATE<=RESET;  
         elsif (cnt>=750) then  --初始化时序结束
           cnt<=0; --计数器清零 
           STATE<=CMD_CC;  --复位过程伴随着忽略rom指令“CC”
         end if;  
         when CMD_CC=>  --忽略rom指令“CC”
           LED2<='1'; 
           LED3<='0'; 
           write_temp<="11001100";  --将write_temp设为“11001100”
           STATE<=WRITE_BYTE; 
         when WRITE_BYTE=> 
           case WRITE_BYTE_CNT is  
             when 0 to 7=>  
               if (write_temp(WRITE_BYTE_CNT)='0') then  --判断当前write_temp第WRITE_BYTE_CNT上是否为'0'
                 STATE<=WRITE_LOW;  --如果当前write_temp第WRITE_BYTE_CNT上是'0',进入WRITE_LOW状态(即对DS18b20写低)
                 LED3<='1';      
               else 
                 STATE<=WRITE_HIGH;  --如果当前write_temp第WRITE_BYTE_CNT上是'1',进入WRITE_HIGH状态(即对DS18b20写高)
               end if;  
               WRITE_BYTE_CNT<=WRITE_BYTE_CNT+1;  --判断write_temp的下一位
             when 8=> 
               if (WRITE_BYTE_FLAG=0) then -- 第一次写0XCC完毕  
                 STATE<=CMD_44;  --开启温度转换指令
                 WRITE_BYTE_FLAG<=1;  
               elsif (WRITE_BYTE_FLAG=1) then --写0X44完毕 (写温度转换指令后没有读数据?) 
                 STATE<=RESET;  
                 WRITE_BYTE_FLAG<=2;  
               elsif (WRITE_BYTE_FLAG=2) then --第二次写0XCC完毕  
                 STATE<=CMD_BE;  
                 WRITE_BYTE_FLAG<=3;  
               elsif (WRITE_BYTE_FLAG=3) then --写0XBE完毕  
                 STATE<=GET_TMP;  
                 WRITE_BYTE_FLAG<=0;  
               end if;  
               WRITE_BYTE_CNT<=0; 
             when others=>STATE<=RESET; 
           end case;  
         when WRITE_LOW=>  进入写0时序,参看前面
           LED3<='1'; 
           case WRITE_LOW_CNT is  
             when 0=>  
               dq<='0';  
               if (cnt=70) then  --等待时序
                 cnt<=0;  
                 WRITE_LOW_CNT<=1;  
               else  
                 cnt<=cnt+1;  
               end if;  
             when 1=>  
               dq<='Z';  
               if (cnt=5) then  
                 cnt<=0;  
                 WRITE_LOW_CNT<=2;  
               else  
                 cnt<=cnt+1;  
               end if;  
             when 2=>  
               STATE<=WRITE_BYTE;  
               WRITE_LOW_CNT<=0;  
             when others=>WRITE_LOW_CNT<=0;  
           end case;  
         when WRITE_HIGH=>    --进入写1时序,参看前面
           case WRITE_HIGH_CNT is  
             when 0=>  
               dq<='0';  
               if (cnt=8) then  
                 cnt<=0;  
                 WRITE_HIGH_CNT<=1;  
               else  
                 cnt<=cnt+1;  
               end if;  
             when 1=>  
               dq<='Z';  
               if (cnt=72) then  
                 cnt<=0;  
                 WRITE_HIGH_CNT<=2;  
               else  
                 cnt<=cnt+1;  
               end if;  
             when 2=>  
               STATE<=WRITE_BYTE;  
               WRITE_HIGH_CNT<=0;  
            when others=>WRITE_HIGH_CNT<=0;  
          end case;  
         when CMD_44=>  
           write_temp<="01000100";  --写指令44h
           STATE<=WRITE_BYTE;  
         when CMD_BE=>  
           write_temp<="10111110";  --写指令BEh
           STATE<=WRITE_BYTE;
         when READ_BIT=>  
           case READ_BIT_CNT is  
             when 0=>  
               dq<='0';  --4μs的低电平
               if (cnt=4) then  
                 READ_BIT_CNT<=1;  
                 cnt<=0;  
               else  
                 cnt<=cnt+1;  
               end if;  
             when 1=>  
               dq<='Z'; --4μs的高电平 
               if (cnt=4) then 
                 READ_BIT_CNT<=2;  
                 cnt<=0;  
               else  
                 cnt<=cnt+1;  
               end if;  
             when 2=>  
               dq<='Z'; 
               TMP_BIT<=dq; --12μs读出数据 ,就是最后一次赋值的结果。
               if (cnt=4) then  
                 READ_BIT_CNT<=3;  
                 cnt<=0;  
               else  
                 cnt<=cnt+1;  
               end if;  
             when 3=>   
               dq<='Z';    --控制器拉高总线 
               if (cnt=50) then --读出数据后,等待50us 
                 cnt<=0;  
                 READ_BIT_CNT<=0;  
                 STATE<=GET_TMP;  
               else  
                 cnt<=cnt+1;  
               end if;  
             when others=>READ_BIT_CNT<=0;  
           end case;  
    
         when GET_TMP=>  --读数据
           case GET_TMP_CNT is  
             when 0 => 
               STATE<=READ_BIT; 
               GET_TMP_CNT<=GET_TMP_CNT+1; 
             when 1 to 12=>  
               STATE<=READ_BIT;  
               TMP(GET_TMP_CNT-1)<=TMP_BIT;--将读出的每一位数据按顺序存进 TMP(0 to 11)里面  
               GET_TMP_CNT<=GET_TMP_CNT+1; --存的是读出的0到11位,第十二位没有存 
             when 13=>  
               GET_TMP_CNT<=0;  
               STATE<=WAIT4MS;  
           end case;  
         when WAIT4MS=>  --等待4ms
           if (cnt>=4000) then  
             --STATE<=WAIT4MS; 
             STATE<=RESET;  
             cnt<=0;  
           else  
             cnt<=cnt+1;  
             STATE<=WAIT4MS;  
           end if;  
         when others=>STATE<=RESET; 
           LED<='0'; 
           LED2<='0';  
           LED3<='0';  
      end case;  
    
    end if; 
    end if; 
    end process;  
    
    end;
            其中LED只是为了方便观察程序到了哪一步,所有的LED都可以不要。

           这样就完成了,当然肯定还存在一些问题,希望大家不吝赐教。或者还有什么其他的疑惑,可以联系QQ:3463758699





    展开全文
  • ds18b20温度传感器程序,用1602显示,自己写好的,正在用的,精确0.1度
  • 在这里和大家分享一个DS18B20温度传感器的C语言程序,感兴趣的朋友可以看看。
  • 数字温度传感器DS18B20) 传感器参数

    数字温度传感器(DS18B20)

    DS18B20是一款常用的高精度的单总线数字温度测量芯片。具有体积小,硬件开销低,抗干扰能力强,精度高的特点。

    在这里插入图片描述

    传感器参数

    • 测温范围为-55℃到+125℃,在-10℃到+85℃范围内误差为±0.4°

    • 返回16位二进制温度数值

    • 主机和从机通信使用单总线,即使用单线进行数据的发送和接收

    • 在使用中不需要任何外围元件,独立芯片即可完成工作。

    • 掉电保护功能 DS18B20 内部含有 EEPROM ,通过配置寄存器可以设定数字转换精度和报警温度,在系统掉电以后,它仍可保存分辨率及报警温度的设定值。

    • 每个DS18B20都有独立唯一的64位-ID,此特性决定了它可以将任意多的DS18b20挂载到一根总线上,通过ROM搜索读取相应DS18B20的温度值

    • 宽电压供电,电压2.5V~5.5V

    • DS18B20返回的16位二进制数代表此刻探测的温度值,其高五位代表正负。如果高五位全部为1,则代表返回的温度值为负值。如果高五位全部为0,则代表返回的温度值为正值。后面的11位数据代表温度的绝对值,将其转换为十进制数值之后,再乘以0.0625即可获得此时的温度值。

    传感器引脚及原理图

    DS18B20传感器的引脚及封装图如下:

    在这里插入图片描述
    DS18B20一共有三个引脚,分别是:

    • GND:电源地线
    • DQ:数字信号输入/输出端。
    • VDD:外接供电电源输入端。

    单个DS18B20接线方式: VDD接到电源,DQ接单片机引脚,同时外加上拉电阻,GND接地

    注意这个上拉电阻是必须的,就是DQ引脚必须要一个上拉电阻

    DS18B20上拉电阻

    首先我们要知道什么是漏极开路

    首先看一下 场效应管(MOSFET)
    在这里插入图片描述
    场效应管 是电压控制型元器件,只要对栅极施加一定电压,DS就会导通。

    漏极开路:MOS管的栅极G和输入连接,源极S接公共端,漏极D悬空(开路)什么也没有接,直接输出 ,这时只能输出低电平和高阻态,不能输出高电平

    那么这个时候会出现三种情况:

    1. 图a为正常输出(内有上拉电阻):场效应管导通时,输出低电位输出低电位,截止时输出高电位。

    2. 图b为漏极开路输出,外接上拉电阻:场效应管导通时,驱动电流是从外部的VCC流经电阻通过MOSFET到GND,输出低电位,截止时输出高电位。

    3. 图c为漏极开路输出,无外接上拉电阻:场效应管导通时输出低电位,截止呈高阻态(断开)。
      在这里插入图片描述

    总结:

    开漏输出只能输出低电平,不能输出高电平。漏极开路输出高电平时必须在输出端与正电源(VCC)间外接一个上拉电阻。否则只能输出高阻态。

    DS18B20 是单线通信,即接收和发送都是这个通信脚进行的。 其接收数据时为高电阻输入,其发送数据时是开漏输出,本身不具有输出高电平的能力,即输出0时通过MOS下拉为低电平,而输出1时,则为高阻,需要外接上拉电阻将其拉为高电平。 因此,需要外接上拉电阻,否则无法输出1。



    外接上拉电阻阻值:

    DS18B20的工作电流约为1mA,VCC一般为5V,则电阻R=5V/1mA=5KΩ,

    所以正常选择4.7K电阻,或者相近的电阻值。



    DS18B20寄生电源

    DSl8B20的另一个特点是不需要再外部供电下即可工作。当总线高电平时能量由单线上拉电阻经过DQ引脚获得。高电平同时充电一个内部电容,当总线低电平时由此电容供应能量。这种供电方法被称为“寄生电源”。另外一种选择是DSl8B20由接在VDD的外部电源供电
    在这里插入图片描述

    DS18B20内部构成

    主要由以下3部分组成: 64 位ROM,高速暂存器,存储器

    64 位ROM存储独有的序列号

    ROM中的64位序列号是出厂前被光刻好的,它可以看作是该DS18B20的地址序列码,每个DS18B20的64位序列号均不相同。这样就可以实现一根总线上挂接多个DS18B20的目的。

    高速暂存器包含:

    • 温度传感器
    • 一个字节的温度上限和温度下限报警触发器(TH和TL)
    • 配置寄存器允许用户设定9位,10位,11位和12位的温度分辨率,分别对应着温度的分辨率为:0.5°C,0.25°C,0.125°C,0.0625°C,默认为12位分辨率,

    存储器:由一个高速的RAM和一个可擦除的EEPROM组成,EEPROM存储高温和低温触发器(TH和TL)以及配置寄存器的值,(就是存储低温和高温报警值以及温度分辨率)
    在这里插入图片描述

    DS18B20高速缓存器

    高速暂存器由9个字节组成

    • 字节0~1 是温度存储器,用来存储转换好的温度。第0个字节存储温度低8位,第一个字节存储温度高8位
    • 字节2~3 是用户用来设置最高报警和最低报警值(TH和TL)。
    • 字节4 是配置寄存器,用来配置转换精度,可以设置为9~12 位。
    • 字节5~7 保留位。芯片内部使用
    • 字节8 CRC校验位。是64位ROM中的前56位编码的校验码。由CRC发生器产生。
      在这里插入图片描述

    DS18B20温度读取与计算

    DS18B20采用16位补码的形式来存储温度数据温度是摄氏度。当温度转换命令发布后,经转换所得的温度值以二字节补码形式存放在高速暂存存储器的第0和第1个字节。

    高字节的五个S为符号位,温度为正值时S=1,温度为负值时S=0

    剩下的11位为温度数据位,对于12位分辨率,所有位全部有效,对于11位分辨率,位0(bit0)无定义,对于10位分辨率,位0和位1无定义,对于9位分辨率,位0,位1,和位2无定义

    在这里插入图片描述

    对应的温度计算:


    当五个符号位S=0时,温度为正值,直接将后面的11位二进制转换为十进制,再乘以0.0625(12位分辨率),就可以得到温度值;

    当五个符号位S=1时,温度为负值,先将后面的11位二进制补码变为原码(符号位不变,数值位取反后加1),再计算十进制值。再乘以0.0625(12位分辨率),就可以得到温度值;

    例如:

    +125℃的数字输出07D0(00000111 11010000)
     
    转换成10进制是2000,对应摄氏度:0.0625x2000=125°C

    -55℃的数字输出为 FC90。
      
    首先取反,然后+1,转换成原码为:11111011 01101111
    数值位转换成10进制是870,对应摄氏度:-0.0625x870=-55°C

    在这里插入图片描述
    代码:

    unsigned int Templ,Temp2,Temperature;  //Templ低八位,Temp2高八位
    unsigned char Minus Flag=0;  //负温度标志位
    
    if(Tenp2&0xFC//判断符号位是否为1
    {
    	Minus Flag=l; //负温度标志位置1
    	Temperature=((Temp2<<8)|Temp1); //高八位第八位进行整合
    	Temperature=((Temperature)+1); //讲补码转换为原码,求反,补1
    	Temperature*=0.0625;//求出十进制
    }
    else   //温度为正值
    {
    	Minus Flag=0;  //负温度标志位置0
    	Temperature =((Temp2<<8) |Temp1)*0.0625;
    }
    

    配置寄存器

    在配置寄存器中,我们可以通过R0和R1设置DS18B20的转换分辨率,DS18B20在上电后默认R0=1和R1=1(12分辨率),寄存器中的第7位和第0位到4位保留给设备内部使用。
    在这里插入图片描述

    单总线系统

    在每个DS18B20内部都有一个唯一的64位长的序列号,这个序列号值就存在DS18B20内部的ROM中。开始的8位是产品类型编码(DS18B20是10H),接着的48位是每个器件唯一的序号,最后的8位是CRC校验码。
    在这里插入图片描述

    一线总线系统使用单总线主控来控制一个或多个从机设备。每个DS18B20都有独立唯一的64位-ID,此特性决定了它可以将任意多的DS18b20挂载到一根总线上,通过ROM搜索读取相应DS18B20的温度值。

    DS18B20工作步骤

    DS18B20的工作步骤可以分为三步:

    1.初始化DS18B20
    2.执行ROM指令
    3.执行DS18B20功能指令

    其中第二步执行ROM指令,也就是访问每个DS18B20,搜索64位序列号,读取匹配的序列号值,然后匹配对应的DS18B20,如果我们仅仅使用单个DS18B20,可以直接跳过ROM指令。而跳过ROM指令的字节是0xCC。

    1.初始化DS18B20

    任何器件想要使用,首先就是需要初始化,对于DS18B20单总线设备,首先初始化单总线为高电平,然后总线开始也需要检测这条总线上是否存在DS18B20这个器件。如果这条总线上存在DS18B20,总线会根据时序要求返回一个低电平脉冲,如果不存在的话,也就不会返回脉冲,即总线保持为高电平。

    初始化具体时序步骤如下:

    • 1.单片机拉低总线至少480us,产生复位脉冲,然后释放总线(拉高电平)。
    • 2.这时DS8B20检测到请求之后,会拉低信号,大约60~240us表示应答。
    • 3.DS8B20拉低电平的60~240us之间,单片机读取总线的电平,如果是低电平,那么表示初始化成功
    • 4.DS18B20拉低电平60~240us之后,会释放总线。
      在这里插入图片描述
      代码如下:
    /*****初始化DS18B20*****/
    unsigned int Init_DS18B20(void)
    {
      unsigned int x=0;
      DQ = 1;      //DQ复位
      delay(4);    //稍做延时
      DQ = 0;      //单片机将DQ拉低
      delay(60);   //精确延时,大于480us
      DQ = 1;      //拉高总线
      delay(8);
      x = DQ;      //稍做延时后,如果x=0则初始化成功,x=1则初始化失败
      delay(4);
      return x;
    }
    

    2.写时序

    总线控制器通过控制单总线高低电平持续时间从而把逻辑1或0写DS18B20中。每次只传输1位数据

    单片机想要给DS18B20写入一个0时,需要将单片机引脚拉低,保持低电平时间要在60~120us之间,然后释放总线
    单片机想要给DS18B20写入一个1时,需要将单片机引脚拉低,拉低时间需要大于1us,然后在15us内拉高总线.

    在写时序起始后15μs到60μs期间,DS18B20处于采样单总线电平状态。如果在此期间总线为高电平,则向DS18B20写入1;如果总线为低电平,则向DSl8B20写入0。

    注意:2次写周期之间至少间隔1us

    在这里插入图片描述

    /*****写一个字节*****/
    void WriteOneChar(unsigned char dat)
    {
      unsigned char i=0;
      for (i=8; i>0; i--)
      {
        DQ = 0;
        DQ = dat&0x01;  //与1按位与运算,dat最低位为1时DQ总线为1,dat最低位为0时DQ总线为0
    	delay(4);
        DQ = 1;
        dat>>=1;
      }
      delay(4);
    }
    
    

    DS18B20写入的功能命令:

    ROM指令:

    采用多个DS18B20时,需要写ROM指令来控制总线上的某个DS18B20
    如果是单个DS18B20,直接写跳过ROM指令0xCC即可
    在这里插入图片描述

    RAM指令,DS18B20的一些功能指令

    常用的是:

    温度转换 0x44

    开启温度读取转换,读取好的温度会存储在高速暂存器的第0个和第一个字节中

    读取温度 0xBE
    读取高速暂存器存储的数据
    在这里插入图片描述

    读时序

    读时隙由主机拉低总线电平至少1μs然后再释放总线,读取DS18B20发送过来的1或者0

    DS18B20在检测到总线被拉低1微秒后,便开始送出数据,若是要送出0就把总线拉为低电平直到读周期结束。若要送出1则释放总线为高电平。

    在这里插入图片描述
    注意:所有读时隙必须至少需要60us,且在两次独立的时隙之间至少需要1ps的恢复时间

    同时注意:主机只有在发送读暂存器命令(0xBE)或读电源类型命令(0xB4)后,立即生成读时隙指令,DS18B20才能向主机传送数据。 也就是先发读取指令,再发送读时隙

    最后一点: 写时序注意是先写命令的低字节,比如写入跳过ROM指令0xCC(11001100),写的顺序是“零、零、壹、壹、零、零、壹、壹”,

    读时序时是先读低字节,在读高字节,也就是先读取高速暂存器的第0个字节(温度的低8位),在读取高速暂存器的第1个字节(温度的高8位) 我们正常使用DS18B20读取温度读取两个温度字节即可



    51例程

    sbit DQ=P1^0;	//定义DS18b20的管脚
    
    /*****延时子程序*****/
    void delay(unsigned int t)
    {
    	for(;t>0;t--);
    }
    
    
    /*****初始化DS18B20*****/
    unsigned char Init_DS18B20(void)
    {
      unsigned char x=0;
      DQ = 1;      //DQ复位
      delay(8);    //稍做延时
      DQ = 0;      //单片机将DQ拉低
      delay(80);   //精确延时,大于480us
      DQ = 1;      //拉高总线
      delay(8);
      x = DQ;      //稍做延时后,如果x=0则初始化成功,x=1则初始化失败
      delay(4);
      return x;
    }
    
    /*****读一个字节*****/
    unsigned char ReadOneChar(void)
    {
      unsigned char i=0;
      unsigned char dat = 0;
      for (i=8;i>0;i--)
      {
        DQ = 0;     // 给脉冲信号
        dat>>=1;
        DQ = 1;     // 给脉冲信号
        if(DQ)
        	dat|=0x80;
    	delay(4);
      }
      return(dat);
    }
    
    /*****写一个字节*****/
    void WriteOneChar(unsigned char dat)
    {
      unsigned char i=0;
      for (i=8; i>0; i--)
      {
        DQ = 0;
        DQ = dat&0x01;
    	delay(4);
        DQ = 1;
        dat>>=1;
      }
      delay(4);
    }
    
    /*****读取温度*****/
    int ReadTemperature(void)
    {
      	unsigned char a=0;
      	unsigned char b=0;
      	unsigned int t=0;
      	t=Init_DS18B20();
      	if(t) return Real_temp;
      	WriteOneChar(0xCC);  //跳过读序号列号的操作
      	WriteOneChar(0x44);  //启动温度转换
      	t=Init_DS18B20();
      	if(t) return Real_temp;
      	WriteOneChar(0xCC);  //跳过读序号列号的操作
      	WriteOneChar(0xBE);  //读取温度寄存器
      	a=ReadOneChar();     //读低8位
      	b=ReadOneChar();     //读高8位
      	t=b;
      	t<<=8;
      	t=t|a;
      	if(t<=0||t>0x900) 
    	return Real_temp;
    	t=t*0.625+0.5;
      	return(t);
    }
    
    

    STM32例程

    DS18B20.C

    #include "ds18b20.h"
    #include "delay.h"	
    
    //复位DS18B20
    void DS18B20_Rst(void)	   
    {                 
    	DS18B20_IO_OUT(); 	//SET PG11 OUTPUT
        DS18B20_DQ_OUT=0; 	//拉低DQ
        delay_us(750);    	//拉低750us
        DS18B20_DQ_OUT=1; 	//DQ=1 
    	delay_us(15);     	//15US
    }
    //等待DS18B20的回应
    //返回1:未检测到DS18B20的存在
    //返回0:存在
    u8 DS18B20_Check(void) 	   
    {   
    	u8 retry=0;
    	DS18B20_IO_IN();	//SET PG11 INPUT	 
        while (DS18B20_DQ_IN&&retry<200)
    	{
    		retry++;
    		delay_us(1);
    	};	 
    	if(retry>=200)return 1;
    	else retry=0;
        while (!DS18B20_DQ_IN&&retry<240)
    	{
    		retry++;
    		delay_us(1);
    	};
    	if(retry>=240)return 1;	    
    	return 0;
    }
    //从DS18B20读取一个位
    //返回值:1/0
    u8 DS18B20_Read_Bit(void) 	 
    {
        u8 data;
    	DS18B20_IO_OUT();	//SET PG11 OUTPUT
        DS18B20_DQ_OUT=0; 
    	delay_us(2);
        DS18B20_DQ_OUT=1; 
    	DS18B20_IO_IN();	//SET PG11 INPUT
    	delay_us(12);
    	if(DS18B20_DQ_IN)data=1;
        else data=0;	 
        delay_us(50);           
        return data;
    }
    //从DS18B20读取一个字节
    //返回值:读到的数据
    u8 DS18B20_Read_Byte(void)     
    {        
        u8 i,j,dat;
        dat=0;
    	for (i=1;i<=8;i++) 
    	{
            j=DS18B20_Read_Bit();
            dat=(j<<7)|(dat>>1);
        }						    
        return dat;
    }
    //写一个字节到DS18B20
    //dat:要写入的字节
    void DS18B20_Write_Byte(u8 dat)     
     {             
        u8 j;
        u8 testb;
    	DS18B20_IO_OUT();	//SET PG11 OUTPUT;
        for (j=1;j<=8;j++) 
    	{
            testb=dat&0x01;
            dat=dat>>1;
            if (testb) 
            {
                DS18B20_DQ_OUT=0;	// Write 1
                delay_us(2);                            
                DS18B20_DQ_OUT=1;
                delay_us(60);             
            }
            else 
            {
                DS18B20_DQ_OUT=0;	// Write 0
                delay_us(60);             
                DS18B20_DQ_OUT=1;
                delay_us(2);                          
            }
        }
    }
    //开始温度转换
    void DS18B20_Start(void) 
    {   						               
        DS18B20_Rst();	   
    	DS18B20_Check();	 
        DS18B20_Write_Byte(0xcc);	// skip rom
        DS18B20_Write_Byte(0x44);	// convert
    } 
    
    //初始化DS18B20的IO口 DQ 同时检测DS的存在
    //返回1:不存在
    //返回0:存在    	 
    u8 DS18B20_Init(void)
    {
     	GPIO_InitTypeDef  GPIO_InitStructure;
     	
     	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOG, ENABLE);	 //使能PORTG口时钟 
    	
     	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;				//PORTG.11 推挽输出
     	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		  
     	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
     	GPIO_Init(GPIOG, &GPIO_InitStructure);
    
     	GPIO_SetBits(GPIOG,GPIO_Pin_11);    //输出1
    
    	DS18B20_Rst();
    
    	return DS18B20_Check();
    }  
    //从ds18b20得到温度值
    //精度:0.1C
    //返回值:温度值 (-550~1250) 
    short DS18B20_Get_Temp(void)
    {
        u8 temp;
        u8 TL,TH;
    	short tem;
        DS18B20_Start ();  			// ds1820 start convert
        DS18B20_Rst();
        DS18B20_Check();	 
        DS18B20_Write_Byte(0xcc);	// skip rom
        DS18B20_Write_Byte(0xbe);	// convert	    
        TL=DS18B20_Read_Byte(); 	// LSB   
        TH=DS18B20_Read_Byte(); 	// MSB  
    	    	  
        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;    
    }
    
    
    

    DS18B20.H

    #ifndef __DS18B20_H
    #define __DS18B20_H 
    #include "sys.h"   
    
    //IO方向设置
    #define DS18B20_IO_IN()  {GPIOG->CRH&=0XFFFF0FFF;GPIOG->CRH|=8<<12;}
    #define DS18B20_IO_OUT() {GPIOG->CRH&=0XFFFF0FFF;GPIOG->CRH|=3<<12;}
    IO操作函数											   
    #define	DS18B20_DQ_OUT PGout(11) //数据端口	PA0 
    #define	DS18B20_DQ_IN  PGin(11)  //数据端口	PA0 
       	
    u8 DS18B20_Init(void);//初始化DS18B20
    short DS18B20_Get_Temp(void);//获取温度
    void DS18B20_Start(void);//开始温度转换
    void DS18B20_Write_Byte(u8 dat);//写入一个字节
    u8 DS18B20_Read_Byte(void);//读出一个字节
    u8 DS18B20_Read_Bit(void);//读出一个位
    u8 DS18B20_Check(void);//检测是否存在DS18B20
    void DS18B20_Rst(void);//复位DS18B20    
    #endif
    
    

    在这里插入图片描述
    在这里插入图片描述

    展开全文
  • 该资源是《openwrt开发指南》第27章 《DS18B20温度传感器》的附件:ds18b20驱动程序和应用程序,请有需要的朋友自行下载,没有积分的朋友私信博主。
  • DS18B20温度传感器测量程序(LCD1602显示)
  • 这是DS18B20数字温度传感器测温程序,参加各种电子设计比赛可能会用到。DS18B20 是美信公司的一款温度传感器,单片机可以通过 1-Wire 协议与 DS18B20 进行通信,最终将温度读出。1-Wire 总线的硬件接口很简单,只...
  • DS18B20温度传感器c程序 使用AVR单片机读取
  • 单片机DS18B20温度传感器C语言程序含CRC校验.doc
  • 51单片机DS18B20单总线温度传感器,附件包含一个DS18B20的例程,基于51单片机,利用12MHz晶振写的温度时序程序
  • ds18b20温度传感器51程序源码 keil 工程 含有串口程序
  • 这是一个好用的DS18B20温度传感器程序,基于51单片机的,用1602显示的,可以精确到小数点后一位
  • 单片机上显示温度(ds18b20温度传感器传感器)的程序
  • 基于51单片机与DS18B20温度传感器的温度计程序文件.doc
  • MSP430单片机初学者程序DS18B20温度传感器C语言程序,适合MSP430初学者和18b20温度传感器驱动代码
  • DS18B20的数字温度传感器,可以用来对环境温度进行定量的检测。

    目录

    1、模组简介

    2、驱动原理

    3、HC32L136驱动

    4、ESP32驱动


    新冠疫情、元器件涨价,同一家店铺之前买的DS18B20模组体积有大拇指这么大,最近买体积只有大拇指指甲盖这么大,以前无论买多少都有6元运费,今年哪怕买一块都是包邮,今年生意难做了,祈祷国泰民安、国强民富!


    言归正传,说大事分割线~


    1、模组简介

    DS18B20的数字温度传感器,可以用来对环境温度进行定量的检测。DS18B20数字温度传感器是美国DALLAS公司生产的一总线数字温度传感器。其测温范围 -55℃~+125℃,固有测温分辨率0.5℃,支持多点组网功能,多个DS18B20可以并联在唯一的三线上,实现多点测温,测量结果以9~12位数字量方式串行传送。模组结构如下图所示:

    模组特性如下所示: 

    • 独特的1-Wire总线接口仅需要一个管脚来通信。
    • 每个设备的内部ROM上都烧写了一个独一无二的64位序列号。
    • 多路采集能力使得分布式温度采集应用更加简单。
    • 无需外围元件。
    • 能够采用数据线供电,供电范围为3.0V至5.5V。
    • 温度可测量范围为:-55℃至+125℃(-67℉至+257℉)。
    • 温度范围超过-10℃至85℃之外时测温分辨率0.5℃。
    • 内部温度采集精度可以由用户自定义为9-Bits至12-Bits。
    • 温度转换时间在转换精度为12-Bits时达到最大值750ms。
    • 用户自定义非易失性的的温度报警设置。
    • 定义了温度报警搜索命令和当温度超过用户自定义的设定值时。
    • 可选择的8-Pin SO (150 mils), 8-Pin μSOP,及3-Pin TO-92封装。
    • 与DS1822程序兼容。
    • 应用于温度控制系统,工业系统,民用产品,温度传感器,或者任何温度检测系统中。

    DS18B20管脚定义如下图所示:

    DS18B20采用Maxim公司专有的1-Wire总线协议,该总线协议仅需要一个控制信号进行通信。该控制信号线需要一个唤醒的上拉电阻以防止连接在该总线上的口是3态或者高阻态(DQ信号线是在DS18B20上)。在该总线系统中,微控制器(主设备)通过每个设备的64为序列号来识别该总线上的设备。因为每个设备都有一个独一无二的序列号,挂在一个总线上的设备理论上是可以无限个的。在下面的“1-Wire总线系统”章节中包含有1-Wire总线协议详细的命令和时序关系。

    DS18B20的另外一个特性就是可以无需外部电源供电。当数据线DQ为高的时候由其为设备供电。总线拉高的时候为内部电容(Spp)充电,当总线拉低是由该电容向设备供电。这种由1-Wire总线为设备供电的方式称为“寄生电源”。此外,DS18B20也可以由外部电源通过VDD供电。DS18B20内部框图如下所示:

    DS18B20的核心功能是直接温度—数字测量,上电后工作在低功耗闲置状态下,其温度转换可由用户自定义为9、10、11、12位精度分别为0.5℃、0.25℃、0.125℃、0.0625℃分辨率,上电默认为12位转换精度。温度数据以一个16位标志扩展二进制补码数的形式存储在温度寄存器中,符号标志位(S)温度的正负极性:正数则S=0,负数则S=1。如果DS18B20被定义为12位的转换精度,温度寄存器中的所有位都将包含有效数据。若为11位转换精度,则BIT 0为未定义的。若为10位转换精度,则BIT 1和BIT 0为未定义的。 若为9位转换精度,则BIT 2、BIT 1和BIT 0为未定义的。下表为在12位转换精度下温度输出数据与相对应温度之间的关系表。

    DS18B20的温度输出数据时在摄氏度下校准的,若是在华氏度下应用的话,可以用查表法或者常规的数据换算,温度/数据对应关系如下表所示:

    DS18B20可以通过VDD引脚由外部供电,或者可以由“寄生电源”供电,这使得DS18B20可以不采用当地的外部电源供电而实现其功能。

    外部电源供电方式具有不需要上拉的MOSFET、该1-Wire总线在温度转换期间可执行其他动作的优点,外部电源供电方式如下图所示:

    “寄生电源”供电方式在远程温度检测或空间比较有限制的地方有很大的应用,其由DQ口拉高时向其供电。总线拉高的时候为内部电容(Cpp)充电,当总线拉低是由该电容向设备供电。当DS18B20为“寄生电源”供电模式时,该VDD引脚必须连接到地。“寄生电源”供电方式在温度超过+100℃时不推荐使用,因为在超过该温度下时将会有很大的漏电流导致不能进行正常的通信。实际应用中,在类似的温度状态下强烈推荐该DS18B20由外部电源供电,“寄生电源”供电方式如下图所示。

    DS18B20存储器包含了SRAM暂存寄存器、过温和低温(TH和TL)温度报警寄存器、配置寄存器的非易失性EEPROM。当温度报警功能没有用到的时候,过温和低温(TH和TL)温度报警寄存器可以当做通用功能的存储单元。

    SRAM暂存寄存器中的Byte 0和Byte 1分别作为温度寄存器的低字节和高字节,同时这两个字节是只读的;Byte 2和Byte 3作为过温和低温(TH和TL)温度报警寄存器;Byte 4保存着配置寄存器的数据;Byte 5、6、7作为内部使用的字节而保留使用,不可被写入;Byte 8存储着该暂存寄存器中Byte 0至Byte 7的循环冗余校验(CRC)值,并且只读不可写入,存储器组织结构如下图所示:

    2、驱动原理

     DS18B20的驱动过程主要依托于1-Wire总线系统,该总线系统可以一个总线主设备控制一个或多个从设备,我们的MCU作为主设备,DS18B20永远为从设备,1-Wire总线系统上所有的命令或者数据的发送送都是遵循低位先发送的原则。

    1-Wire总线系统仅有一根数据线,且需要一个5kΩ左右的外部上拉电阻,因此闲置情况下数据线是高电平。每个设备(主设备或从设备)通过一个漏极开路或3态门引脚连接至数据线上。这就允许每个设备“释放”数据线,当设备没有传递数据的时其他设备可以有效地使用数据线。DS18B20的1-Wire总线接口(DQ引脚)是其内部电路组成的漏极开路,硬件配置如下图所示:

    实现DS18B20的驱动主要有三步:

    第一步:初始化DS18B20;

    第二步:ROM命令(紧跟任何数据交换请求);

    第三步:DS18B20功能命令(紧跟任何数据交换请求);

    每次对DS18B20的访问都必须遵循这样的步骤来进行,如果这些步骤中的任何一个丢失或者没有执行,则DS18B20将不会响应。这只说明驱动的思路,具体参见DS18B20数据手册

    3、HC32L136驱动

    第1步:配置GPIO,这里配置HC32L136的PB03引脚,PB03引脚连接DS18B20数据线,所以IO口的方向(输入、输出)在读、写过程中是不断变化的,代码如下所示:

    uint8_t DS18B20_Init(void)
    {
      
      stc_gpio_cfg_t stcGpioCfg;
    
      DDL_ZERO_STRUCT(stcGpioCfg);
    
      Sysctrl_SetPeripheralGate(SysctrlPeripheralGpio,TRUE);   //开启GPIO时钟门控 
    
      stcGpioCfg.enDir = GpioDirOut;                           ///< 端口方向配置->输出    
      stcGpioCfg.enOD = GpioOdDisable;                         ///< 推挽输出
      stcGpioCfg.enPu = GpioPuDisable;                         ///< 端口上拉配置->禁止
      stcGpioCfg.enPd = GpioPdDisable;                         ///< 端口下拉配置->禁止
      stcGpioCfg.enDrv=GpioDrvH;                               ///< 强驱动
    
      Gpio_Init(GpioPortB,GpioPin8,&stcGpioCfg);               ///< 端口初始化
    
      Gpio_SetIO(GpioPortB,GpioPin8);                          ///< 默认置高电平
    }

    第2步:配置延时,本案例基于HC32L136 24MHz时钟频率下工作的,一个机器周期约为2us(num参数,不是倍数关系,HC32L136延时相当不精准,需要用示波器验证),代码如下所示:

    void delay_us(uint32_t num)
    {
      while(num--)
      {
        __NOP();
      }
    }

    第3步:初始化以及检测DS18B20是否存在,当DS18B20响应复位信号的存在脉冲后,则其向主设备表明其在该总线上,并且已经做好操作命令。

    在初始化序列期间,总线上的主设备通过拉低1-Wire总线超过480us来发送(TX)复位脉冲。之后主设备释放总线而进入接收模式(RX)。当总线释放后,5kΩ左右的上拉电阻将1-Wire总线拉至高电平。当DS18B20检测到该上升边沿信号后,其等待15us至60us后通过将1-Wire总线拉低60us至240us来实现发送一个存在脉冲。初始化时序如下图所示:

    初始化时序代码如下所示:

    //复位DS18B20
    void DS18B20_Rst(void)	   
    {       
      DS18B20_IO_OUT(); 	                ///< 配置端口输出
      Gpio_ClrIO(GpioPortB,GpioPin8); 	///< 拉低DQ
      delay100us(7);                        ///< 拉低700us
      Gpio_SetIO(GpioPortB,GpioPin8); 	///< 拉高DQ
      delay10us(1);                         ///< 拉高15us
    }
    
    //等待DS18B20的回应
    //返回1:未检测到DS18B20的存在
    //返回0:存在
    uint8_t DS18B20_Check(void) 	   
    {   
      uint8_t retry=0;
      DS18B20_IO_IN();	///< 配置端口输入
      while ((Gpio_GetInputIO(GpioPortB,GpioPin8)==1) && (retry<100))  ///< 最多200us
      {
        retry++;            
        delay_us(1);        ///< 每次等待2us
      }	
    
      if(retry>=200) 
      {
        return 1;
      }
      else 
      {
        retry=0;
      }
    
      while ((Gpio_GetInputIO(GpioPortB,GpioPin8)==0 )&& (retry<120))  ///< 最多240us
      {
        retry++;
        delay_us(1);        ///< 每次等待2us
      }
    
      if(retry>=120) 
      {
        return 1;	
      }
      
      return 0;
    }

    运行程序,时序效果如下所示:

    第4步:开始转换DS18B20,写入ROM命令:0XCC和0X44。写时段有两种情况:“写1”时段和“写0”时段,主设备通过写1时段来向DS18B20中写入逻辑1以及通过写0时段来向DS18B20中写入逻辑0。每个写时段最小必须有60us的持续时间且独立的写时段间至少有1us的恢复时间。

    为了形成写1时段,在将1-Wire总线拉低后,主设备必须在15us之内释放总线。当总线释放后,5kΩ的上拉电阻将总线拉至高。为了形成写0时段,在将1-Wire总线拉低后,在整个时段期间主设备必须一直拉低总线(至少60us)。

    在主设备初始化写时段后,DS18B20将会在15us至60us的时间窗口内对总线进行采样。如果总线在采样窗口期间是高电平,则逻辑1被写入DS18B20;若总线是低电平,则逻辑0被写入DS18B20。读/写时段时序如下所示:

     转换DS18B20代码如下所示:

    //写一个字节到DS18B20
    //dat:要写入的字节
    void DS18B20_Write_Byte(uint8_t dat)     
     {             
      uint8_t j;
      uint8_t testb;
      DS18B20_IO_OUT();	                ///< 配置端口输出
      for (j=1;j<=8;j++) 
      {
        testb=dat&0x01;
        dat=dat>>1;
        if (testb)                         ///< 写入1
        {
          Gpio_ClrIO(GpioPortB,GpioPin8); 	   
          delay_us(1);                     ///< 拉低2us   
    
          Gpio_SetIO(GpioPortB,GpioPin8); 
          delay10us(5);                    ///< 拉高64us
        }
        else                              ///< 写入0
        {
          Gpio_ClrIO(GpioPortB,GpioPin8);     
          delay10us(5);                    ///< 拉低64us
    
          Gpio_SetIO(GpioPortB,GpioPin8); 
          delay_us(1);                     ///< 拉高2us   
        }
      }
    }
    
    //开始温度转换
    void DS18B20_Start(void) 
    {   						               
      DS18B20_Rst();	   
      DS18B20_Check();	 
      DS18B20_Write_Byte(0xCC);	///<  skip rom
      DS18B20_Write_Byte(0x44);	///<  convert
    } 

    运行程序,写入0XCC(二进制:‭1100 1100‬)时序效果如下所示:

    写入0X44(二进制:0100 0100‬)时序效果如下所示:

    第5步: 写入读取DS18B20暂存器功能命令:0XCC和0XBE,代码如下所示:

      DS18B20_Write_Byte(0xCC);	///<  skip rom
      DS18B20_Write_Byte(0xBE);	///<  convert	

    运行程序,写入0XBE(二进制:‭1011 1110‬)时序效果如下所示:

    第6步:  读取温度寄存器数据,这里只需要读取两个字节(16位)即可。每个读时段最小必须有60us的持续时间且独立的写时段间至少有1us的恢复时间。读时段通过主设备将总线拉低超过1us再释放总线来实现初始化,当主设备初始化完读时段后,DS18B20将会向总线发送0或者1。DS18B20通过将总线拉至高来发送逻辑1,将总线拉至低来发送逻辑0。当发送完0后,DS18B20将会释放总线,则通过上拉电阻该总线将会恢复到高电平的闲置状态。从DS18B20中输出的数据在初始化读时序后仅有15us的有效时间,因此,主设备在开始改读时段后的15us之内必须释放总线,并且对总线进行采样。读时段时序图如下所示:

    读时段代码如下所示:

    //从DS18B20读取一个位
    //返回值:1/0
    uint8_t DS18B20_Read_Bit(void) 	 
    {
      uint8_t data;
      DS18B20_IO_OUT();	///< 配置端口输出
      Gpio_ClrIO(GpioPortB,GpioPin8); 
      delay_us(1);          ///< 等待2us
    
      Gpio_SetIO(GpioPortB,GpioPin8);
      DS18B20_IO_IN();	///< 配置端口输入
      delay_us(40);         ///< 等待12us
    
      if(Gpio_GetInputIO(GpioPortB,GpioPin8)==1)
      {
        data=1;
      }
      else 
      {
        data=0;	 
      }
      
      delay10us(4);        ///< 等待52us
      return data;
    }
    
    //从DS18B20读取一个字节
    //返回值:读到的数据
    uint8_t DS18B20_Read_Byte(void)     
    {        
      uint8_t i=0,j=0,dat=0;
      uint8_t num1,num2;
      for (i=1;i<=8;i++)            ///< 一次读取一个字节,8位
      {
        j=DS18B20_Read_Bit();
        num1=j<<7;
        num2=dat>>1;
        dat=num1|num2;
      }						
      return dat;
    }
    
    TL=DS18B20_Read_Byte(); 	///<  读取LSB,低八位数据   
    TH=DS18B20_Read_Byte(); 	///<  读取MSB,高八位数据    

    运行程序,读取低八位数据时序效果如下所示:

     读取高八位数据时序效果如下所示:

    所以读到的数据为,二进制:101101010。

    第7步:将十六进制数据转换为十进制形式,代码如下所示:

    if(TH>7)                      ///<  温度为负 
    {
      TH=~TH;
      TL=~TL; 
      temp_flag=0;					
    }
    else                          ///<  温度为正
    {
      temp_flag=1;	
    }	  
    
    tem=TH; 					
    tem<<=8;    
    tem+=TL;					
    temp=(float)tem/16.0;		///<  转换数据 
     
    if(temp_flag)
    {
      return temp; 		
    } 
    
    return -temp;    
    

    二进制:101101010按照数据手册转换为十进制362,362除以16为22.625‬,与此时程序串口打印效果完全一致,说明转换无误。

    4、ESP32驱动

    闲来无事为了验证温度检测的精准性(HC32L136精度较差),特使用ESP32又写了一版驱动程序,完整示例代码如下所示(可直接复制使用):

    #include <OneWire.h>
    
    int DS18B20_Pin = D3; //DS18B20信号引脚在D3上
    
    //温度芯片I/O
    OneWire ds(DS18B20_Pin);  //配置数字引脚D3
    
    void setup(void) {
      Serial.begin(9600);
      Serial.println("Start!\n");
    }
    
    void loop(void) {
      float temperature = getTemp();
      Serial.println(temperature);
      
      delay(1000); 
    }
    
    
    float getTemp(){
      //获取DS18B20温度数据
    
      byte data[12];
      byte addr[8];
    
      if ( !ds.search(addr)) {
          //若无传感器继续搜索
          ds.reset_search();
          return -1000;
      }
    
      if ( OneWire::crc8( addr, 7) != addr[7]) {
          Serial.println("CRC is not valid!");
          return -1000;
      }
    
      if ( addr[0] != 0x10 && addr[0] != 0x28) {
          Serial.print("Device is not recognized");
          return -1000;
      }
    
      ds.reset();
      ds.select(addr);
      ds.write(0x44,1); //开始转换
    
      byte present = ds.reset();
      ds.select(addr);    
      ds.write(0xBE); //读暂存存储器
    
      
      for (int i = 0; i < 9; i++) { //读取9个字节
        data[i] = ds.read();
      }
      
      ds.reset_search();
      
      byte MSB = data[1];
      byte LSB = data[0];
    
      float tempRead = ((MSB << 8) | LSB); 
      float TemperatureSum = tempRead / 16;
      
      return TemperatureSum;
      
    }

    同时运行程序,HC32L136和ESP32同时获取DS18B20温度数据基本一致,时序效果如下所示:

    串口输出数据效果如下所示:

    展开全文
  • DS18B20温度传感器

    2014-10-12 21:35:47
    基于51开发板,使用ds18b20温度传感器,可以显示在数码管上!
  • DS18B20温度传感器模块使用资料包,包括并不限于: 1、DS18B20温度传感器模块原理图; 2、DS18B20温度传感器模块相关资料; 3、DS18B20温度传感器模块测试程序(51版本和STM32版本)。

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,560
精华内容 1,024
关键字:

ds18b20温度传感器程序