DS18B20数字温度传感器

一、DS18B20简介

1.DS18B20模块

1.1 序列号

1.2 高速暂存器

0,1字节温度数据;2字节温度报警高位,3字节,温度报警低位;4字节配置寄存器;5,6,7字节设备内部使用(保留位);8字节,CRC循环校验位。

1.2.1 温度传感器

DS18B20的核心模块是温度传感器,温度传感器用户可配置9,10,11,12位(分别对应的温度精度为0.5,0.25,0.125,0.0625),温度测量和AD转换命令[44h]。

温度数据以16位符号扩展的二进制补码形式存储在温度寄存器中。符号位(S)表示温度是正还是负:对于正数S = 0,对于负数S = 1;温度数据帧格式如下:

供电方式的确定,命令Skip ROM [CCh],确定是VDD还是寄生电源供电。

1.2.2 配置寄存器

通过R1和R0设置温度测量分辨率;其余位给设备内部使用,不能覆盖

1.2.3 CRC循环校验

高8位为CRC校验位

2.通信协议:1-wire/单总线

二、DS18B20命令

1.ROM指令

1.1 SKIP ROM [CCh] 跳出ROM

当总线上只有一个DS18B20时,可以不发送64bit数据,以节省时间,读指令(Read Scratchpad [BEh])会默认跟随跳出指令(SKIP ROM [CCh])发出。

2.DS18B20功能指令

三、DS18B20时序

1.初始化时隙

总线拉低480us -> 延时等待60us -> 采样存在脉冲(为1表示初始化失败跳回idle,为0表示初始化结束,开始配置ROM)

2.读写时隙

2.1 写时隙

主设备通过写时隙将命令写入 DS18B20 中,写时隙有两种情况:写“1”和写“0”时 隙。主设备通过写 1 时隙来向 DS18B20 中写入逻辑 1,通过写 0 时隙来向 DS18B20 中写入 逻辑 0。当主设备将总线从高电平拉至低电平时,启动写时隙,所有的写时隙持续时间最 少为 60us,每个写时隙间的恢复时间最少为 1us。 当总线(DQ)拉低后,DS18B20 在 15us 至 60us 之间对总线进行采样,如果采的 DQ 为高电平则发生写 1,如果为低电平则发生写 0,如上图所示(图中的总线控制器即为主设备)。 如果要产生写 1 时隙,必须先将总线拉至逻辑低电平然后释放总线,允许总线在写 隙开始后 15us 内上拉至高电平。若要产生写 0 时隙,必须将总线拉至逻辑低电平并保持不 变最少 60us。

2.2 读时隙

当我们发送完读取供电模式[B4h]或读高速缓存器[BEh]命令时,必须及时地生成读时隙,只有在读时隙 DS18B20 才能向主设备传送数据。每个读时隙最小必须有 60us 的持续 时间以及每个读时隙间至少要有 1us 的恢复时间。当主设备将总线从高电平拉至低电平超 过 1us,启动读时隙,如下图所示。当启动读时隙后,DS18B20 将会向主设备发送“0”或者“1”。DS18B20 通过将总线 拉高来发送 1,将总线拉低来发送 0 。当读时隙完成后,DQ 引脚将通过上拉电阻将总线拉高至高电平的闲置状态。从 DS18B20 中输出的数据在启动读时隙后的 15us 内有效,所以,主设备在读时隙开始后的 15us 内必须释放总线,并且对总线进行采样

四、工程实践

1.系统框图

2.程序设计

2.1 DS18B201驱动模块设计
2.1.1 DS18B20读取流程

1).初始化(IDLE)

2).ROM 配置,跳过ROM(ROM_SKIP)

3).发送温度转换命令,等待温度转换完成;

4).再次初始化,跳过ROM

5).发送温度读取命令,等待温度读取完成

2.1.2 状态机设计

2.1.3 驱动模块代码
module DS18B20_drive (
    input               clk             ,
    input               rst_n           ,
    inout   	        dq              ,
    output      [21:0]  temp_data       ,
    output              sign            ,
    output  reg         temp_data_vld              
);

