DS18B20

一.、一.内部结构框图

1.管脚图

在这里插入图片描述

2.结构方框图

在这里插入图片描述
其中包括:GND接地引脚,VDD电源引脚,DQ总线(当上拉电阻拉高时为由DQ总线为设备供电,当拉低时则为电容向设备供电),CPP内部供电电容,一个64BIT的ROM,中间结果暂存器(温度传感器,报警高触发器,报警低触发器,配置寄存器,8bitCRC发生器)

二.温度测量

1.温度寄存器格式

由8bit的高八位(其中高5位为符号位),8bit低八位组成
在这里插入图片描述
DS18B20的温度输出数据时在摄氏度下校准的;若是在华氏度下应用的话,可以用查表法或者常规的数据换算。温度数据以一个16位标志扩展二进制补码数的形式存储在温度寄存器中(详见图2)。符号标志位(S)温度的正负极性:正数则S=0,负数则S=1。如果DS18B20被定义为12位的转换精度,温度寄存器中的所有位都将包含有效数据。若为11位转换精度,则bit 0为未定义的。若为10位转换精度,则bit 1和bit 0为未定义的。 若为9位转换精度,则bit 2、bit 1和bit 0为未定义的。表格1为在12位转换精度下温度输出数据与相对应温度之间的关系表
温度/数据对应关系
在这里插入图片描述

2.温度报警

在这里插入图片描述
只与温度寄存器数据的4——11位比较,且该寄存器是非易失性的,在每次温度转换完成后,得到的温度会与定义的温度作比较

3.在外部电源模式下

在这里插入图片描述
由外部电源供电,并且有一个上拉电阻在没有数据传输时将总线拉高
64bitrom
在这里插入图片描述
低8位为分类编码。中间48位为序列号,高8位为冗余校验
DS18B20内存映射
暂存寄存器中的Byte 0和Byte 1分别作为温度寄存器的低字节和高字节。同时这两个字节是只读的。Byte 2和Byte 3作为过温和低温(TH和TL)温度报警寄存器。Byte 4保存着配置寄存器的数据,Byte 5、6、7作为内部使用的字节而保留使用,不可被写入。
在这里插入图片描述
暂存寄存器中的Byte 4包含着配置寄存器;如图8所示。用户通过改变表2中R0和R1的值来配置DS18B20的分辨率。上电默认为R0=1及R1=1(12位分辨率)。需要注意的是,转换时间与分辨率之间是有制约关系的。Bit 7和Bit 0至Bit 4作为内部使用而保留使用,不可被写入。
在这里插入图片描述
在这里插入图片描述
测温流程:
在这里插入图片描述
这里只需要发送复位脉冲,并且跳过ROM指令
在这里插入图片描述
这里只需要温度转换,还有从寄存器中读取温度数据

三.数据时序

1.初始化时序

在这里插入图片描述

2.读写时序

写时序
在这里插入图片描述
写时段有两种情况:“写1”时段和“写0”时段。主设备通过写1时段来向DS18B20中写入逻辑1以及通过写0时段来向DS18B20中写入逻辑0。每个写时段最小必须有60us的持续时间且独立的写时段间至少有1us的恢复时间。两个写时段都是由主设备通过将1-Wire总线拉低来进行初始化。
为了形成写1时段,在将1-Wire总线拉低后,主设备必须在15us之内释放总线。当总线释放后,5kΩ的上拉电阻将总线拉至高。为了形成写0时段,在将1-Wire总线拉低后,在整个时段期间主设备必须一直拉低总线(至少60us)。
在主设备初始化写时段后,DS18B20将会在15us至60us的时间窗口内对总线进行采样。如果总线在采样窗口期间是高电平,则逻辑1被写入DS18B20;若总线是低电平,则逻辑0被写入DS18B20。
读时序
在这里插入图片描述

四.代码设计

1.状态机设计

在这里插入图片描述

2.代码

驱动模块,通过主从状态机实现,主状态机控制整个流程,从状态负责数据的发送接收

/**************************************功能介绍***********************************
Date	: 
Author	: WZY.
Version	: 
Description: ws18d20驱动模块
*********************************************************************************/
    
//---------<模块及端口声名>------------------------------------------------------
module ws18d20_dirver( 
    input 	wire				clk		,
    input 	wire				rst_n	,
    input   wire                flag_ws18d20_dirver,
    output  reg     [23:0]      temp_data,
    output  reg                 temp_data_vld,
    inout   wire                dp   
);								 
//---------<参数定义>--------------------------------------------------------- 
//主状态机参数
localparam M_IDLE = 0,//空闲状态
           M_REST = 1,//发送复位脉冲
           M_RELS = 2,//释放总线15~60us
           M_RACK = 3,//接收存在脉冲
           M_ROMS = 4,//发送跳过ROM指令
           M_CONT = 5,//发送温度转换指令
           M_WAIT = 6,//等待温度转换完成
           M_RCMD = 7,//发送读取温度命令
           M_RTMP = 8;//接收温度数据
//副状态机参数
localparam S_IDLE = 0,//空闲状态等待传输请求
           S_LOW  = 1,//读写前拉低大于1us
           S_SEND = 2,//发送1bit数据,持续59us
           S_SAMP = 3,//接收1bit数据,持续59us
           S_RELS = 4,//时隙间隔,大于1us
           S_DOWN = 5;//一次命令或者数据执行完成
parameter  T_CYC    = 20;
//状态机计数器参数
parameter  REST_T = 480_000,
           RELS_T = 60_000,
           RACK_T = 240_000,
           WAIT_T = 750_000_000;
//从状态机计数器参数
parameter  LOW_T    = 1_000,
           SEND_T   = 60_000,
           SAMP_T   = 60_000,
           S_RELS_T = 1_000;
parameter  RX_RACK_T = 20_000;
parameter  RX_SAMP_T = 12_000;

parameter  SKIP     = 8'hCC,
           CONVER   = 8'h44,
           READ     = 8'hBE;





//---------<内部信号定义>-----------------------------------------------------
//主状态机参数
reg 	[3:0]	cstate_M     ;//现态
reg	    [3:0]	nstate_M     ;//次态

wire            midle2rest;
wire            mrest2rels;
wire            mrels2rack;
wire            mrack2roms;
wire            mrack2idle;
wire            mroms2cont;
wire            mroms2rcmd;
wire            mcont2wait;
wire            mwait2rest;
wire            mrcmd2rtmp;
wire            mrtmp2idle;

reg             flag_S;//跳转使能

//从状态机参数
reg 	[5:0]	cstate_S     ;//现态
reg	    [5:0]	nstate_S     ;//次态

wire            sidle2low;
wire            slow2send;
wire            slow2samp;
wire            ssend2rels;
wire            ssamp2rels;
wire            srels2down;
wire            srels2low;
wire            sdown2idle;

reg         cmd_vld;//跳转使能

//三态门判断
reg             OE         ;
wire            din;
reg             dout;

//数据传输
reg     [7:0]   dict;

//数据接收
reg     [15:0]  recept_data;//接收数据
reg     [10:0]  temp_data_w;//原码
wire    [23:0]  temp_data_r; //数据处理        

//主状态机计数器参数
reg			[25:0]	cnt_num_M	   	;
wire				add_cnt_num_M	;
wire				end_cnt_num_M	;
reg         [25:0]  num_M         ;

//从状态机计数器参数
reg			[25:0]	cnt_num_S	   	;
wire				add_cnt_num_S	;
wire				end_cnt_num_S	;
reg         [25:0]  num_S         ;

