FPGA_DS18B20温度传感器手册介绍以及接口代码编写思路

  • Post author:
  • Post category:其他




一. DS18B20大概介绍



1. Power

电源可以用 parasite power 或者

external power

,普遍选择外部电源



2. DS18B20内部存储一共有9个字节



(1).DS18B20内部存储框图


读取温度只需要用byte0,byte1

内部存储框图



(2).DS18B20 温度有四种分辨率模式(9,10,11,


12bit


)

​ 采用12bit分辨率,高5位(S)是判断温度正负(0为正,1为负)



下面两图分别为温度高低字节,温度与读取数据之间的关联

在这里插入图片描述



3.DS18B20采用单总线协议

  • All data and commands are transmitted

    least significant bit first(读写都是从最低位开始)

    over the 1-Wire bus.
  • 1-wire : 异步半双工串行通信



4.DS18B20发送命令顺序



(1).

TRANSACTION SEQUENCE

The transaction sequence for accessing the DS18B20 is as follows:


三个顺序必须遵行

(初始化 – ROM命令 – DS18B20命令)


  • Step 1. Initialization

  • Step 2. ROM Command (followed by any required data exchange)

  • Step 3. DS18B20 Function Command (followed by any required data exchange)

It is very important to follow this sequence every time the DS18B20 is accessed, as the DS18B20 will not respond if any steps in the sequence are missing or out of order. Exceptions to this rule are the Search ROM [F0h] and Alarm Search [ECh] commands. After issuing either of these ROM commands, the master must return to Step 1 in the sequence.



(2).ROM,DS18B20命令流程图


读取温度需要的命令:

SKIP ROM [CCh]

(跳过ROM命令),

CONVERT T [44h]

(温度转换命令),

READ SCRATCHPAD [BEh]

(温度读取命令)

在这里插入图片描述

DS18B20 函数命令流程表

在这里插入图片描述



二. DS1820 INITIAL(初始化)

INITIALIZATION PROCEDURE:

RESET AND PRESENCE PULSES

(复位脉冲和存在脉冲)

All communication with the DS18B20 begins with an initialization sequence that consists of a reset pulse from the master followed by a presence pulse from the DS18B20. This is illustrated in Figure 13. When the DS18B20 sends the presence pulse in response to the reset, it is indicating to the master that it is on the bus and ready to operate.

During the initialization sequence the bus master transmits (TX) the reset pulse by pulling the 1-Wire bus low for a minimum of 480us. The bus master then releases the bus and goes into receive mode (RX). When the bus is released, the 5k pullup resistor pulls the 1-Wire bus high. When the DS18B20 detects this rising edge, it waits 15us to 60us and then transmits a presence pulse by pulling the 1-Wire bus low for 60us to 240us



1.初始化过程

  1. 复位脉冲:控制总线拉低480us以上,然后释放总线
  2. WAIT:15~60us
  3. 检测存在脉冲:在60~240us内总线有一个低电平
  4. wait:1000us-复位脉冲-WAIT-检测存在脉冲
  5. 初始化完成.



2.初始化时序图

在这里插入图片描述



三.向DS18B20 写命令


WRITE TIME SLOTS

There are two types of write time slots: “Write 1” time slots and “Write 0” time slots. The bus master uses a Write 1 time slot to write a logic 1 to the DS18B20 and a Write 0 time slot to write a logic 0 to the DS18B20. All write time slots must be a minimum of 60us in duration with a minimum of a 1 s recovery time between individual write slots. Both types of write time slots are initiated by the master pulling the 1-Wire bus low (see Figure 14). To generate a Write 1 time slot, after pulling the 1-Wire bus low, the bus master must release the 1-Wire bus within 15us. When the bus is released, the 5k pullup resistor will pull the bus high.

To generate a Write 0 time slot, after pulling the 1-Wire bus low, the bus master must continue to hold the bus low for the duration of the time slot (at least 60us). The DS18B20 samples the 1-Wire bus during a window that lasts from 15us to 60us after the master initiates the write time slot. If the bus is high during the sampling window, a 1 is written to the DS18B20. If the line is low, a 0 is written to the DS18B20.



1.写时序图

在这里插入图片描述