//延时计数器最大值
parameter   DELAY_480US = 15'd24_000,
            DELAY_240US = 15'd12_000,
            DELAY_1US   = 15'd50,
            DELAY_12US  = 15'd600,
            DELAY_20US  = 15'd1_000 ,
            DELAY_15US  = 15'd1_500 ,
            DELAY_60US  = 15'd3_000 ,
            DELAY_61US  = 15'd3_050 ,
            DELAY_80us_sampling = 15'd4_000;

//状态机状态
parameter   IDLE        =   0,
            REST        =   1,
            RELS        =   2,
            RACK        =   3,
            ROM         =   4,
            CONT        =   5,
            RCMD        =   6,
            RTMP        =   7;

/**************************************************************
                变量/端口定义                 
**************************************************************/
//三态门
reg             dq_en ;
reg             dq_out;
wire            dq_in ;

reg     [2:0]   state_c;                
reg     [2:0]   state_n;

//状态跳转条件
wire            idle2rst ; 
wire            rst2rels ; 
wire            rels2rack; 
wire            rack2rom ; 
wire            rack2idle; 
wire            rom2cont ; 
wire            rom2rcmd ;
wire            rcmd2rtmp; 
wire            cont2idle; 
wire            rtmp2idle;   

reg             rack_flag    ;//存在脉冲标志
reg     [14:0]  DELAY        ;         
reg 	[14:0]	cnt_delay    ;
wire		  	add_cnt_delay;
wire		  	end_cnt_delay;

reg             flag;
//主机发送指令
reg     [7:0]   cmd;

reg     [4:0]   BIT_MAX    ;
reg 	[3:0]	cnt_bit    ;
wire		  	add_cnt_bit;
wire		  	end_cnt_bit;
//温度数据转换
reg         [15:0]  rd_data   ;    // /*synthsis noprone*/防止优化   
reg         [21:0]  rd_data_r ;
wire        [21:0]  rd_data_r1; 
/**************************************************************
              双向端口dq的使用方式                   
**************************************************************/
assign	dq_in = dq;							//高阻态的话,则把总线上的数据赋给dq_in
assign	dq =  dq_en ? dq_out : 1'bz;		//使能1则输出,0则高阻态

always @(*) begin
    if(state_c == REST || state_c == RELS
    || ((state_c == ROM || state_c == CONT || state_c ==RCMD) && cnt_delay <DELAY_60US )
    ||(state_c == RTMP && cnt_delay < DELAY_1US))
        dq_en = 1;
    else
        dq_en = 0;
end

/**************************************************************
                   ASCII              
**************************************************************/
reg         [47:0]  ascii_state;
always @(*)
case(state_c)
    IDLE     :   ascii_state = "IDLE";
    REST     :   ascii_state = "REST";
    RELS     :   ascii_state = "RELS";
    RACK     :   ascii_state = "RACK";
    ROM      :   ascii_state = "ROM ";
    CONT     :   ascii_state = "CONT";
    RCMD     :   ascii_state = "RCMD";
    RTMP     :   ascii_state = "RTMP";     
    default  :	 ascii_state = "IDLE";
endcase

/**************************************************************
                  状态机模块               
**************************************************************/
//第一段状态机
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(idle2rst)
                state_n = REST;
               else 
                state_n = state_c;
    REST    :   if(rst2rels)
                    state_n = RELS;
                else
                    state_n = state_c;
    RELS    :   if(rels2rack)
                    state_n = RACK;
                else
                    state_n = state_c;
    RACK    :   if(rack2rom)
                    state_n = ROM;      //接收到了存在脉冲
                else if(rack2idle)
                    state_n = IDLE;     //没有接收到存在脉冲
                else
                    state_n = state_c;
    ROM     :   if(rom2cont)
                    state_n = CONT;     //转换温度
                else if(rom2rcmd)
                    state_n = RCMD;     //读暂存器
                else
                    state_n = state_c;
    CONT    :   if(cont2idle)
                    state_n = IDLE;
                else
                    state_n = state_c;
    RCMD    :   if(rcmd2rtmp)
                    state_n = RTMP;
                else
                    state_n = state_c;
    RTMP    :   if(rtmp2idle)
                    state_n = IDLE;
                else
                    state_n = state_c;                                
    default : state_n = state_c;
    endcase