reg                 slave_rac   ;//数据输入

//bit计数器参数
reg			[15:0]	cnt_bit	   	;
wire				add_cnt_bit	;
wire				end_cnt_bit	;
reg         [15:0]  num_bit;
reg                 flag_bit;




//****************************************************************
//                      主状态机
//****************************************************************

//第一段:时序逻辑描述状态转移
always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin
        cstate_M <= M_IDLE;
    end 
    else begin 
        cstate_M <= nstate_M;
    end 
end

//第二段:组合逻辑描述状态转移规律和状态转移条件
always @(*) begin
    case(cstate_M)
         M_IDLE :   begin
                        if (midle2rest) begin
                            nstate_M = M_REST;
                        end
                        else begin
                            nstate_M = cstate_M;
                        end
                    end
         M_REST :   begin
                        if (mrest2rels) begin
                            nstate_M = M_RELS;
                        end
                        else begin
                            nstate_M = cstate_M;
                        end
                    end
         M_RELS :   begin
                        if (mrels2rack) begin
                            nstate_M = M_RACK;
                        end
                        else begin
                            nstate_M = cstate_M;
                        end
                    end 
         M_RACK :   begin
                        if (mrack2roms) begin
                            nstate_M = M_ROMS;
                        end
                        else if (mrack2idle) begin
                            nstate_M = M_IDLE;
                        end
                        else begin
                            nstate_M = cstate_M;
                        end
                    end
         M_ROMS :   begin
                        if (mroms2cont) begin
                            nstate_M = M_CONT;
                        end
                        else if (mroms2rcmd) begin
                            nstate_M = M_RCMD;
                        end
                        else begin
                            nstate_M = cstate_M;
                        end
                    end
         M_CONT :   begin
                        if (mcont2wait) begin
                            nstate_M = M_WAIT;
                        end
                        else begin
                            nstate_M = cstate_M;
                        end
                    end
         M_WAIT :   begin
                        if (mwait2rest) begin
                            nstate_M = M_REST;
                        end
                        else begin
                            nstate_M = cstate_M;
                        end
                    end
         M_RCMD :   begin
                        if (mrcmd2rtmp) begin
                            nstate_M = M_RTMP;
                        end
                        else begin
                            nstate_M = cstate_M;
                        end
                    end
         M_RTMP :   begin
                        if (mrtmp2idle) begin
                            nstate_M = M_IDLE;
                        end
                        else begin
                            nstate_M = cstate_M;
                        end
                    end
        default : nstate_M = M_IDLE;
    endcase
end

assign midle2rest = cstate_M == M_IDLE && flag_ws18d20_dirver;//主机上电后自动进入复位状态
assign mrest2rels = cstate_M == M_REST && end_cnt_num_M;//复位脉冲计数480us后跳转
assign mrels2rack = cstate_M == M_RELS && end_cnt_num_M;//释放总线
assign mrack2roms = cstate_M == M_RACK && end_cnt_num_M && (slave_rac == 0);//接收存在脉冲
assign mrack2idle = cstate_M == M_RACK && end_cnt_num_M ;//未接收到存在脉冲
assign mroms2cont = cstate_M == M_ROMS && sdown2idle&&(flag_S == 0);//发送完8bit数据指令
assign mroms2rcmd = cstate_M == M_ROMS && sdown2idle&&(flag_S == 1);//发送完8bit数据指令
assign mcont2wait = cstate_M == M_CONT && sdown2idle;//发送完8bit数据指令
assign mwait2rest = cstate_M == M_WAIT && end_cnt_num_M;
assign mrcmd2rtmp = cstate_M == M_RCMD && sdown2idle;//发送完8bit数据指令
assign mrtmp2idle = cstate_M == M_RTMP && sdown2idle;//接收完16bit温度数据

            
//第三段:描述输出,时序逻辑或组合逻辑皆可

//****************************************************************
//                  从状态机
//****************************************************************

//第一段:时序逻辑描述状态转移
always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin
        cstate_S <= S_IDLE;
    end 
    else begin 
        cstate_S <= nstate_S;
    end 
end

//第二段:组合逻辑描述状态转移规律和状态转移条件
always @(*) begin
    case(cstate_S)
        S_IDLE :  begin
                    if (sidle2low) begin
                        nstate_S =  S_LOW;
                    end
                    else begin
                        nstate_S = cstate_S;
                    end
                end
        S_LOW  :  begin
                    if (slow2send) begin
                        nstate_S =  S_SEND;
                    end
                    else if (slow2samp) begin
                        nstate_S = S_SAMP;
                    end
                    else begin
                        nstate_S = cstate_S;
                    end
                end
        S_SEND :  begin
                    if (ssend2rels) begin
                        nstate_S =  S_RELS;
                    end
                    else begin
                        nstate_S = cstate_S;
                    end
                end
        S_SAMP :  begin
                    if (ssamp2rels) begin
                        nstate_S =  S_RELS;
                    end
                    else begin
                        nstate_S = cstate_S;
                    end
                end
        S_RELS :  begin
                    if (srels2down) begin
                        nstate_S =  S_DOWN;
                    end
                    else if (srels2low) begin
                        nstate_S = S_LOW;
                    end
                    else begin
                        nstate_S = cstate_S;
                    end
                end
        S_DOWN :  begin
                    if (sdown2idle) begin
                        nstate_S =  S_IDLE;
                    end
                    else begin
                        nstate_S = cstate_S;
                    end
                end 
        default : ;
    endcase
end
            

assign sidle2low  = cstate_S == S_IDLE && cmd_vld;//主状态机在发送指令或者接收数据状态跳转
assign slow2send  = cstate_S == S_LOW  && end_cnt_num_S && (cstate_M != M_RTMP);//主状态为发送状态
assign slow2samp  = cstate_S == S_LOW  && end_cnt_num_S && (cstate_M == M_RTMP);//主状态为接收状态
assign ssend2rels = cstate_S == S_SEND && end_cnt_num_S;//1bit数据发送完成
assign ssamp2rels = cstate_S == S_SAMP && end_cnt_num_S;//1bit数据发送完成
assign srels2down = cstate_S == S_RELS && end_cnt_num_S && flag_bit;//时隙延迟1us且bit数已经发完
assign srels2low  = cstate_S == S_RELS && end_cnt_num_S;//bit数未发完
assign sdown2idle = cstate_S == S_DOWN && 1;        
//****************************************************************
//                          从状态机跳转使能
//****************************************************************  

always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        cmd_vld <= 0;
    end
    else if (mrack2roms||mroms2cont||mroms2rcmd||mrcmd2rtmp) begin
        cmd_vld <= 1;
    end
    else begin
      cmd_vld <= 0;
    end
end         
            
//****************************************************************
//                  主状态机复用计数器
//****************************************************************

always @(posedge clk or negedge rst_n)begin 
   if(!rst_n)begin
        cnt_num_M <= 'd0;
    end 
    else if(add_cnt_num_M)begin 
        if(end_cnt_num_M)begin 
            cnt_num_M <= 'd0;
        end
        else begin 
            cnt_num_M <= cnt_num_M + 1'b1;
        end 
    end
end 

assign add_cnt_num_M =( cstate_M == M_REST)||( cstate_M == M_RELS)||( cstate_M == M_RACK)||(cstate_M == M_WAIT);
assign end_cnt_num_M = add_cnt_num_M && cnt_num_M == num_M-1;