2.写过程

1.写0缝隙:控制总线拉低60

120us,然后释放总线(dq会在15

45us之间采样)

.写1缝隙:控制总线拉低15us以内,然后ds18b20释放总线(dq会在15~45us之间采样)

2.wait:每一次写完1bit都需要等待1us以上

3.写完成,根据需求判断是否需要读取下个bit



四.读取DS18B20数据


READ TIME SLOTS

The DS18B20 can only transmit data to the master when the master issues read time slots. Therefore, the master must generate read time slots immediately after issuing a Read Scratchpad [BEh] or Read Power Supply [B4h] command, so that the DS18B20 can provide the requested data. In addition, the master can generate read time slots after issuing Convert T [44h] or Recall E2 [B8h] commands to find out the status of the operation as explained in the DS18B20 FUNCTION COMMAND section.

All read time slots must be a minimum of 60us in duration with a minimum of a 1us recovery time between slots. A read time slot is initiated by the master device pulling the 1-Wire bus low for a minimum of 1us and then releasing the bus (see Figure 14). After the master initiates the read time slot, the DS18B20 will begin transmitting a 1 or 0 on bus. The DS18B20 transmits a 1 by leaving the bus high and transmits a 0 by pulling the bus low. When transmitting a 0, the DS18B20 will release the bus by the end of the time slot, and the bus will be pulled back to its high idle state by the pullup resister. Output data from the DS18B20 is valid for 15us after the falling edge that initiated the read time slot. Therefore, the master must release the bus and then sample the bus state within 15us from the start of the slot.

Figure 15 illustrates that the sum of TINIT, TRC, and TSAMPLE must be less than 15us for a read time slot. Figure 16 shows that system timing margin is maximized by keeping TINIT and TRC as short as possible and by locating the master sample time during read time slots towards the end of the 15us period.



1.读时序图