end	
                               
//状态跳转条件
assign 	 idle2rst   = state_c == IDLE && 1	; 
assign 	 rst2rels   = state_c == REST && end_cnt_delay;               //计满480us                    
assign 	 rels2rack  = state_c == RELS && end_cnt_delay;               //计满20us                 
assign 	 rack2rom   = state_c == RACK && ~rack_flag && end_cnt_delay; //采样dq(在80us时采样一次,并寄存住)
assign 	 rack2idle  = state_c == RACK &&  rack_flag && end_cnt_delay; 
assign 	 rom2cont   = state_c == ROM  && end_cnt_bit && !flag	;     //8bit数据发送完成
assign 	 rom2rcmd   = state_c == ROM  && end_cnt_bit && flag	;     //8bit数据发送完成
assign 	 rcmd2rtmp  = state_c == RCMD && end_cnt_bit	;             //8bit数据发送完成
assign 	 cont2idle  = state_c == CONT && end_cnt_bit && dq_in	;     //采样dq(检测到dq为1)
assign 	 rtmp2idle  = state_c == RTMP && end_cnt_bit	;             //16bit数据发送完成                   

/**************************************************************
                    存在脉冲采样             
**************************************************************/
always@(posedge clk or negedge rst_n)
    if(!rst_n)
        rack_flag <= 1;
    else if(state_c == RACK && cnt_delay == DELAY_15US)       
        rack_flag <= dq_in ;

/**************************************************************
                    状态跳转flag             
**************************************************************/
always@(posedge clk or negedge rst_n)
    if(!rst_n)
        flag <= 0;
    else if(state_c == CONT)
        flag <= 1;
    else if(rcmd2rtmp)
        flag <= 0;

/**************************************************************
                    延时计数器            
**************************************************************/		
always@(posedge clk or negedge rst_n)	
    if(!rst_n)								
        cnt_delay <= 'd0;						
    else    if(add_cnt_delay) begin				
        if(end_cnt_delay)						
            cnt_delay <= 'd0;  				
        else									
            cnt_delay <= cnt_delay + 1'b1;		
    end											
assign add_cnt_delay = !IDLE; //
assign end_cnt_delay = add_cnt_delay && cnt_delay == DELAY  - 1;

//延时计数最大值选择
always @(*) begin
    case (state_c)
        REST    :   DELAY = DELAY_480US;
        RELS    :   DELAY = DELAY_20US;
        RACK    :   DELAY = DELAY_240US;
        ROM     :   DELAY = DELAY_61US;
        CONT    :   DELAY = DELAY_61US;
        RCMD    :   DELAY = DELAY_61US;
        RTMP    :   DELAY = DELAY_61US;
        default :   DELAY =  0; 
    endcase
end

/**************************************************************
                   描述dq输出              
**************************************************************/
always @(*) begin
    case (state_c)         
        ROM     :   cmd = 8'hCC;
        CONT    :   cmd = 8'h44;
        RCMD    :   cmd = 8'hBE; 
        default :   cmd = 0 ;
    endcase
end

//bit计数器		
always@(posedge clk or negedge rst_n)	
    if(!rst_n)								
        cnt_bit <= 'd0;						
    else    if(add_cnt_bit) begin				
        if(end_cnt_bit)						
            cnt_bit <= 'd0;  				
        else									
            cnt_bit <= cnt_bit + 1'b1;		
    end											
assign add_cnt_bit = (state_c == ROM || state_c == CONT ||state_c == RCMD || state_c == RTMP) && end_cnt_delay;
assign end_cnt_bit = add_cnt_bit && cnt_bit == BIT_MAX - 1  ;

//bit计数器最大值选择
always@(*)
    if(state_c == RTMP)
        BIT_MAX = 5'd16;
    else
        BIT_MAX = 5'd8;

//写时隙
always@(posedge clk or negedge rst_n)
    if(!rst_n )
        dq_out <= 1;
    else if(state_c == REST)
        dq_out <= 0;
    else if(state_c == ROM || state_c == CONT || state_c == RCMD)begin
        if(cnt_delay < DELAY_1US)
            dq_out <= 0;
        else if(cnt_delay < DELAY_60US)
            dq_out <= cmd[cnt_bit];
    end    
    else if(state_c == RTMP)
        if(cnt_delay < DELAY_1US)
             dq_out <= 0;


