DS18B20读取温度实验

一.DS18B20简介

  • DS18B20数字温度传感器提供9-12bit的摄氏温度测量精度和一个用户可编程的非易失性且具有过温和低温报警功能。
  • 采用单总线接口方式通信
  • 每个设备内部ROM上烧写了一个独一无二的序列号
  • 可以由数据线供电而不需要外部电源供电
  • 测量范围在-55℃~125℃
  • 在温度范围超过-10摄氏度至85摄氏度之外时还具有±0.5℃的精度

二.手册解析

1.单总线协议

  • 1-Wire总线系统即一个总线主设备控制一个或多个从设备。DS18B20始终是一个从设备。当总线上只有一个从设备时,此系统被称为“单节点”系统;当总线上有多个从设备连接时,此系统被称之为“多节点”系统。
    1-Wire总线上所有的命令或者数据的发送送都是遵循低位先发送的原则。
    接下来关于1-Wire总线系统的描述将会分成三个部分:硬件配置,事件序列和1-Wire总线信号(信号定义和时序)。

2.DS18B20内部框图

在这里插入图片描述

3.DS118B20供电模式

  • DS18B20可以通过外部电源供电,也可以通过“寄生电源”供电。那么什么是“寄生电源”?
    在这里插入图片描述

上图中模式就是寄生电源模式,结合内部框图来看,DQ拉高时由其向设备供电,总线拉高时为内部电容充电,总线拉低时改由电容向设备供电。
在这里插入图片描述

上图中模式是外接电源模式。这样不需要上拉的MOSFET,单总线在温度转换期间可以执行其他动作。

4.温度数据

  • 两字节共16bit数据存储温度数据,其中bit11-bit15存储符号位S(0为正数,1为负数);bit4-bit10存储整数部分;bit0-bit3存储小数部分(这一部分要考察精度,12位转换精度时,四位小数都会有值;11位转换精度时,bit0为未定义;10位转换精度时,bit0和bit1为未定义;9位转换精度时,bit0、bit1和bit2为未定义)
    在这里插入图片描述

  • 温度/数据关系
    在这里插入图片描述

5.温度报警

  • 过温和低温数据各存在于一个字节(8bit数据)内。我们可以理解为我们设定的一个阈值,与我们传感器测量的温度数据进行比较。其寄存器值如下
    在这里插入图片描述

需要注意的是,过温和低温报警寄存器存储的是整数,所以我们只和温度寄存器的bit4-bit11整数部分比较。

6.64位光刻ROM编码

在这里插入图片描述

  • 64位中,低8位为保存有DS18B20的分类编码:28h。中间的48位中保存着独一无二的序列号。最高8位保存CRC校验值

7.配置寄存器

  • 一字节中两个bit数据定义之前说的转换精度
    在这里插入图片描述

在这里插入图片描述

bit0-bit4和bit7作为内部使用保留,不可被写入。主要考虑其中bit5和bit6,也就是R0和R1的值 [上电默认R0=1,R1=1(12位分辨率)]

8.流程

8.1初始化

  • 需要复位信号和存在脉冲(计时,状态转换条件)
    在这里插入图片描述

8.2ROM命令

在这里插入图片描述

  • 由于我们只有一个DS18B20传感器,所以我们只考虑跳过ROM命令

8.3DS18B20功能命令

  • 这里我们只考虑温度转换命令【44h】和读取暂存器命令【BEh】
    在这里插入图片描述

DS18B20功能命令续在ROM命令完成后开始。完成一次功能命令后,需要回到初始化状态再走一次跳过ROM命令,再进行下一个功能命令。如图中,先走红线,然后再次进入到DS18B20功能命令时走绿线。

9.时隙

  • 写时段有两种情况:“写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。
    在这里插入图片描述

10.状态及状态转移

状态转移图如下,状态解析以及状态转移条件可以参考资源https://download.csdn.net/download/weixin_67803687/88254394
在这里插入图片描述