![在这里插入图片描述](https://img-blog.csdnimg.cn/9de84bf9913641f695503db4d5e136d5.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAd29yc2Vfb3JfYmV0dGVy,size_17,color_FFFFFF,t_70,g_se,x_16#pic_center)

在这里插入图片描述



2.读数据过程

1.控制总线拉低

1us

以上,然后释放总线

2.读取数据:最好在

10-14us

3.wait:读1bit整个过程需要

60us

4.wait_bit:每读完1bit需要等待

1us

以上

5.读完成,根据需求判断是否需要读取下个bit



五. 状态转换以及整体框架



1.状态转换

在这里插入图片描述



2. 整体框架

在这里插入图片描述



六.DS18B20接口代码

module ds18b20_driver (
    input                 clk       ,
    input                 rst_n     ,
    input     [1:0]       req       ,//开启/关闭温度检测,按键控制

    output   [15:0]      data_out  ,
    inout                dq                      
);
/* 参数定义 */
localparam      IDLE        = 7'b000_0001,//状态参数,独热码
                INIT        = 7'b000_0010,//DS18B20初始化
                WRITE1      = 7'b000_0100,//第一次写跳过ROM命令和温度转换命令
                WAIT        = 7'b000_1000,//等待温度转换成功
                WRITE2      = 7'B001_0000,//第二次写跳过ROM命令和温度读取命令
                READ        = 7'b010_0000,//读取温度
                DONE        = 7'b100_0000;


localparam      T_INIT_RES  = 24000  ,//初始化复位脉冲时间480us,总线释放
                T_INIT_WAIT = 1500   ,//复位脉冲后等待30us
                T_INIT_PP   = 6000   ,//DS18B20存在脉冲120us
                T_INIT_ALL  = 50000  ;//初始化全过程1000us

localparam      T_WRITE0_LOW = 600   ,//12us总线拉低
                T_WRITE0_SP  = 3000  ,//SAMPLE window 60us,总线释放
                T_WRITE1_LOW = 600   ,//12us总线拉低,,总线释放
                T_WRITE1_SP  = 3000  ,//SAMPLE window 60us
                T_BIT_WAIT   = 100   ,//1bit写完等待时间2us
                T_WRITE      = 3600  ,//写72us
                T_WRITE_BIT  = 3700  ;//写全过程时间 74us   

localparam      T_CONV       = 37_500_000;//温度转换时间

localparam      T_READ_LOW   = 100   ,//拉低总线2us
                T_READ_DATA  = 600   ,//在12us读取数据
                T_READ_SLOT  = 3000  ,//READ SLOT,总线释放
                T_READ_WAIT  = 100   ,//1BIT等待时间
                T_READ       = 3200  ,//读64us
                T_READ_BIT   = 3300  ;//读取数据全过程时间66us
                

/* 信号定义 */
reg                 dq_out_en;//三态门选择
reg                 dq_out;
wire                dq_in;
reg                 slave_ack;//DS18B20初始化是否成功信号
reg     [15:0]      command;
reg     [15:0]      data_out_r;

reg     [6:0]       state_c    ;//状态信号
reg     [6:0]       state_n    ;

wire                idle_init  ;    
wire                init_write1;    
wire                init_write2;    
wire                write1_wait;    
wire                wait_init  ;
wire                write2_read;    
wire                read_done  ;
wire                done_idle  ;

reg                 start_flag ;//开始信号
reg                 write1_over;//第一次命令写完

reg      [31:0]    time_cnt;//计数器
wire               add_time_cnt;
wire               end_time_cnt;
reg      [31:0]    time_cnt_sel;//计数选择

reg      [4:0]    bit_cnt;//bit计数器
wire              add_bit_cnt;
wire              end_bit_cnt;


//start_flag开始信号
always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin
        start_flag <= 0;
    end 
    else if(req[0])begin 
        start_flag <= 1;
    end 
    else if(req[1])begin 
        start_flag <= 0;
    end 
end
//状态转换
always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin
        state_c <= IDLE;
    end 
    else begin 
        state_c <= state_n;
    end 
end

always @(*) begin
    case(state_c)
        IDLE    : 
                if (idle_init) begin
                    state_n = INIT;            
                end 
                else begin
                    state_n = state_c;
                end
        INIT    : 
                if (init_write1) begin
                    state_n = WRITE1;            
                end 
                else if (init_write2) begin
                    state_n = WRITE2;            
                end 
                else begin
                    state_n = state_c;
                end
        WRITE1 : 
                if (write1_wait) begin
                    state_n = WAIT;            
                end 
                else begin
                    state_n = state_c;
                end
        WAIT   : 
                if (wait_init) begin
                    state_n = INIT;            
                end 
                else begin
                    state_n = state_c;
                end
        WRITE2 : 
                if (write2_read) begin
                    state_n = READ;            
                end 
                else begin
                    state_n = state_c;
                end
        READ   : 
                if (read_done) begin
                    state_n = DONE;            
                end 
                else begin
                    state_n = state_c;
                end
        DONE   : 
                if (done_idle) begin
                    state_n = IDLE;            
                end 
                else begin
                    state_n = state_c;
                end
        default : state_n <= state_c ;
    endcase
end

assign    idle_init    = state_c == IDLE    && start_flag  ;
assign    init_write1  = state_c == INIT    && end_time_cnt && write1_over == 0 && slave_ack ;
assign    init_write2  = state_c == INIT    && end_time_cnt && write1_over && slave_ack; 
assign    write1_wait  = state_c == WRITE1  && end_bit_cnt ; 
assign    wait_init    = state_c == WAIT    && end_time_cnt;
assign    write2_read  = state_c == WRITE2  && end_bit_cnt ;  
assign    read_done    = state_c == READ    && end_bit_cnt ;
assign    done_idle    = state_c == DONE    && 1'b1;       

//write1_over
always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin
        write1_over <= 0;
    end 
    else if(write1_wait)begin 
        write1_over <= 1'b1;
    end 
    else if(write2_read)begin 
        write1_over <= 1'b0;
    end 
end


//计数器
always @(posedge clk or negedge rst_n)begin 
   if(!rst_n)begin
        time_cnt <= 0;
    end 
    else if(add_time_cnt)begin 
            if(end_time_cnt)begin 
                time_cnt <= 0;
            end
            else begin 
                time_cnt <= time_cnt + 1;
            end 
    end
   else  begin
       time_cnt <= time_cnt;
    end
end 

assign add_time_cnt = (state_c != IDLE || state_c != DONE) ;
assign end_time_cnt = add_time_cnt && time_cnt == time_cnt_sel - 1;

//时间计数选择
always @(*)begin 
    case(state_c)
    INIT   : time_cnt_sel = T_INIT_ALL  ;
    WRITE1 : time_cnt_sel = T_WRITE_BIT ;
    WAIT   : time_cnt_sel = T_CONV      ;
    WRITE2 : time_cnt_sel = T_WRITE_BIT ;
    READ   : time_cnt_sel = T_READ_BIT  ;
    default: time_cnt_sel = 10;
    endcase
end

//bit计数器
always @(posedge clk or negedge rst_n)begin 
   if(!rst_n)begin
        bit_cnt <= 0;
    end 
    else if(add_bit_cnt)begin 
            if(end_bit_cnt)begin 
                bit_cnt <= 0;
            end
            else begin 
                bit_cnt <= bit_cnt + 1;
            end 
    end
   else  begin
       bit_cnt <= bit_cnt;
    end
end 

assign add_bit_cnt = (state_c == WRITE1 ||state_c == WRITE2|| state_c == READ) && end_time_cnt;
assign end_bit_cnt = add_bit_cnt && bit_cnt == 16-1;

//command
always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin
        command <= 0;
    end 
    else if(state_c == WRITE1)begin 
        command <= 16'h44CC;
    end 
    else if(state_c == WRITE2)begin 
        command <= 16'hBECC;
    end 
end

//slave_ack
always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin
        slave_ack <= 0;
    end 
    else if(state_c == INIT && dq_in == 0 )begin 
        slave_ack <= 1;
    end 
    else if(state_c != INIT)begin 
        slave_ack <= 0;
    end 
end

//初始化,写命令,读取数据DS18B20
always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin
        dq_out <= 0;
        dq_out_en <= 0;
        data_out_r <= 0;
    end 
    else if (state_c == INIT) begin
            if(time_cnt <= T_INIT_RES ) begin
                dq_out  <= 1'b0;
                dq_out_en <= 1'b1;
            end
            else if (time_cnt == (T_INIT_RES + T_INIT_WAIT)) begin
                dq_out_en <= 1'b0;
            end    
    end
    else if(state_c == WRITE1 )begin 
        if (time_cnt < T_WRITE0_LOW ) begin
                dq_out  <= 1'b0;
                dq_out_en <= 1'b1;
        end
        else if (time_cnt == T_WRITE0_LOW && command[bit_cnt] == 0) begin
                dq_out  <= 1'b0;
                dq_out_en <= 1'b1;
        end
        else if (time_cnt == T_WRITE) begin
                dq_out_en <= 1'b0;            
        end        
        else if(time_cnt == T_WRITE0_LOW && command[bit_cnt] == 1)begin            
                dq_out_en <= 1'b0;
        end 
 
    end 
    else if(state_c == WRITE2 )begin 
        if (time_cnt < T_WRITE0_LOW ) begin
                dq_out  <= 1'b0;
                dq_out_en <= 1'b1;
        end
        else if (time_cnt == T_WRITE0_LOW && command[bit_cnt] == 0) begin
                dq_out  <= 1'b0;
                dq_out_en <= 1'b1;
        end
        else if (time_cnt == T_WRITE) begin
                dq_out_en <= 1'b0;            
        end        
        else if(time_cnt == T_WRITE0_LOW && command[bit_cnt] == 1)begin            
                dq_out_en <= 1'b0;
        end    
    end 
    else if(state_c == READ )begin 
         if (time_cnt < T_READ_LOW ) begin
                 dq_out  <= 1'b0;
                 dq_out_en <= 1'b1;
         end
         else if (time_cnt == T_READ_LOW ) begin
                 dq_out_en <= 1'b0;
         end
         else if (time_cnt == T_READ_DATA) begin
                 data_out_r[bit_cnt] <= dq_in;            
         end           
    end 
end


assign data_out = data_out_r;
assign dq = dq_out_en?dq_out:1'bz;
assign dq_in = dq;
endmodule //ds18b20_driver



版权声明:本文为worse_or_better原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。