//读时隙
always@(posedge clk or negedge rst_n)
    if(!rst_n)
        rd_data <= 0;
    else if(state_c == RTMP && cnt_delay == DELAY_12US)     //在12us时采样,
        rd_data[cnt_bit] <= dq_in;

/**************************************************************
                  温度数据转换               
**************************************************************/
//一级处理
always@(posedge clk or negedge rst_n)
    if(!rst_n)
        rd_data_r <= 0;
    else if(rtmp2idle)begin
        if(rd_data[15]) //符号位为1,表示负数
            rd_data_r <= (~(rd_data[10:0] - 1'b1)) ;
        else
            rd_data_r <= rd_data[10:0] ;
    end

   // //二级乘法运算
   //always@(posedge clk or negedge rst_n)
   // if(!rst_n)
   //     rd_data_r1 <= 0;
   // else
   //     rd_data_r1 <= rd_data_r * 11'd625;       //11'd625 /7'd100

assign  rd_data_r1 = rd_data_r * 11'd625;

assign  sign = rd_data[15]; 
assign  temp_data = rd_data_r1;

always@(posedge clk or negedge rst_n)
    if(!rst_n)
        temp_data_vld <= 0;
    else
        temp_data_vld <= rtmp2idle; 


endmodule
2.2 控制模块设计

控制模块将采集到的数据进行转换,并将转换后的数据传递给tx和seg模块

module ctrl (
    input               clk             ,
    input               rst_n           ,
    input      [21:0]   temp_data       ,
    input               sign            ,
    input  	            temp_data_vld   , 
    input               tx_ready        ,
    output reg [7:0]    tx_din          ,
    output              tx_din_vld      ,
    output     [23:0]   display_data    
);

binary2bcd #(
    .binary_width (22),
    .bcd_width    (24)
) binary2bcd_inst(
/*     input                                */.sys_clk     (clk  ),
/*     input                                */.sys_rst_n   (rst_n),
/*     input       [binary_width - 1 : 0]   */.binary      (temp_data),
/*     input                                */.binary_vliad(temp_data_vld),
/*     output  reg [bcd_width - 1 : 0]      */.bcd         (display_data),
/*     output  reg                          */.bcd_vliad   ()
);


reg             flag;
wire             cnt_flag;
reg 	[3:0]	cnt_l;
wire		  	add_cnt_l;
wire		  	end_cnt_l;

reg 	[25:0]	cnt_1s;
wire		  	add_cnt_1s;
wire		  	end_cnt_1s;

reg             temp_data_vld_r;
always@(posedge clk or negedge rst_n)
    if(!rst_n)
        temp_data_vld_r <= 0;
    else if(temp_data_vld)    
        temp_data_vld_r <= 1;

assign  cnt_flag = temp_data_vld_r && end_cnt_1s;

always@(posedge clk or negedge rst_n)
    if(!rst_n)
        flag <= 0;
    else if(cnt_flag)
        flag <= 1;
    else if(end_cnt_l)
        flag <= 0;


always@(posedge clk or negedge rst_n)	
    if(!rst_n)								
        cnt_1s <= 'd0;						
    else    if(add_cnt_1s) begin				
        if(end_cnt_1s)						
            cnt_1s <= 'd0;  				
        else									
            cnt_1s <= cnt_1s + 1'b1;		
    end											
assign add_cnt_1s = 1;
assign end_cnt_1s = add_cnt_1s && cnt_1s == 50_000_000 - 1 ;

always@(posedge clk or negedge rst_n)	
    if(!rst_n)								
        cnt_l <= 'd0;						
    else    if(add_cnt_l) begin				
        if(end_cnt_l)						
            cnt_l <= 'd0;  				
        else									
            cnt_l <= cnt_l + 1'b1;		
    end											
assign add_cnt_l = tx_din_vld ;
assign end_cnt_l = add_cnt_l && cnt_l == 15 - 1 ;

assign tx_din_vld = tx_ready && flag ;

always @(*) begin
    case (cnt_l)
        0   :   tx_din = 8'hCE;
        1   :   tx_din = 8'hC2;
        2   :   tx_din = 8'hB6;
        3   :   tx_din = 8'hC8;
        4   :   tx_din = ":";
        5   :   tx_din = sign?"-":"+";
        6   :   tx_din = display_data[20+:4] + "0";
        7   :   tx_din = display_data[16+:4] + "0";
        8   :   tx_din = ".";
        9   :   tx_din = display_data[12+:4] + "0";
        10  :   tx_din = display_data[8+:4]  + "0";
        11  :   tx_din = display_data[4+:4]  + "0";
        12  :   tx_din = display_data[0+:4]  + "0";
        13  :   tx_din =8'hA1;
        14  :   tx_din =8'hE6;
        default: ;
    endcase
end

endmodule
// binary2bcd #(.binary_width(5),.bcd_width(8)) binary2bcd_inst(
//     /*input                               */.sys_clk     (sys_clk),
//     /*input                               */.sys_rst_n   (sys_rst_n),
//     /*input       [binary_width - 1 : 0]  */.binary      (),
//     /*input                               */.binary_vliad(),
//     /*output  reg [bcd_width - 1 : 0]     */.bcd         (),
//     /*output  reg                         */.bcd_vliad   ()
// );

module binary2bcd #(
        parameter binary_width = 5,
        parameter bcd_width = 8
    )(
    input                               sys_clk     ,
    input                               sys_rst_n   ,
    input       [binary_width - 1 : 0]  binary      ,
    input                               binary_vliad,
    output  reg [bcd_width - 1 : 0]     bcd         ,
    output  reg                         bcd_vliad   
);