三.代码

  • DS18B20_driver.v
/**************************************功能介绍***********************************
Date	: 2023年8月21日16:44:25
Author	: Alegg xy.
Version	: 1.0
Description: 
*********************************************************************************/
    
//---------<模块及端口声名>------------------------------------------------------
module DS18B20_driver( 
    input				clk		,
    input				rst_n	,

    output      [23:0]  temp_data,
    output  reg         temp_data_vld,
    output              dout_signed, 
    inout               dq
);								 
//---------<参数定义>--------------------------------------------------------- 
    //主状态机参数定义
    localparam  M_IDLE      = 9'b000000001,//空闲
                M_RST       = 9'b000000010,//复位
                M_RELE      = 9'b000000100,//释放总线
                M_BACK      = 9'b000001000,//接受存在脉冲
                M_SKIP_ROM  = 9'b000010000,//跳过ROM
                M_CON_T     = 9'b000100000,//数据转换命令
                M_WAIT      = 9'b001000000,//等待750ms
                RD_SCRA     = 9'b010000000,//读数据命令
                M_READ      = 9'b100000000;//读出数据

    //从状态机参数定义
    localparam  S_IDLE   = 6'b000001,//空闲状态
                S_LOW    = 6'b000010,//拉低
                S_SEND   = 6'b000100,//发送数据
                S_RECV   = 6'b001000,//接受数据
                S_RELE   = 6'b010000,//释放总线
                S_DONE   = 6'b100000;//完成

    parameter   MAX_500us = 15'd25_000;
    parameter   MAX_20us  = 10'd1_000;
    parameter   MAX_200us = 14'd10_000;
    parameter   MAX_750ms = 26'd37_500_000;
    parameter   MAX_2us   = 7'd100;
    parameter   MAX_60us  = 12'd3000;
    parameter   MAX_3us   = 8'd150;

    localparam  SKIP_ROM  = 8'hCC,//跳过rom指令
                CON_T     = 8'h44,//温度转换指令
                READ_T    = 8'hBE;//读取温度指令