always @(*) begin
    case (cstate_M)
       M_REST : num_M = REST_T/T_CYC;
       M_RELS : num_M = RELS_T/T_CYC;
       M_RACK : num_M = RACK_T/T_CYC;
       M_WAIT : num_M = WAIT_T/T_CYC;
        default: num_M = 0;
    endcase
end
//****************************************************************
//              从状态机复用计数器
//****************************************************************
always @(posedge clk or negedge rst_n)begin 
   if(!rst_n)begin
        cnt_num_S <= 'd0;
    end 
    else if(add_cnt_num_S)begin 
        if(end_cnt_num_S)begin 
            cnt_num_S <= 'd0;
        end
        else begin 
            cnt_num_S <= cnt_num_S + 1'b1;
        end 
    end
end 

assign add_cnt_num_S =( cstate_S == S_LOW)||( cstate_S == S_SEND)||( cstate_S == S_SAMP)||(cstate_S == S_RELS);
assign end_cnt_num_S = add_cnt_num_S && cnt_num_S == num_S-1;

always @(*) begin
    case (cstate_S)
       S_LOW  : num_S = LOW_T   / T_CYC;
       S_SEND : num_S = SEND_T  / T_CYC;
       S_SAMP : num_S = SAMP_T  / T_CYC;
       S_RELS : num_S = S_RELS_T/ T_CYC;
        default: num_S = 0;
    endcase
end

//****************************************************************
//              存在脉冲检测
//****************************************************************
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        slave_rac <= 1;
    end
    else if (cstate_M == M_REST) begin//每次发送复位脉冲时复位信号
        slave_rac <= 1;
    end
    else if (cstate_M == M_RACK && slave_rac == 1) begin//未检测到存在脉冲就一直取样
        slave_rac <= dp;
    end
end

//****************************************************************
//                      flag使能
//****************************************************************

always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        flag_S <= 0;
    end
    else if (mwait2rest) begin
        flag_S <= 1;
    end
    else if (mrtmp2idle) begin
        flag_S <= 0;
    end
end

//****************************************************************
//                  bit计数器
//****************************************************************

always @(posedge clk or negedge rst_n)begin 
   if(!rst_n)begin
        cnt_bit <= 'd0;
    end 
    else if(add_cnt_bit)begin 
        if(end_cnt_bit)begin 
            cnt_bit <= 'd0;
        end
        else begin 
            cnt_bit <= cnt_bit + 1'b1;
        end 
    end
end 

assign add_cnt_bit = ssend2rels||ssamp2rels;
assign end_cnt_bit = add_cnt_bit && cnt_bit == num_bit - 1;

always @(*) begin
    case (cstate_M)
        M_ROMS,M_CONT,M_RCMD: num_bit = 8;
        M_RTMP : num_bit = 16;
        default: num_bit = 1; 
    endcase
end

always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        flag_bit <= 0;
    end
    else if (end_cnt_bit) begin
        flag_bit <= 1;
    end
    else if (sdown2idle) begin
        flag_bit <= 0;
    end
end
//****************************************************************
//                      三态门使能
//****************************************************************

assign  din = dp;
assign  dp = OE?dout:1'bz;

always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        OE  <= 1;
    end
    else if (midle2rest||mrack2roms||mroms2cont||mwait2rest||mroms2rcmd||sidle2low||srels2low||slow2send ) begin
        OE <= 1;
    end
    else if (mrest2rels||mcont2wait||slow2samp||ssend2rels) begin
        OE <= 0 ;
    end
    else begin
      OE <= OE;
    end
end

//****************************************************************
//              信号发送
//****************************************************************             
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        dout <= 0;
    end
    else if (midle2rest||mwait2rest||sidle2low||srels2low) begin
        dout <= 0;
    end
    else if (slow2send) begin
        dout <= dict[cnt_bit];
    end
end
//****************************************************************
//             指令数据
//****************************************************************
always @(*) begin
    case (cstate_M)
        M_ROMS :   dict =  SKIP  ;
        M_CONT :   dict =  CONVER;
        M_RCMD :   dict =  READ  ; 
        default: dict = 8'h00;
    endcase
end

//****************************************************************
//          数据接收
//****************************************************************
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        recept_data <= 16'd0;
    end
    else if ((cstate_S == S_SAMP) && (cnt_num_S == RX_SAMP_T/T_CYC)) begin
        recept_data[cnt_bit] <= dp  ;
    end
end

//****************************************************************
//                      数据处理
//****************************************************************
//原码处理
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        temp_data_w <= 11'b0;
    end
    else if ((cstate_S == S_SAMP)&&ssamp2rels) begin
        if (recept_data[15]) begin
            temp_data_w <= ~recept_data[10:0] + 1;//负数的原码等于补码处符号位取反+1
        end
        else begin
            temp_data_w <= recept_data[10:0];//正数补码等于原码
        end
    end
end
assign temp_data_r = temp_data_w*625;//10000*0.0625
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        temp_data <= 24'd0;
    end
    else if ((cstate_M == M_RTMP)&&srels2down) begin
        temp_data <= temp_data_r;
    end
end

//****************************************************************
//                  数据发送有效信号(脉冲信号)
//****************************************************************
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        temp_data_vld <= 0;
    end
    else if ((cstate_M == M_RTMP)&&srels2down) begin
        temp_data_vld <= 1;
    end
    else begin
      temp_data_vld <= 0;
    end
end
endmodule

数据处理

/**************************************功能介绍***********************************
Date	: 
Author	: WZY.
Version	: 
Description: 
*********************************************************************************/
    
//---------<模块及端口声名>------------------------------------------------------
module ws18d20_ctrl( 
    input 	wire				clk		,
    input 	wire				rst_n	,
    input   wire    [23:0]      temp_data,
    input   wire                temp_data_vld,
    output  wire    [23:0]      data_out
);								 
//---------<参数定义>--------------------------------------------------------- 
reg     [23:0]   data_in;//数据寄存寄存器
reg     [11:0]   data_int;
reg     [15:0]   data_dot;
wire     [3:0]   data_int_w0;
wire     [3:0]   data_int_w1;
wire     [3:0]   data_int_w2;
wire     [3:0]   data_dot_w0;
wire     [3:0]   data_dot_w1;
wire     [3:0]   data_dot_w2;
reg              temp_data_vld_0;
reg              temp_data_vld_1;
//---------<内部信号定义>-----------------------------------------------------
    
//****************************************************************
//                  数据寄存
//****************************************************************  
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        data_in <= 24'd0;
    end
    else if (temp_data_vld) begin
        data_in <= temp_data;
    end
    else begin
      data_in <= data_in;
    end
end
//****************************************************************
//                  打拍
//****************************************************************
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        temp_data_vld_0 <= 0;
        temp_data_vld_1 <= 0;
    end
    else begin
        temp_data_vld_0 <= temp_data_vld;
        temp_data_vld_1 <= temp_data_vld_0;
    end     
end
//****************************************************************
//                  数据处理
//****************************************************************
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        data_int <= 12'd123;
    end
    else if (temp_data_vld_1) begin
        data_int <= data_in/10000;
    end
end

always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        data_dot <= 12'd123;
    end
    else if (temp_data_vld_1) begin
        data_dot <= data_in%10000;
    end
end

// assign data_int    = data_in/10000;
assign data_int_w0 = data_int/100;
assign data_int_w1 = data_int%100/10;
assign data_int_w2 = data_int%10;

// assign data_dot    = data_in%10000;
assign data_dot_w0 = data_dot/1000;
assign data_dot_w1 = data_dot%1000/100;
assign data_dot_w2 = data_dot%100/10;