parameter  SHIFT_MAX = binary_width;   //移位次数与二进制的位宽相等

parameter   IDLE    =   3'b001,
            SHIFT   =   3'b010,
            DONE    =   3'b100;

reg     [2:0]   state;

/* 6个BCD编码,对应输出的BCD编码 */
reg     [3:0]   bcd_data0,bcd_data1,bcd_data2,bcd_data3,bcd_data4,bcd_data5;
wire    [3:0]   bcd_temp0,bcd_temp1,bcd_temp2,bcd_temp3,bcd_temp4,bcd_temp5;


//移位次数控制
reg     [binary_width - 1 : 0]  shift_cnt;  //移位的次数,与二进制的位宽相同,可以保证位宽足够使用 
wire                            add_shift_cnt,end_shift_cnt;  
always@(posedge sys_clk or negedge sys_rst_n)
    if(!sys_rst_n)
        shift_cnt <= 'd0;
    else    if(add_shift_cnt) begin
        if(end_shift_cnt)
            shift_cnt <= 'd0;
        else
            shift_cnt <= shift_cnt + 1'b1;
    end

assign add_shift_cnt = state == SHIFT;
assign end_shift_cnt = add_shift_cnt && shift_cnt == SHIFT_MAX - 1;     //达到最大的移位次数