//---------<内部信号定义>-----------------------------------------------------
    reg 	[9:0]	m_cstate     ;//主状态机现态
    reg	    [9:0]	m_nstate     ;//主状态机次态
    reg 	[6:0]	s_cstate     ;//从状态机现态
    reg	    [6:0]	s_nstate     ;//从状态机次态

    reg			[14:0]	cnt_500us	   	;
    wire				add_cnt_500us	;
    wire				end_cnt_500us	;

    reg			[9:0]	cnt_20us	   	;
    wire				add_cnt_20us	;
    wire				end_cnt_20us	;

    reg			[13:0]	cnt_200us	   	;
    wire				add_cnt_200us	;
    wire				end_cnt_200us	;

    reg			[25:0]	cnt_750ms	   	;
    wire				add_cnt_750ms	;
    wire				end_cnt_750ms	;

    reg			[6:0]	cnt_2us	   	;
    wire				add_cnt_2us	;
    wire				end_cnt_2us	;

    reg         [11:0]  cnt_60us        ;
    wire                add_cnt_60us    ;
    wire                end_cnt_60us    ;

    // reg			[7:0]	cnt_3us	   	;
    // wire				add_cnt_3us	;
    // wire				end_cnt_3us	;

    reg			[3:0]	cnt_bit	   	;
    wire				add_cnt_bit	;
    wire				end_cnt_bit	;
    
    reg                 slave_ack   ;//判断是否接收到存在脉冲 —— 0:接受到存在脉冲、1:没有接受到存在脉冲
    reg                 flag        ;//判断命令是什么 —— 0:温度转换命令、1:温度读取命令
    reg                 flag_bit    ;//0:没写完8bit或读完16bit  1:写完8bit或读完16bit

    reg                 OE          ;//三态使能信号
    reg                 dq_out      ;
    wire                dq_in       ;

    reg         [7:0]   cmd         ;//记录命令   
    reg                 cmd_vld     ;//发送命令使能

    reg         [15:0]  rx_data     ;//接收的原始数据
    wire                rx_data_vld ;
    reg         [23:0]  true_data   ;//转补码处理后的温度              

    //主状态机状态转移条件
    wire    M_IDLE_M_RST;
    wire    M_RST_M_RELE;
    wire    M_RELE_M_BACK;
    wire    M_BACK_M_SKIP_ROM;
    wire    M_BACK_M_IDLE;
    wire    M_SKIP_ROM_M_CON_T;
    wire    M_SKIP_ROM_RD_SCRA;
    wire    M_CON_T_M_WAIT;
    wire    M_WAIT_M_RST;
    wire    RD_SCRA_M_READ;
    wire    M_READ_M_IDLE;

    //从状态机状态转移条件
    wire    S_IDLE_S_LOW;
    wire    S_LOW_S_SEND;
    wire    S_LOW_S_RECV;
    wire    S_SEND_S_RELE;
    wire    S_RECV_S_RELE;
    wire    S_RELE_S_LOW;
    wire    S_RELE_S_DONE;
    wire    S_DONE_S_IDLE;

    //500us计数器
    always @(posedge clk or negedge rst_n)begin 
       if(!rst_n)begin
            cnt_500us <= 'd0;
        end 
        else if(add_cnt_500us)begin 
            if(end_cnt_500us)begin 
                cnt_500us <= 'd0;
            end
            else begin 
                cnt_500us <= cnt_500us + 1'd1;
            end 
        end
    end 
    
    assign add_cnt_500us = m_cstate == M_RST;
    assign end_cnt_500us = add_cnt_500us && cnt_500us == MAX_500us - 1'd1;

    //20us计数器    
    always @(posedge clk or negedge rst_n)begin 
       if(!rst_n)begin
            cnt_20us <= 'd0;
        end 
        else if(add_cnt_20us)begin 
            if(end_cnt_20us)begin 
                cnt_20us <= 'd0;
            end
            else begin 
                cnt_20us <= cnt_20us + 1'd1;
            end 
        end
    end 
    
    assign add_cnt_20us = m_cstate == M_RELE;
    assign end_cnt_20us = add_cnt_20us && cnt_20us == MAX_20us - 1'd1;

    //200us计数器
    always @(posedge clk or negedge rst_n)begin 
       if(!rst_n)begin
            cnt_200us <= 'd0;
        end 
        else if(add_cnt_200us)begin 
            if(end_cnt_200us)begin 
                cnt_200us <= 'd0;
            end
            else begin 
                cnt_200us <= cnt_200us + 1'd1;
            end 
        end
    end 
    
    assign add_cnt_200us = m_cstate == M_BACK;
    assign end_cnt_200us = add_cnt_200us && cnt_200us == MAX_200us - 1'd1;

    //750ms计数器
    always @(posedge clk or negedge rst_n)begin 
       if(!rst_n)begin
            cnt_750ms <= 'd0;
        end 
        else if(add_cnt_750ms)begin 
            if(end_cnt_750ms)begin 
                cnt_750ms <= 'd0;
            end
            else begin 
                cnt_750ms <= cnt_750ms + 1'd1;
            end 
        end
    end 
    
    assign add_cnt_750ms = m_cstate == M_WAIT;
    assign end_cnt_750ms = add_cnt_750ms && cnt_750ms == MAX_750ms - 1'd1;

    //2us计数器   
    always @(posedge clk or negedge rst_n)begin 
       if(!rst_n)begin
            cnt_2us <= 'd0;
        end 
        else if(add_cnt_2us)begin 
            if(end_cnt_2us)begin 
                cnt_2us <= 'd0;
            end
            else begin 
                cnt_2us <= cnt_2us + 1'd1;
            end 
        end
    end 
    
    assign add_cnt_2us = s_cstate == S_LOW || s_cstate == S_RELE;
    assign end_cnt_2us = add_cnt_2us && cnt_2us == MAX_2us - 1'd1;

    //60us计数器    
    always @(posedge clk or negedge rst_n)begin 
       if(!rst_n)begin
            cnt_60us <= 'd0;
        end 
        else if(add_cnt_60us)begin 
            if(end_cnt_60us)begin 
                cnt_60us <= 'd0;
            end
            else begin 
                cnt_60us <= cnt_60us + 1'd1;
            end 
        end
    end 
    
    assign add_cnt_60us = s_cstate == S_SEND || s_cstate == S_RECV || m_cstate == M_BACK;
    assign end_cnt_60us = add_cnt_60us && cnt_60us == MAX_60us - 1'd1;

    // //3us计数器    
    // always @(posedge clk or negedge rst_n)begin 
    //    if(!rst_n)begin
    //         cnt_3us <= 'd0;
    //     end 
    //     else if(add_cnt_3us)begin 
    //         if(end_cnt_3us)begin 
    //             cnt_3us <= 'd0;
    //         end
    //         else begin 
    //             cnt_3us <= cnt_3us + 1'd1;
    //         end 
    //     end
    // end 
    
    // assign add_cnt_3us = s_cstate == S_RELE;
    // assign end_cnt_3us = add_cnt_3us && cnt_3us == MAX_3us - 1'd1;

    //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'd1;
            end 
        end
    end 
    
    assign add_cnt_bit = S_SEND_S_RELE || S_RECV_S_RELE;
    assign end_cnt_bit = add_cnt_bit && cnt_bit == (m_cstate == M_READ ? 16 - 1 : 8 - 1);

    //定义flag
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            flag <= 'd0;
        end
        else if (M_WAIT_M_RST) begin
            flag <= 'd1;
        end
        else if (M_READ_M_IDLE) begin
            flag <= 'd0;
        end
    end

    //定义flag_bit
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            flag_bit <= 'b0;
        end
        else if (end_cnt_bit) begin
            flag_bit <= 'b1;
        end
        else if (s_cstate == S_DONE) begin
            flag_bit <= 'b0;
        end
    end

    //定义slave_ack存在脉冲
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            slave_ack <= 'd0;
        end
        else if (m_cstate == M_RST) begin
            slave_ack <= 'd0;
        end
        else if (m_cstate == M_BACK && end_cnt_200us) begin
            slave_ack <= dq;
        end
    end
       
    //主状态机第一段
    always @(posedge clk or negedge rst_n)begin 
        if(!rst_n)begin
            m_cstate <= M_IDLE;
        end 
        else begin 
            m_cstate <= m_nstate;
        end 
    end
    
    //主状态机第二段
    always @(*) begin
        case(m_cstate)
            M_IDLE      : begin
                if (M_IDLE_M_RST) begin
                    m_nstate = M_RST;
                end
                else begin
                    m_nstate = m_cstate;
                end
            end
            M_RST       : begin
                if (M_RST_M_RELE) begin
                    m_nstate = M_RELE;
                end
                else begin
                    m_nstate = m_cstate;
                end
            end
            M_RELE      : begin
                if (M_RELE_M_BACK) begin
                    m_nstate = M_BACK;
                end
                else begin
                    m_nstate = m_cstate;
                end
            end
            M_BACK      : begin
                if (M_BACK_M_SKIP_ROM) begin
                    m_nstate = M_SKIP_ROM;
                end
                else if (M_BACK_M_IDLE) begin
                    m_nstate = M_IDLE;
                end
                else begin
                    m_nstate = m_cstate;
                end
            end
            M_SKIP_ROM  : begin
                if (M_SKIP_ROM_M_CON_T) begin
                    m_nstate = M_CON_T;
                end
                else if (M_SKIP_ROM_RD_SCRA) begin
                    m_nstate = RD_SCRA;
                end
                else begin
                    m_nstate = m_cstate;
                end
            end
            M_CON_T     : begin
                if (M_CON_T_M_WAIT) begin
                    m_nstate = M_WAIT;
                end
                else begin
                    m_nstate = m_cstate;
                end
            end
            M_WAIT      : begin
                if (M_WAIT_M_RST) begin
                    m_nstate = M_RST;
                end
                else begin
                    m_nstate = m_cstate;
                end
            end
            RD_SCRA     : begin
                if (RD_SCRA_M_READ) begin
                    m_nstate = M_READ;
                end
                else begin
                    m_nstate = m_cstate;
                end
            end
            M_READ      : begin
                if (M_READ_M_IDLE) begin
                    m_nstate = M_IDLE;
                end
                else begin
                    m_nstate = m_cstate;
                end
            end
            default : m_nstate = M_IDLE;
        endcase
    end

    assign M_IDLE_M_RST         = (m_cstate == M_IDLE) && 1'b1;    
    assign M_RST_M_RELE         = (m_cstate == M_RST) && end_cnt_500us;//500us
    assign M_RELE_M_BACK        = (m_cstate == M_RELE) && end_cnt_20us;//20us
    assign M_BACK_M_SKIP_ROM    = (m_cstate == M_BACK) && end_cnt_200us && slave_ack == 1'b0;//200us并且接受到存在信号
    assign M_BACK_M_IDLE        = (m_cstate == M_BACK) && end_cnt_200us && slave_ack == 1'b1;//200us并且没接受到存在信号
    assign M_SKIP_ROM_M_CON_T   = (m_cstate == M_SKIP_ROM) && (s_cstate == S_DONE && flag == 0);//发送完跳过rom命令后,发送温度转换命令
    assign M_SKIP_ROM_RD_SCRA   = (m_cstate == M_SKIP_ROM) && (s_cstate == S_DONE && flag == 1);//发送完跳过rom命令后,发送温度读取命令
    assign M_CON_T_M_WAIT       = (m_cstate == M_CON_T) && (s_cstate == S_DONE);//主机发送完8bit的温度转换命令
    assign M_WAIT_M_RST         = (m_cstate == M_WAIT) && end_cnt_750ms;//750ms
    assign RD_SCRA_M_READ       = (m_cstate == RD_SCRA) && (s_cstate == S_DONE);//主机发送完8bit的读取温度命令
    assign M_READ_M_IDLE        = (m_cstate == M_READ) && (s_cstate == S_DONE);//主机收到16bit的温度数据
    
    //从状态机第一段
    always @(posedge clk or negedge rst_n)begin 
        if(!rst_n)begin
            s_cstate <= S_IDLE;
        end 
        else begin 
            s_cstate <= s_nstate;
        end 
    end
    
    //从状态机第二段
    always @(*) begin
        case(s_cstate)
            S_IDLE :begin
                if (S_IDLE_S_LOW) begin
                    s_nstate = S_LOW;
                end

                else begin
                    s_nstate = s_cstate;
                end
            end
            S_LOW  :begin
                if (S_LOW_S_RECV) begin
                    s_nstate = S_RECV;
                end
                else if (S_LOW_S_SEND) begin
                    s_nstate = S_SEND;
                end
                else begin
                    s_nstate = s_cstate;
                end
            end
            S_SEND :begin
                if (S_SEND_S_RELE) begin
                    s_nstate = S_RELE;
                end
                else begin
                    s_nstate = s_cstate;
                end
            end
            S_RECV :begin
                if (S_RECV_S_RELE) begin
                    s_nstate = S_RELE;
                end
                else begin
                    s_nstate = s_cstate;
                end
            end
            S_RELE :begin
                if (S_RELE_S_LOW) begin
                    s_nstate = S_LOW;
                end
                else if (S_RELE_S_DONE) begin
                    s_nstate = S_DONE;
                end
                else begin
                    s_nstate = s_cstate;
                end
            end
            S_DONE:begin
                if (S_DONE_S_IDLE) begin
                    s_nstate = S_IDLE;
                end
                else begin
                    s_nstate = s_cstate;
                end
            end
            S_DONE  :s_nstate = S_IDLE;
            default : s_nstate = S_IDLE;
        endcase
    end
                
    assign S_IDLE_S_LOW  = (s_cstate == S_IDLE) && (m_cstate == M_READ || m_cstate == RD_SCRA || m_cstate == M_SKIP_ROM || m_cstate == M_CON_T);//这四个状态用到发送命令或接收数据开始运转从状态机
    assign S_LOW_S_SEND  = (s_cstate == S_LOW) && (m_cstate == RD_SCRA || m_cstate == M_SKIP_ROM || m_cstate == M_CON_T) && end_cnt_2us;//发送命令的三个主状态机状态,并拉低2us
    assign S_LOW_S_RECV  = (s_cstate == S_LOW) && (m_cstate == M_READ) && end_cnt_2us;//接收数据的主状态机状态,并拉低2us
    assign S_SEND_S_RELE = (s_cstate == S_SEND) && end_cnt_60us;//发送1bit数据用60us
    assign S_RECV_S_RELE = (s_cstate == S_RECV) && end_cnt_60us;//接收1bit数据用60us
    assign S_RELE_S_LOW  = (s_cstate == S_RELE) && end_cnt_2us && flag_bit == 1'b0;//没有写满8bit或读完16bit
    assign S_RELE_S_DONE = (s_cstate == S_RELE) && end_cnt_2us && flag_bit == 1'b1;//写满8bit或读满16bit
    assign S_DONE_S_IDLE = (s_cstate == S_DONE) && 1'b1;

    //定义OE
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            OE <= 'b0;
        end
        else if(M_IDLE_M_RST || M_BACK_M_SKIP_ROM || M_SKIP_ROM_M_CON_T || M_SKIP_ROM_RD_SCRA || S_IDLE_S_LOW || S_RELE_S_LOW || M_WAIT_M_RST) begin
            OE <= 'b1;
        end
        else if (M_RST_M_RELE || M_CON_T_M_WAIT || S_SEND_S_RELE || S_LOW_S_RECV) begin
            OE <= 'b0;
        end
    end            
                
    assign dq = OE ? dq_out : 1'bz;            
    assign dq_in = dq;
    
    //描述cmd
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            cmd <= 8'h00;
        end
        else begin
            case (m_cstate)
                M_SKIP_ROM  : cmd <= SKIP_ROM   ;
                M_CON_T     : cmd <= CON_T      ;
                RD_SCRA     : cmd <= READ_T     ;
                default: cmd <= 8'h00;
            endcase
        end
    end
    
    //描述cmd_vld
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            cmd_vld <= 'b0;
        end
        else if (M_BACK_M_SKIP_ROM || M_SKIP_ROM_M_CON_T || M_SKIP_ROM_RD_SCRA || RD_SCRA_M_READ) begin
            cmd_vld <= 'b1;
        end
        else begin
            cmd_vld <= 'b0;
        end
    end

    //描述dq_out
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            dq_out <= 'b0;
        end
        else if (M_IDLE_M_RST || M_WAIT_M_RST || S_IDLE_S_LOW || S_RELE_S_LOW) begin
            dq_out <= 'b0;
        end
        else if (S_LOW_S_SEND) begin
            dq_out <= cmd[cnt_bit];
        end
    end
    