assign data_out    = {data_int_w0,data_int_w1,data_int_w2,data_dot_w0,data_dot_w1,data_dot_w2};
   
endmodule

使能模块

/**************************************功能介绍***********************************
Date	: 
Author	: WZY.
Version	: 
Description: 
*********************************************************************************/
    
//---------<模块及端口声名>------------------------------------------------------
module flag_enable( 
    input 	wire				clk		,
    input 	wire				rst_n	,
    input   wire    [7:0]       rx_data ,
    input   wire                rx_data_vld,
    output  wire                flag_ws18d20_dirver,
    output  wire    [5:0]       seg_mask,
    output  wire                flag_ctrl      

);								 
//---------<参数定义>--------------------------------------------------------- 
reg     [7:0]   data_in;
reg     [5:0]   seg_mask_r;
reg             flag_ws18d20_dirver_r;
reg             flag_ctrl_r;
//---------<内部信号定义>-----------------------------------------------------

//****************************************************************
//              数据寄存
//****************************************************************
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        data_in <= 8'd0;
    end
    else if (rx_data_vld) begin
        data_in <= rx_data;
    end
end


//****************************************************************
//              控制数码管两灭
//****************************************************************

always @(posedge clk  or negedge rst_n) begin
    if (!rst_n) begin
        seg_mask_r <= 6'b111111;
    end
    else if (data_in == 8'hAA|| data_in == 8'hEE) begin
        seg_mask_r <= 6'b000000;
    end
    else if (data_in == 8'hAB|| data_in == 8'hEF) begin
        seg_mask_r <= 6'b111111;
    end
end

assign  seg_mask = seg_mask_r;
    
//****************************************************************
//控制ws18d20是否传输数据
//****************************************************************
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        flag_ws18d20_dirver_r <= 1;
    end
    else if (data_in == 8'hBB|| data_in == 8'hEE) begin
        flag_ws18d20_dirver_r <= 0;
    end
    else if (data_in == 8'hBC|| data_in == 8'hEF) begin
        flag_ws18d20_dirver_r <= 1;
    end
end
assign flag_ws18d20_dirver = flag_ws18d20_dirver_r;

//****************************************************************
//控制串口发送
//****************************************************************
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
       flag_ctrl_r <= 1; 
    end
    else if (data_in == 8'hCC|| data_in == 8'hEE) begin
        flag_ctrl_r <= 0;
    end
    else if (data_in == 8'hCE|| data_in == 8'hEF) begin
        flag_ctrl_r <= 1;
    end
end
assign flag_ctrl = flag_ctrl_r;
endmodule

数码管模块

/**************************************************************
                        6位数码管驱动模块
date:2022/7/13
author:WangHaodong
note:C4开发板使用的是共阳的数码管
**************************************************************/
/* 例化模板 */
// seg_drive seg_drive_inst(
//     /*input               */.sys_clk      (sys_clk),
//     /*input               */.sys_rst_n    (sys_rst_n),
//     /*input       [5:0]   */.seg_mask     (6'b111111),   //数码管掩码,高电平设置对应数码管有效
//     /*input       [23:0]  */.display_data (),   //{4'd0,4'd0,4'd0,4'd0,4'd0,4'd0}
//     /*input       [5:0]   */.display_point(),    //高电平有效
//     /*output  reg [5:0]   */.seg_sel      (seg_sel),
//     /*output      [7:0]   */.seg_dig      (seg_dig)
// );

/*  配合以下约束内容使用
#数码管选段
set_location_assignment PIN_B7 -to seg_dig[0]
set_location_assignment PIN_A8 -to seg_dig[1]
set_location_assignment PIN_A6 -to seg_dig[2]
set_location_assignment PIN_B5 -to seg_dig[3]
set_location_assignment PIN_B6 -to seg_dig[4]
set_location_assignment PIN_A7 -to seg_dig[5]
set_location_assignment PIN_B8 -to seg_dig[6]
set_location_assignment PIN_A5 -to seg_dig[7]

#数码管片选
set_location_assignment PIN_A4 -to seg_sel[5]
set_location_assignment PIN_B4 -to seg_sel[4]
set_location_assignment PIN_A3 -to seg_sel[3]
set_location_assignment PIN_B3 -to seg_sel[2]
set_location_assignment PIN_A2 -to seg_sel[1]
set_location_assignment PIN_B1 -to seg_sel[0]
*/



module seg_drive(
    input               sys_clk      ,
    input               sys_rst_n    ,
    input       [5:0]   seg_mask     ,   //数码管掩码,1有效
    input       [23:0]  display_data ,   //{4'd0,4'd0,4'd0,4'd0,4'd0,4'd0}
    input       [5:0]   display_point,   //高电平有效
    output  reg [5:0]   seg_sel      ,
    output      [7:0]   seg_dig       
);

parameter   NUM_0 = 7'b100_0000,
            NUM_1 = 7'b111_1001,
            NUM_2 = 7'b010_0100,
            NUM_3 = 7'b011_0000,
            NUM_4 = 7'b001_1001,
            NUM_5 = 7'b001_0010,
            NUM_6 = 7'b000_0010,
            NUM_7 = 7'b111_1000,
            NUM_8 = 7'b000_0000,
            NUM_9 = 7'b001_0000,
            A     = 7'b000_1000,//
            B     = 7'b000_0011,//b
            C     = 7'b100_0110,//
            D     = 7'b010_0001,//d
            E     = 7'b000_0110,//
            F     = 7'b000_1110;//


//显示数据与小数点
reg     [6:0]   seg_data    ;
reg             seg_point   ;

//2ms   余晖效应
parameter   CNT_2MS = 20'd1_000_00;
reg	    [19:0]  cnt_2ms;				
wire		    add_2ms_cnt,end_2ms_cnt;	
always@(posedge sys_clk or negedge sys_rst_n)	
    if(!sys_rst_n)								
        cnt_2ms <= 'd0;						
    else    if(add_2ms_cnt) begin				
        if(end_2ms_cnt)						
            cnt_2ms <= 'd0;  				
        else									
            cnt_2ms <= cnt_2ms + 1'b1;		
    end

assign add_2ms_cnt = 1'b1;
assign end_2ms_cnt = add_2ms_cnt && cnt_2ms == CNT_2MS - 1;  											

//位选
reg	    [5:0] cnt_sel;			
wire		  add_sel_cnt,end_sel_cnt;	
always@(posedge sys_clk or negedge sys_rst_n)	
    if(!sys_rst_n)								
        cnt_sel <= 'd0;						
    else    if(add_sel_cnt) begin				
        if(end_sel_cnt)						
            cnt_sel <= 'd0;  				
        else									
            cnt_sel <= cnt_sel + 1'b1;		
    end		

assign  add_sel_cnt = end_2ms_cnt;
assign  end_sel_cnt = add_sel_cnt && cnt_sel == 6 - 1;							

reg     [3:0]   display_reg;
reg     [6:0]   seg_data_reg;
reg             seg_point_reg;
//数据输出
always@(posedge sys_clk or negedge sys_rst_n)	
    if(!sys_rst_n)
        display_reg <= 4'd0;    /* 默认选择第0个数码管 */
    else    case(cnt_sel)
        6'd0    :   display_reg <= display_data[3:0];
        6'd1    :   display_reg <= display_data[7:4];
        6'd2    :   display_reg <= display_data[11:8];
        6'd3    :   display_reg <= display_data[15:12];
        6'd4    :   display_reg <= display_data[19:16];
        6'd5    :   display_reg <= display_data[23:20];
        default :   display_reg <= 4'd0;
    endcase