/* 状态机 */
always@(posedge sys_clk or negedge sys_rst_n)
    if(!sys_rst_n)
        state <= IDLE;
    else    case(state)
        IDLE    :   if(binary_vliad == 1'b1)
                        state <= SHIFT;
        SHIFT   :   if(end_shift_cnt)  //达到最大的移位次数
                        state <= DONE;
        DONE    :       state <= IDLE;
        default :       state <= IDLE;
    endcase

//二进制数据移位
reg     [binary_width - 1 : 0]  shitf_data;  
always@(posedge sys_clk or negedge sys_rst_n)
    if(!sys_rst_n)
        shitf_data <= 'd0;
    else    if(state == SHIFT)  //处于移位状态时,每个时钟左移对应计数值
        shitf_data <= shitf_data << 1'b1;
    else                        //其他状态,保持最新的二进制数据
        shitf_data <= binary;

always@(posedge sys_clk or negedge sys_rst_n)
    if(!sys_rst_n) begin
        bcd_data0 <= 4'd0;
        bcd_data1 <= 4'd0;
        bcd_data2 <= 4'd0;
        bcd_data3 <= 4'd0;
        bcd_data4 <= 4'd0;
        bcd_data5 <= 4'd0;
    end
    else    if(state == SHIFT) begin
        bcd_data0 <= {bcd_temp0[2:0],shitf_data[binary_width - 1]};     //更新二进制位宽的最高一位
        bcd_data1 <= {bcd_temp1[2:0],bcd_temp0[3]};     //保存上一个BCD缓冲区溢出的一位     
        bcd_data2 <= {bcd_temp2[2:0],bcd_temp1[3]};     //保存上一个BCD缓冲区溢出的一位
        bcd_data3 <= {bcd_temp3[2:0],bcd_temp2[3]};     //保存上一个BCD缓冲区溢出的一位
        bcd_data4 <= {bcd_temp4[2:0],bcd_temp3[3]};     //保存上一个BCD缓冲区溢出的一位
        bcd_data5 <= {bcd_temp5[2:0],bcd_temp4[3]};     //保存上一个BCD缓冲区溢出的一位    
    end
    else begin
        bcd_data0 <= 4'd0;
        bcd_data1 <= 4'd0;
        bcd_data2 <= 4'd0;
        bcd_data3 <= 4'd0;
        bcd_data4 <= 4'd0;
        bcd_data5 <= 4'd0;
    end

//如果当前的BCD缓冲区的数据大于4,就会将该缓冲区的数据加3
assign bcd_temp0 = (bcd_data0 > 4'd4)? (bcd_data0 + 4'd3) : bcd_data0;
assign bcd_temp1 = (bcd_data1 > 4'd4)? (bcd_data1 + 4'd3) : bcd_data1;
assign bcd_temp2 = (bcd_data2 > 4'd4)? (bcd_data2 + 4'd3) : bcd_data2;
assign bcd_temp3 = (bcd_data3 > 4'd4)? (bcd_data3 + 4'd3) : bcd_data3;
assign bcd_temp4 = (bcd_data4 > 4'd4)? (bcd_data4 + 4'd3) : bcd_data4;
assign bcd_temp5 = (bcd_data5 > 4'd4)? (bcd_data5 + 4'd3) : bcd_data5;

//BCD编码数据输出
always@(posedge sys_clk or negedge sys_rst_n)
    if(!sys_rst_n)
        bcd <= 'd0;
    else    if(state == DONE)
        bcd <= {bcd_data5,bcd_data4,bcd_data3,bcd_data2,bcd_data1,bcd_data0};

//输出一个时钟周期的有效信号
always@(posedge sys_clk or negedge sys_rst_n)
    if(!sys_rst_n)
        bcd_vliad <= 1'b0;
    else    if(state == DONE)
        bcd_vliad <= 1'b1;
    else
        bcd_vliad <= 1'b0;

endmodule
2.3 其余模块设计

2.4 顶层模块设计
module top(
    input           clk          ,
    input           rst_n        ,
    inout           dq           ,
    output  [7:0]   seg_out      ,
    output  [5:0]   sel          ,
    output          tx_dout 
);
wire    [21:0]   temp_data     ;
wire             temp_data_vld ;
wire    [23:0]   display_data  ;
wire             tx_ready      ;
wire    [7:0]    tx_din        ;
wire             tx_din_vld    ;
wire             sign          ;

DS18B20_drive   DS18B20_drive_inst (
    /* input              */  .clk          (clk          ),
    /* input              */  .rst_n        (rst_n        ),
    /* inout   	          */  .dq           (dq           ),
    /* output      [21:0] */  .temp_data    (temp_data    ),
    /* output             */  .sign         (sign         ),
    /* output  reg        */  .temp_data_vld(temp_data_vld)
);

seg_d#(.CNT_MAX (100_000))seg_d
(
/*     input             */.clk          (clk  )          ,
/*     input             */.rst_n        (rst_n)          ,
/*     input     [24:0]  */.display_data (display_data)   ,
/*     input             */.display_vld  (1)              ,
/*     input      [5:0]  */.display_point(6'b010000)      ,
/*     output     [5:0]  */.sel          (sel)            ,
/*     input      [5:0]  */.display_mask (6'b111111)      ,//数码管掩码,高电平表示数码管显示
/*     output  [7:0]     */.seg_out      (seg_out)
);

uart_tx #(
    .CLK_FREQ(50_000_000),
    .BPS     (115200    ),
    .CHECK   ("NONE"    ) 
)uart_tx_inst(
    /* input          */  .clk       (clk       )  ,
    /* input          */  .rst_n     (rst_n     )  ,
    /* input    [7:0] */  .tx_din    (tx_din    )  ,
    /* input          */  .tx_din_vld(tx_din_vld)  ,
    /* output         */  .tx_ready  (tx_ready  )  ,
    /* output   reg   */  .tx_dout   (tx_dout   )  
);

ctrl ctrl_inst(
    /* input             */   .clk          (clk          )   ,
    /* input             */   .rst_n        (rst_n        )   ,
    /* input      [21:0] */   .temp_data    (temp_data    )   ,
    /* input             */   .sign         (sign         )   ,
    /* input  reg        */   .temp_data_vld(temp_data_vld)   , 
    /* input             */   .tx_ready     (tx_ready     )   ,
    /* output reg [7:0]  */   .tx_din       (tx_din       )   ,
    /* output            */   .tx_din_vld   (tx_din_vld   )   ,
    /* output     [23:0] */   .display_data (display_data )   
);

endmodule

3.仿真测试

3.1 仿真测试代码
`timescale 1ns/1ps
module  ds18b20_drive_tb();

parameter CLK_CYCLE = 20;
reg	sys_clk,sys_rst_n;

always #(CLK_CYCLE/2) sys_clk = ~sys_clk;
initial begin
    sys_clk = 1'b1;
    sys_rst_n = 1'b0;
    #(CLK_CYCLE*2);
    sys_rst_n = 1'b1;
end

wire    dq;
pullup(dq);

DS18B20_drive DS18B20_drive_inst(
    /* input              */  .clk          (sys_clk      ),
    /* input              */  .rst_n        (sys_rst_n    ),
    /* inout   	          */  .dq           (dq           ),
    /* output      [21:0] */  .temp_data    (),
    /* output             */  .sign         (),
    /* output  reg        */  .temp_data_vld()
);

ds18b20_model #(
		.SIG_DATA(0      ),//0:正数、1:负数
		.INT_DATA(85     ),//有效输入 -40 ~ +85
		.DEC_DATA(4'b0000) //仅接受4bit-binary输入
)ds18b20_model(
	/* input  */      .Rst_n (sys_rst_n), //
	/* inout  */	  .dq    (dq)  //
);


endmodule
`timescale 1ns/1ps
module top_tb();

parameter CLK_CYCLE = 20;
reg	sys_clk,sys_rst_n;

always #(CLK_CYCLE/2) sys_clk = ~sys_clk;
initial begin
    sys_clk = 1'b1;
    sys_rst_n = 1'b0;
    #(CLK_CYCLE*2);
    sys_rst_n = 1'b1;
end

wire    dq;
pullup(dq);


top top_tb(
    /* input         */   .clk    (sys_clk)      ,
    /* input         */   .rst_n  (sys_rst_n)      ,
    /* inout         */   .dq     (dq     )      ,
    /* output  [7:0] */   .seg_out(       )      ,
    /* output  [5:0] */   .sel    (       )       
);

ds18b20_model #(
		.SIG_DATA(0      ),//0:正数、1:负数
		.INT_DATA(85     ),//有效输入 -40 ~ +85
		.DEC_DATA(4'b0000) //仅接受4bit-binary输入
)ds18b20_model(
	/* input  */      .Rst_n (sys_rst_n), //
	/* inout  */	  .dq    (dq)  //
);


endmodule

3.2 仿真测试图

仿真测试分析:

如图,当仿真串口输入指令8’hBE时,可以观察到DS18B20开始采集温度数据;当仿真串口输入指令8’h44时,可以观察到DS18B20停止采集温度数据;当仿真串口输入指令8’h11时,可以观察到数码管开始显示采集到的温度数据;当仿真串口输入指令8’hff时,可以观察到数码管显示关闭;

4.板级验证

通过串口控制DS18B20板级验证视频

  • 31
    点赞
  • 58
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值