//****************************************************************
//--接收数据&数据处理
//****************************************************************
    //接收原始数据
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            rx_data <= 'd0;
        end
        else if (s_cstate == S_RECV && cnt_60us == MAX_60us / 10) begin//计数器0-15us采样
            rx_data <= {dq_in,rx_data[15:1]};
        end
    end

    assign rx_data_vld = m_cstate == M_READ && S_DONE_S_IDLE;

    //原始数据处理,考虑正负数,取补码
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            true_data <= 0;
        end
        else if (rx_data_vld) begin
            if (rx_data[15]) begin//符号位为1,负数
                true_data <= ~rx_data[10:0] + 1;//取反加一
            end
            else begin
                true_data <= rx_data[10:0];//正数原码补码相同
            end
        end
    end

    //数据扩大10000*精度(0.0625)
    assign temp_data = true_data * 'd625;

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            temp_data_vld <= 'b0;
        end
        else begin
            temp_data_vld <= rx_data_vld;
        end
    end

    assign dout_signed = rx_data[15];
endmodule
  • seg_driver.v
/**************************************功能介绍***********************************
Date	: 
Author	: Alegg xy.
Version	: 
Description: 
*********************************************************************************/
    
//---------<模块及端口声名>------------------------------------------------------
module seg_driver( 
    input				clk		,
    input				rst_n	,
    input       [23:0]  temp_data,
    input       [5:0]   point_n ,

    output	reg	[5:0]	sel	    ,
    output	reg	[7:0]	seg	    
);								 
//---------<参数定义>--------------------------------------------------------- 
    parameter MAX_1ms = 50_000;//1ms