always@(posedge sys_clk or negedge sys_rst_n)	
    if(!sys_rst_n)
        seg_data_reg <= 7'h7F;   //不亮
    else    case(display_reg)
        6'd0    :   seg_data_reg <= NUM_0;
        6'd1    :   seg_data_reg <= NUM_1;
        6'd2    :   seg_data_reg <= NUM_2;
        6'd3    :   seg_data_reg <= NUM_3;
        6'd4    :   seg_data_reg <= NUM_4;
        6'd5    :   seg_data_reg <= NUM_5;
        6'd6    :   seg_data_reg <= NUM_6;
        6'd7    :   seg_data_reg <= NUM_7;
        6'd8    :   seg_data_reg <= NUM_8;
        6'd9    :   seg_data_reg <= NUM_9;
        6'd10   :   seg_data_reg <= A    ;
        6'd11   :   seg_data_reg <= B    ;
        6'd13   :   seg_data_reg <= D    ;
        6'd15   :   seg_data_reg <= F    ;
        default :   seg_data_reg <= 7'h7F;
    endcase

//小数点输出
always@(posedge sys_clk or negedge sys_rst_n)	
    if(!sys_rst_n)
        seg_point_reg <= 1'b1;   //小数点不亮
    else    case(cnt_sel)
        6'd0    :   seg_point_reg <= !(display_point[0] && seg_mask[0]);
        6'd1    :   seg_point_reg <= !(display_point[1] && seg_mask[1]);
        6'd2    :   seg_point_reg <= !(display_point[2] && seg_mask[2]);
        6'd3    :   seg_point_reg <= !(display_point[3] && seg_mask[3]);
        6'd4    :   seg_point_reg <= !(display_point[4] && seg_mask[4]);
        6'd5    :   seg_point_reg <= !(display_point[5] && seg_mask[5]);
        default :   seg_point_reg <= 1'b1;
    endcase

assign seg_dig = {seg_point_reg,seg_data_reg[6:0]}; /* 拼接小数点和数据 */

//位选输出
always@(posedge sys_clk or negedge sys_rst_n)	
    if(!sys_rst_n)
        seg_sel <= 6'b11_1110;   //默认选择第一个数码管
    else    case(cnt_sel)
        6'd0    :   seg_sel <= ~(6'b00_0001 & seg_mask);
        6'd1    :   seg_sel <= ~(6'b00_0010 & seg_mask);
        6'd2    :   seg_sel <= ~(6'b00_0100 & seg_mask);
        6'd3    :   seg_sel <= ~(6'b00_1000 & seg_mask);
        6'd4    :   seg_sel <= ~(6'b01_0000 & seg_mask);
        6'd5    :   seg_sel <= ~(6'b10_0000 & seg_mask);
        default :   seg_sel <= ~(6'b00_0000 & seg_mask);  //不选择任何的数码管
    endcase

endmodule

串口模块在之前有过再此不做赘述
顶层:

/**************************************功能介绍***********************************
Date	: 
Author	: WZY.
Version	: 
Description: 
*********************************************************************************/
    
//---------<模块及端口声名>------------------------------------------------------
module top
( 
    input   wire			clk     ,
    input   wire			rst_n	,
    inout   wire                        dp      ,
    input   wire                        rx      ,
    output  wire     [5:0]              seg_sel ,
    output  wire     [7:0]              seg_dig ,
    output  wire                        tx
);								 
//---------<参数定义>--------------------------------------------------------- 
wire    [23:0]  temp_data;
wire            temp_data_vld;
wire    [23:0]  data_out;
wire            ready;
wire            tx_data_vld;
wire    [7:0]   tx_data;
wire    [7:0]   rx_data;
wire            rx_data_vld;
wire    [5:0]   seg_mask;
wire            flag_ws18d20_dirver;
wire            flag_ctrl;

//---------<内部信号定义>-----------------------------------------------------
//ws18d20驱动模块
ws18d20_dirver ws18d20_dirver_inst( 
        .clk		    (clk),
        .rst_n	        (rst_n),
        .flag_ws18d20_dirver (flag_ws18d20_dirver),
        .temp_data      (temp_data),
        .temp_data_vld  (temp_data_vld),
        .dp             (dp) 
);  
//数据处理(数码管)
ws18d20_ctrl ws18d20_ctrl_inst( 
        .clk		(clk),
        .rst_n	    (rst_n),
        .temp_data  (temp_data),
        .temp_data_vld(temp_data_vld),
        .data_out   (data_out)
);
//数码管驱动
seg_drive seg_drive_inst(
        .sys_clk      (clk),
        .sys_rst_n    (rst_n),
        .seg_mask     (seg_mask),   //数码管掩码,1有效
        .display_data (data_out),   //{4'd0,4'd0,4'd0,4'd0,4'd0,4'd0}
        .display_point(6'b001000),   //高电平有效
        .seg_sel      (seg_sel),
        .seg_dig      (seg_dig) 
);


tx_ctrl tx_ctrl_inst( 
                .clk		 (clk),
                .rst_n	         (rst_n),
                .temp_data       (temp_data),
                .temp_data_vld   (temp_data_vld),
                .ready           (ready),
                .flag_ctrl       (flag_ctrl),
                .tx_data         (tx_data),
                .tx_data_vld     (tx_data_vld)
);

uart_tx#
(
    .BPS  (115200),
    .CLK_FRE  (50_000_000),
    .CHECK_BIT ("NONE")//NONE 不校验 DDO奇数 EVEN偶数

)uart_tx_inst
( 
                .clk		(clk),
                .rst_n	        (rst_n),
                .tx_data_vld    (tx_data_vld),//数据发送标志
                .tx_data        (tx_data),//发送数据
                .tx             (tx), 
                .ready          (ready)//准备好发送
);   


uart_rx#
(
   .BPS (115200),
   .CLK_FRE (50_000_000),
   .CHECK_BIT ("NONE")//NONE 不校验 DDO奇校验 EVEN偶校验

) uart_rx_inst
( 
    /*input   wire			*/	   .clk		   (clk),
    /*input   wire			*/	   .rst_n	   (rst_n),
    /*input   wire          */                     .rx             (rx),
    /*output  wire          */                     .ready          (),
    /*output  wire     [7:0]*/                     .rx_data        (rx_data),
    /*output  wire          */                     .rx_data_vld    (rx_data_vld)
);	

flag_enable flag_enable_inst( 
                .clk		        (clk),
                .rst_n	                (rst_n),
                .rx_data                (rx_data),
                .rx_data_vld            (1),
                .flag_ws18d20_dirver    (flag_ws18d20_dirver),
                .seg_mask               (seg_mask),
                .flag_ctrl              (flag_ctrl)     

);	
    
endmodule

五.仿真

仿真模型

/* ================================================ *\
Filename           : ds18b20_model.v
Author             : Adolph
Description        : DS18B20仿真模型
Called by          : 
Revision History   : 2023-7-12 12:31:15
Revision           : 1.0
Email              : ***@gmail.com
Company            : AWCloud...Std 
NOTE:
	2023-7-12 15:02:42 v1.0 
		仅考虑正数温度数据的读取,以及分辨率的设计;
		ROM指令只支持8'hCC;
		指令接收错误时,会打印消息,并暂停仿真系统的执行.
	2023-8-22 11:06:50 V1.1
		支持负数温度输入;
		添加弱上拉操作;
		修改最大等待时间支持自定义.
	2023-8-22 17:16:48 V1.2
		负数温度数据显示错乱修正.
	2023-8-23 10:48:09 V1.3
		修正:内部 cnt_bit_tx 未清空,导致第二次读出数据错乱的问题
\* ================================================ */
`timescale 1ns/1ps

module ds18b20_model #(parameter
		SIG_DATA   = 0       	, //0:正数、1:负数
		INT_DATA   = 37      	, //温度数据整数部分,有效输入 -40 ~ +125
		DEC_DATA   = 4'b0000 	, //温度数据小数部分,仅接受4bit-binary输入
		MAX_WAIT   = 750_000//_000  //温度转换等待最长时间 12bit-750ms
	)(
	input       Rst_n , //
	inout 		dq      //
);
//Parameter Declarations
	localparam 
		tRstPluse 	= 24000 	 	, //复位脉冲480us
		tEPulse   	= 10000 	 	, //存在脉冲200us
		tSEND 		= 3000 	 	 	, //数据发送持续时间60us
		tSAMPLE 	= 2000 	 	 	, //采样时间点 40us
		tCONV     	= MAX_WAIT 		; //最大等待750ms

	localparam  //独热码定义状态参数
		IDLE      	= 8'b0000_0001 	, // 空闲状态
		INIT_RST    = 8'b0000_0010 	, // 接收复位脉冲状态
		INIT_EXI    = 8'b0000_0100 	, // 发送存在脉冲状态
		ROM_CMD     = 8'b0000_1000 	, // 接收ROM指令状态
		DS_CMD 		= 8'b0001_0000 	, // 接收功能指令状态
		TX_DATA 	= 8'b0010_0000 	, // 发送数据状态
		WAIT 		= 8'b0100_0000 	, // 温度转换等待状态
		WR_DATA 	= 8'b1000_0000  ; // 修改暂存器内容

	localparam
		CMD_SKIP_ROM = 8'hCC,
		CMD_COVT 	 = 8'h44,
		CMD_WRITE 	 = 8'h4E,
		CMD_READ 	 = 8'hBE;

//Internal wire/reg declarations
	reg      	[63:00]		STC_MACHINE 		; //
	
	wire 					dq_in 				;
	reg                     dq_oe 				; //  
	reg                     dq_out 				; //
	reg      	[01:00]     dq_r 				; //
	wire  					dq_neg,dq_pos 		;
	
	reg 		[07:00] 	Memory [04:00]		; // temperature-2byte 、warning-2byte 、Resolution
	reg         [07:00]     state_c, state_n	; //状态变量声明

	reg                     init_flag 			; //
	reg  					sample_flag 		; //
	reg      	[07:00] 	data_rx_tmp 		; //
	reg      	[31:00]     tDelay				; //
	reg      	[07:00]     data_tx_tmp 		; //	

	reg 		[03:00]		cnt_bit    			; //Counter  
	wire                    add_cnt_bit			; //Counter Enable
	wire                    end_cnt_bit			; //Counter Reset 
	
	reg 		[03:00]		cnt_byte_rx    		; //Counter 
	wire                    add_cnt_byte_rx		; //Counter Enable
	wire                    end_cnt_byte_rx		; //Counter Reset 

	reg 		[03:00]		cnt_bit_tx     		;//Counter  
	wire                    add_cnt_bit_tx 		;//Counter Enable
	wire                    end_cnt_bit_tx 		;//Counter Reset 
	
	reg 		[03:00]		cnt_byte_tx    		; //Counter 
	wire                    add_cnt_byte_tx		; //Counter Enable
	wire                    end_cnt_byte_tx		; //Counter Reset 
	
	wire    	[10:00]    	Original_code 		; //
	wire    	[10:00]    	Inverse_code 		; //
	wire    	[10:00]    	Supplement_code 	; //

	reg 		[15:00]		delay_cnt    		;//Counter  
	wire                    add_delay_cnt		;//Counter Enable
	wire                    end_delay_cnt		;//Counter Reset 

	reg 		[10:00]		cnt_sample    		; //Counter 
	wire                    add_cnt_sample		; //Counter Enable
	wire                    end_cnt_sample		; //Counter Reset 

	reg          [15:00]    cnt_exi    			; //Counter 
	wire                    add_cnt_exi			; //Counter Enable
	wire                    end_cnt_exi			; //Counter Reset 

	reg          [15:00]    cnt_wr_delay     	; //Counter    
	wire                    add_cnt_wr_delay 	; //Counter Enable
	wire                    end_cnt_wr_delay 	; //Counter Reset
	
//Logic Description
	// 生成时钟
	reg 		Clk 	 	;//50MHz
	initial 	Clk = 0 	;
	always #10 Clk = ~Clk 	;

	integer i = 0 ;

	initial begin
		$timeformat(-9,0," ns",15); //精度、小数位数、附带字符串内容、整体最小长度
		i=0;
		repeat(5) begin
			#1;
			case(i)
				0 : begin Memory[0] = 8'h00; end
				1 : begin Memory[1] = 8'h00; end
				2 : begin Memory[2] = 8'h40; end
				3 : begin Memory[3] = 8'h10; end
				4 : begin Memory[4] = 8'h7F; end
				default: ;
			endcase
			i = i + 1;
		end
	end
	
	always @(posedge Clk or negedge Rst_n)begin  
		if(!Rst_n)begin  
			delay_cnt <= 'd0; 
		end  
		else if(add_delay_cnt)begin  
			if(end_delay_cnt)begin  
				delay_cnt <= 'd0; 
			end  
			else begin  
				delay_cnt <= delay_cnt + 1'b1; 
			end  
		end  
		else begin  
			delay_cnt <= 'd0;
		end  
	end //always end
	
	assign add_delay_cnt = ~dq; 
	assign end_delay_cnt = add_delay_cnt && delay_cnt >= tRstPluse; 
	
	always @(posedge Clk or negedge Rst_n)begin  
		if(!Rst_n)begin  
			cnt_sample <= 'd0; 
		end  
		else if(dq_neg)begin
			cnt_sample <= 'd0; 
		end
		else if(add_cnt_sample)begin  
			if(end_cnt_sample)begin  
				cnt_sample <= tSEND; 
			end  
			else begin  
				cnt_sample <= cnt_sample + 1'b1; 
			end  
		end  
		else begin  
			cnt_sample <= 'd0;  
		end  
	end //always end
	
	assign add_cnt_sample = (state_c == ROM_CMD || state_c == DS_CMD || state_c == WR_DATA); 
	assign end_cnt_sample = add_cnt_sample && cnt_sample >= tSEND; 
	
	always @(posedge Clk or negedge Rst_n)begin  
		if(!Rst_n)begin  
			cnt_exi <= 'd0; 
		end  
		else if(add_cnt_exi)begin  
			if(end_cnt_exi)begin  
				cnt_exi <= tEPulse; 
			end  
			else begin  
				cnt_exi <= cnt_exi + 1'b1; 
			end  
		end  
		else begin  
			cnt_exi <= 'd0;  
		end  
	end //always end
	
	assign add_cnt_exi = state_c == INIT_EXI; 
	assign end_cnt_exi = add_cnt_exi && cnt_exi >= tEPulse; 
	
	always @(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)begin  
			cnt_wr_delay <= 'd0; 
		end  
		else if(dq_neg)begin
			cnt_wr_delay <= 'd0; 
		end
		else if(add_cnt_wr_delay)begin  
			if(end_cnt_wr_delay)begin  
				cnt_wr_delay <= tSEND; 
			end  
			else begin  
				cnt_wr_delay <= cnt_wr_delay + 1'b1; 
			end  
		end  
		else begin  
			cnt_wr_delay <= 'd0;  
		end  
	end 		
	assign add_cnt_wr_delay = state_c == TX_DATA; 
	assign end_cnt_wr_delay = add_cnt_wr_delay && cnt_wr_delay >= tSEND; 
	
//三段式状态机
	//第一段设置状态转移空间
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)begin
			state_c <= IDLE;
		end
		else if(init_flag)begin
			state_c = INIT_EXI;
		end
		else begin
			state_c <= state_n;
		end
	end //always end
	
	//第二段、组合逻辑定义状态转移
	always@(*)begin
		case(state_c)
			IDLE    :begin 
				if(1'b1)begin
					state_n = INIT_RST;
				end
				else begin
					state_n = state_c;
				end
			end 
			INIT_RST:begin 
				if(init_flag && dq_pos == 1'b1)begin //检测到主机释放总线才接管总线控制权
					state_n = INIT_EXI;
					$display("%t:  ds18b20.model: Reset  Pulse is received. ",$realtime);
				end 
				else begin 
					state_n = INIT_RST; 
				end 
			end 
			INIT_EXI:begin 
				// #(tEPulse * 20);
				if(end_cnt_exi && dq_neg)begin
					state_n = ROM_CMD;
				end
				else begin
					state_n = state_c;
				end
			end 
			ROM_CMD :begin 
				if(end_cnt_bit)begin
					if(data_rx_tmp == CMD_SKIP_ROM)begin
						state_n = DS_CMD;
						$display("%t:  ds18b20.model: ROM Command received. ",$realtime);
					end
					else begin
						state_n = IDLE;
						#20;
						$display("%t:  ds18b20.model: Error received ROM Command !!! \n ",$realtime);
						$stop(2);
					end
				end
				else begin
					state_n = state_c;
				end
			end 
			DS_CMD 	:begin 
				if(end_cnt_bit)begin
					if(data_rx_tmp == CMD_WRITE)begin
						state_n = WR_DATA;
						$display("%t:  ds18b20.model: Write data Command received. ",$realtime);
					end
					else if(data_rx_tmp == CMD_COVT)begin
						state_n = WAIT;
						$display("%t:  ds18b20.model: Convert Command received. ",$realtime);
					end
					else if(data_rx_tmp == CMD_READ)begin
						state_n = TX_DATA;
						$display("%t:  ds18b20.model: Read data Command received. ",$realtime);
					end
					else begin
						state_n = IDLE;
						#20;
						$display("%t:  ds18b20.model: Error received Function Command !!! \n ",$realtime);
						$stop(0);
					end
				end 
				else begin
					state_n = state_c;
				end
			end 
			TX_DATA :begin //read data				
				if(end_cnt_byte_tx)begin
					state_n = IDLE;
				end
				else begin
					state_n = TX_DATA;
				end
			end 
			WR_DATA :begin //write data
				if(end_cnt_byte_rx)begin
					state_n = IDLE;
					$display("%t:  ds18b20.model: Write data done. ",$realtime);
				end
				else begin
					state_n = state_c;
				end
			end 
			WAIT 	:begin //convert time
				# tDelay;
				$display("%t:  ds18b20.model: Convert time is OK. ",$realtime);
				state_n = IDLE;
			end 
			default: begin
				state_n = IDLE;
			end
		endcase
	end //always end		

	//第三段,定义状态机输出情况,可以时序逻辑,也可以组合逻辑
	always @(posedge Clk or negedge Rst_n)begin 
		if(!Rst_n)begin
			dq_r <= 2'b11;
		end  
		else begin
			dq_r <= {dq_r[0],dq};
		end
	end //always end
	assign dq_pos = ~dq_r[1] & dq_r[0];
	assign dq_neg = dq_r[1] & ~dq_r[0];
	
	always @(posedge Clk or negedge Rst_n)begin 
		if(!Rst_n)begin
			init_flag <= 1'b0;
		end  
		else if(delay_cnt >= tRstPluse)begin //复位脉冲时间满足
			init_flag <= 1'b1;
		end  
		else begin
			init_flag <= 1'b0;
		end
	end //always end

	always @(posedge Clk or negedge Rst_n)begin 
		if(!Rst_n)begin
			data_rx_tmp <= 8'd0;
		end  
		else begin
			data_rx_tmp[cnt_bit] <= (cnt_sample == tSAMPLE) ? dq : data_rx_tmp[cnt_bit];
		end  
	end //always end		

	always @(posedge Clk or negedge Rst_n)begin 
		if(!Rst_n)begin
			sample_flag <= 1'b0;
		end  
		else begin
			sample_flag <= cnt_sample == tSAMPLE;
		end
	end //always end
		
	always @(posedge Clk or negedge Rst_n)begin  
		if(!Rst_n)begin  
			cnt_bit <= 'd0; 
		end  
		else if(init_flag)begin
			cnt_bit <= 'd0; 
		end
		else if(add_cnt_bit)begin  
			if(end_cnt_bit)begin  
				cnt_bit <= 'd0; 
			end  
			else begin  
				cnt_bit <= cnt_bit + 1'b1; 
			end  
		end  
		else begin  
			cnt_bit <= cnt_bit;
		end  
	end //always end
	
	assign add_cnt_bit = (state_c == ROM_CMD || state_c == DS_CMD || state_c == WR_DATA) && sample_flag; 
	assign end_cnt_bit = add_cnt_bit && cnt_bit >= 4'd7; 
	
	always @(posedge Clk or negedge Rst_n)begin  
		if(!Rst_n)begin  
			cnt_byte_rx <= 'd0; 
		end  
		else if(init_flag)begin 
			cnt_byte_rx <= 'd0;
		end
		else if(add_cnt_byte_rx)begin  
			if(end_cnt_byte_rx)begin  
				cnt_byte_rx <= 'd0; 
			end  
			else begin  
				cnt_byte_rx <= cnt_byte_rx + 1'b1; 
			end  
		end  
		else begin  
			cnt_byte_rx <= cnt_byte_rx;  
		end  
	end //always end
	
	assign add_cnt_byte_rx = (state_c == WR_DATA) && end_cnt_bit; 
	assign end_cnt_byte_rx = add_cnt_byte_rx && cnt_byte_rx >= 4'd2; 
	
	always @(*)begin 
		case(Memory[4][6:5])
			0: tDelay = tCONV >> 3;
			1: tDelay = tCONV >> 2;
			2: tDelay = tCONV >> 1;
			3: tDelay = tCONV >> 0;
			default: tDelay = tCONV;
		endcase
	end //always end
	
    //Memory data
	assign Original_code = {INT_DATA[6:0],DEC_DATA[3:0]};
	assign Inverse_code  = ~Original_code;
	assign Supplement_code = Inverse_code + 11'd1;

	always @(posedge Clk )begin 
		if(state_c == WR_DATA && end_cnt_bit)begin //数据写入
			case(cnt_byte_rx)
				0,1: Memory[cnt_byte_rx+2] <= data_rx_tmp;//预警值上下限
				default:Memory[cnt_byte_rx+2] <= {1'b0,data_rx_tmp[6:5],5'h1f};//修改分辨率
			endcase
		end  
		else begin
			if(|SIG_DATA)begin //负数温度数据
				Memory[0] = Supplement_code[07:00];
				Memory[1] = {{5{|SIG_DATA}},Supplement_code[10:08]};
			end
			else begin //正数温度数据
				Memory[0] = Original_code[07:00];
				Memory[1] = {{5{|SIG_DATA}},Original_code[10:08]};
			end
		end
	end //always end
	
	always @(posedge Clk or negedge Rst_n)begin  
		if(!Rst_n)begin  
			cnt_bit_tx <= 'd0; 
		end  
		else if(state_c == INIT_EXI)begin
			cnt_bit_tx <= 'd0; //此处清空,可保证多次数据读取不错乱
		end
		else if(add_cnt_bit_tx)begin  //有效计数范围 1-8
			if(end_cnt_bit_tx)begin  
				cnt_bit_tx <= 'd1; 
			end  
			else begin  
				cnt_bit_tx <= cnt_bit_tx + 1'b1; 
			end  
		end  
	end //always end	
	assign add_cnt_bit_tx = state_c == TX_DATA && dq_neg; 
	assign end_cnt_bit_tx = add_cnt_bit_tx && cnt_bit_tx >= 4'd8; 
	
	always @(posedge Clk or negedge Rst_n)begin  
		if(!Rst_n)begin  
			cnt_byte_tx <= 'd0; 
		end  
		else if(init_flag)begin
			cnt_byte_tx <= 'd0; 
		end
		else if(add_cnt_byte_tx)begin  
			if(end_cnt_byte_tx)begin  
				cnt_byte_tx <= 'd0; 
			end  
			else begin  
				cnt_byte_tx <= cnt_byte_tx + 1'b1; 
			end  
		end  
	end //always end	
	assign add_cnt_byte_tx = end_cnt_bit_tx; 
	assign end_cnt_byte_tx = add_cnt_byte_tx && cnt_byte_tx >= 4'd4; 
	
	// 存在脉冲和数据发送
	always @(posedge Clk or negedge Rst_n)begin 
		if(!Rst_n)begin
			dq_oe <= 1'b0;
			dq_out <= 1'b0;
			data_tx_tmp <= 8'd0;
		end  
		else if(state_c == INIT_EXI && cnt_exi < tEPulse)begin
			dq_oe <= 1'b1; //存在脉冲
			dq_out <= 1'b0;
		end  
		else if(state_c == TX_DATA)begin //发送数据
			data_tx_tmp <= Memory[cnt_byte_tx];
			if(/*cnt_wr_delay >= 100 && */cnt_wr_delay < tSEND && cnt_bit_tx != 0)begin
				dq_oe <= 1'b1; 
				dq_out <= data_tx_tmp[cnt_bit_tx - 1]; 
			end
			else begin
				dq_oe <= 1'b0;
				dq_out <= 1'b0;
			end
		end
		else begin
			dq_oe <= 1'b0;
			dq_out <= 1'b0;
		end
	end //always end
	
	pullup (dq);//设置弱上拉操作
	assign dq = dq_oe ? dq_out : 1'bz;
	assign dq_in = dq;

	// ASCII显示状态机现态变量
	always @(*)begin 
		case(state_c)
			IDLE    :STC_MACHINE = "IDLE    ";
			INIT_RST:STC_MACHINE = "INIT_RST";
			INIT_EXI:STC_MACHINE = "INIT_EXI";
			ROM_CMD :STC_MACHINE = "ROM_CMD ";
			DS_CMD 	:STC_MACHINE = "DS_CMD 	";
			TX_DATA :STC_MACHINE = "TX_DATA ";
			WAIT 	:STC_MACHINE = "WAIT 	";
			WR_DATA :STC_MACHINE = "WR_DATA ";
			default :STC_MACHINE = "IDLE    ";
		endcase
	end //always end

endmodule 

仿真文件

`timescale 1ns/1ns
    
module ws18d20_dirver_tb();

//激励信号定义 
    reg				 clk  	;
    reg				 rst_n	;
    reg              rx ;


//输出信号定义	 
    wire       [23:0]     temp_data;
    wire                  temp_data_vld;
    wire                  dp;
    wire        [5:0]       seg_sel ;
    wire        [7:0]       seg_dig ;
    wire                    tx;
//时钟周期参数定义	
    parameter		 CYCLE = 20; 
pullup(dp);
parameter  T_CYC    = 20;
//状态机计数器参数
// defparam   ws18d20_dirver_inst.REST_T = 480_00,
//            ws18d20_dirver_inst.RELS_T = 60_00,
//            ws18d20_dirver_inst.RACK_T = 240_00,
defparam           top_inst.ws18d20_dirver_inst.WAIT_T = 75_000;
//从状态机计数器参数
// defparam  ws18d20_dirver_inst.LOW_T    = 1000,
//            ws18d20_dirver_inst.SEND_T   = 60_00,
//            ws18d20_dirver_inst.SAMP_T   = 60_00,
//            ws18d20_dirver_inst.S_RELS_T = 1000;
// defparam  ws18d20_dirver_inst.RX_RACK_T = 80_00;
// defparam  ws18d20_dirver_inst.RX_SAMP_T = 30_00; 


// defparam		ds18b20_model_inst.tRstPluse 	= 24 	 	, //复位脉冲480us
// 		        ds18b20_model_inst.tEPulse   	= 10 	 	, //存在脉冲200us
// 		        ds18b20_model_inst.tSEND 		= 30 	 	 	, //数据发送持续时间60us
// 		        ds18b20_model_inst.tSAMPLE 	    = 20 	 	 	, //采样时间点 40us
// 		        ds18b20_model_inst.tCONV     	= 75;//_000 	; //最大等待750ms
//模块例化
// ws18d20_dirver ws18d20_dirver_inst( 
// 		.clk		    (clk),
// 		.rst_n	        (rst_n),
//         .temp_data      (temp_data),
//         .temp_data_vld  (temp_data_vld),
//         .dp             (dp)
// );  

ds18b20_model ds18b20_model_inst(
        .Rst_n (rst_n), //
        .dq    (dp)  //
);

top top_inst
( 
        .clk		(clk),
        .rst_n	    (rst_n),
        .rx         (rx),
        .dp         (dp),
        .tx         (tx),
        .seg_sel    (seg_sel),
        .seg_dig    (seg_dig)            
);	
//产生时钟
    initial 		 clk = 1'b1;
    always #( CYCLE/2)  clk = ~ clk;

//产生激励
    initial  begin 
         rst_n = 1'b1;
        #( CYCLE*2);
         rst_n = 1'b0;
        #( CYCLE*20);
         rst_n = 1'b1;
        #20
        rx = 1  ;
        #(CYCLE*10)
        rx = 0  ;   //开始位发送
        #(CYCLE*10)
        rx = 0  ;   //发送数据1
        #(CYCLE*10)
        rx = 1  ;   //发送数据0
        #(CYCLE*10)
        rx = 0  ;   //发送数据1
        #(CYCLE*10)
        rx = 1  ;   //发送数据0
        #(CYCLE*10)
        rx = 0  ;   //发送数据1
        #(CYCLE*10)
        rx = 1  ;   //发送数据0
        #(CYCLE*10)
        rx = 0  ;   //发送数据1
        #(CYCLE*10)
        rx = 1  ;   //发送数据0
        #(CYCLE*10)
        // rx = 1  ;   //发送标志位0//偶校验
        // #(CYCLE*10)
        rx = 1  ;  //发送结束位
        #100000000;
        $stop;

    end

endmodule 

仿真结果
在这里插入图片描述
串口发送AA表示数码管显示数据

在这里插入图片描述
状态机正常跳转且最后输出正确数据
在这里插入图片描述
数码管显示数据最后只显示五位

六.结果展示

由于器件问题再此不做过多展示,经测试代码是可以正常运行,上板结果正确

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值