//---------<内部信号定义>-----------------------------------------------------
    reg [3:0]   data;//存数据
    reg [5:0]   point_n_r;//存小数点位

    reg			[15:0]	cnt_1ms	   	;
    wire				add_cnt_1ms	;
    wire				end_cnt_1ms	;
    
    always @(posedge clk or negedge rst_n)begin 
       if(!rst_n)begin
            cnt_1ms <= 'd0;
        end 
        else if(add_cnt_1ms)begin 
            if(end_cnt_1ms)begin 
                cnt_1ms <= 'd0;
            end
            else begin 
                cnt_1ms <= cnt_1ms + 1'b1;
            end 
        end
    end 
    
    assign add_cnt_1ms = 1'b1;
    assign end_cnt_1ms = add_cnt_1ms && cnt_1ms == MAX_1ms - 1'd1;
    
    always @(posedge clk or negedge rst_n)begin 
        if(!rst_n)begin
            sel <= 6'b111_110;
        end  
        else if (end_cnt_1ms) begin
             sel <= {sel[4:0],sel[5]};
        end 
    end

    always @(*)begin 
        case (sel)
            6'b111_110:begin data = (temp_data / 10000) / 100            ;   point_n_r = point_n[0]; end
            6'b111_101:begin data = ((temp_data / 10000) % 100) / 10     ;   point_n_r = point_n[1]; end
            6'b111_011:begin data = (temp_data / 10000) % 10             ;   point_n_r = point_n[2]; end
            6'b110_111:begin data = (temp_data % 10000) / 1000            ;   point_n_r = point_n[3]; end
            6'b101_111:begin data = ((temp_data % 10000) % 1000) / 100    ;   point_n_r = point_n[4]; end
            6'b011_111:begin data = ((temp_data % 10000) % 100) / 10      ;   point_n_r = point_n[5]; end
            default: data = 4'd0;
        endcase
    end
    
    always @(*)begin 
        case (data)
            4'h0:seg = {point_n_r,7'b100_0000};
            4'h1:seg = {point_n_r,7'b111_1001};
            4'h2:seg = {point_n_r,7'b010_0100};
            4'h3:seg = {point_n_r,7'b011_0000};
            4'h4:seg = {point_n_r,7'b001_1001};
            4'h5:seg = {point_n_r,7'b001_0010};
            4'h6:seg = {point_n_r,7'b000_0010};
            4'h7:seg = {point_n_r,7'b111_1000};
            4'h8:seg = {point_n_r,7'b000_0000};
            4'h9:seg = {point_n_r,7'b001_0000};
            default: seg = 8'b1100_0000;
        endcase
    end
    
endmodule
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值