FPGA project : DS18B20

本想着一天发一个实验的,这个ds18b20,耗时两天。代码写了两次,呜呜~

由于第二次写代码没画时序图,所以代码和时序图一些参数有些不一致,但问题不大。

这里有几件事情值得一提:

1:关于状态机的编写,我觉得还是三段式比较好。

2:关于生成其他时钟信号,用来做触发边沿。我不喜欢用这种方法(提一个概念“全局时钟网络”)。所以用产生一个1us base基础计时器,产生一个1us的标志信号。之后的计数器与该计数器级联,记得把<end_cnt_base>这个标志信号加上。

我犯下的错误:

1:在画时序图是,没有画<end_cnt_base>标志信号,直接默认时钟为周期为1us,造成了混乱。所以以后要注意。

2:&& 逻辑写成了 || 逻辑

3:三态门输出 Z 写成了 1

4:数据位宽定义错误,因为少思考了一个数据对应的位宽。

4:读取温度时,少记一位。注意data_bit跳转条件,和发指令时不一样的。

 

 

module ds18b20(
    input   wire            sys_clk     ,
    input   wire            sys_rst_n   ,

    inout   wire            dq          ,

    output  reg     [19:0]  data        ,
    output  reg             sign  
);

    // localparam   指令,先发低位。
    localparam      WR_CMD_WORD = 16'h44CC    ,
                    RD_CMD_WORD = 16'hBECC    ;
    localparam      INIT        =  6'b000_001 ,
                    WR_CMD      =  6'b000_010 ,
                    WAIT        =  6'b000_100 ,
                    INIT_AGIN   =  6'b001_000 ,
                    RD_CMD      =  6'b010_000 ,
                    RD_TEMP     =  6'b100_000 ;
    // wire signal define
    wire            end_cnt_base      ;
    wire            INITtoWR_CMD      ;
    wire            WR_CMDtoWAIT      ;
    wire            WAITtoINIT_AGIN   ;
    wire            INIT_AGINtoRD_CMD ;
    wire            RD_CMDtoRD_TEMP   ;
    wire            RD_TEMPtoINIT     ;
    // reg  signal define
    reg     [5:0]   cnt_base     ;
    reg             dq_en        ;
    reg             dq_out       ;
    reg     [5:0]   state_c  /*synthesis preserve*/;
    reg     [5:0]   state_n  /*synthesis preserve*/;
    reg     [19:0]  cnt          ;
    reg     [4:0]   data_bit     ;
    reg             flag_respond ;
    reg             data_done    ;
    reg     [15:0]  data_temp    ; // 读取高速缓存器的byte0和byte1,一共16位。
    
    /****************************************************************************************/
    // reg     [5:0]       cnt_base ;
    // wire                end_cnt_base ;
    always @(posedge sys_clk or negedge sys_rst_n) 
        if(~sys_rst_n)
            cnt_base <= 6'd0 ;
        else if(end_cnt_base)
            cnt_base <= 6'd0 ;
        else 
            cnt_base <= cnt_base + 1'b1 ;
    assign  end_cnt_base = cnt_base == 49;
    // reg     [5:0]       state_c ;
    always @(posedge sys_clk or negedge sys_rst_n)
        if(~sys_rst_n)
            state_c <= INIT;
        else 
            state_c <= state_n ;
    // reg     [5:0]       state_n ;
    always @(*)
        case (state_c)
        INIT       :if(INITtoWR_CMD)
                        state_n <= WR_CMD ;
                    else 
                        state_n <= INIT ;
        WR_CMD     :if(WR_CMDtoWAIT)
                        state_n <= WAIT ;
                    else 
                        state_n <= WR_CMD ;
        WAIT       :if(WAITtoINIT_AGIN)
                        state_n <= INIT_AGIN ;
                    else 
                        state_n <= WAIT ;
        INIT_AGIN  :if(INIT_AGINtoRD_CMD)
                        state_n <= RD_CMD ;
                    else 
                        state_n <= INIT_AGIN ;
        RD_CMD     :if(RD_CMDtoRD_TEMP)
                        state_n <= RD_TEMP ;
                    else 
                        state_n <= RD_CMD ;
        RD_TEMP    :if(RD_TEMPtoINIT)
                        state_n <= INIT ;
                    else 
                        state_n <= RD_TEMP ;
        default    :    state_n <= INIT ;
        endcase
    // 状态转移条件
    assign  INITtoWR_CMD        = (state_c == INIT      ) && (end_cnt_base && flag_respond == 1'b1 && cnt == 999);
    assign  WR_CMDtoWAIT        = (state_c == WR_CMD    ) && (end_cnt_base ==1'b1 && cnt == 60 && data_bit == 15) ;
    assign  WAITtoINIT_AGIN     = (state_c == WAIT      ) && (end_cnt_base && cnt == 749_999)  ;
    assign  INIT_AGINtoRD_CMD   = (state_c == INIT_AGIN ) && (end_cnt_base && flag_respond == 1'b1 && cnt == 999);
    assign  RD_CMDtoRD_TEMP     = (state_c == RD_CMD    ) && (end_cnt_base ==1'b1 && cnt == 60 && data_bit == 15)  ;
    assign  RD_TEMPtoINIT       = (state_c == RD_TEMP   ) && (end_cnt_base ==1'b1 && cnt == 60 && data_done == 1'b1);

    // reg     [19:0]       cnt ;
    always @(posedge sys_clk or negedge sys_rst_n)
        if(~sys_rst_n)
            cnt <= 20'd0 ;
        else case (state_c)
        INIT      : if(cnt == 999 && end_cnt_base == 1'b1)
                        cnt <= 20'd0 ;
                    else if(end_cnt_base == 1'b1)
                        cnt <= cnt + 1'b1 ;
        WR_CMD    : if(cnt == 60 && end_cnt_base == 1'b1)
                        cnt <= 20'd0 ;
                    else if(end_cnt_base == 1'b1)
                        cnt <= cnt + 1'b1 ;
        WAIT      : if(cnt == 749_999 && end_cnt_base == 1'b1)
                        cnt <= 20'd0 ;
                    else if(end_cnt_base == 1'b1)
                        cnt <= cnt + 1'b1 ;
        INIT_AGIN : if(cnt == 999 && end_cnt_base == 1'b1)
                        cnt <= 20'd0 ;
                    else if(end_cnt_base == 1'b1)
                        cnt <= cnt + 1'b1 ;
        RD_CMD    : if(cnt == 60 && end_cnt_base == 1'b1)
                        cnt <= 20'd0 ;
                    else if(end_cnt_base == 1'b1)
                        cnt <= cnt + 1'b1 ;
        RD_TEMP   : if(cnt == 60 && end_cnt_base == 1'b1)
                        cnt <= 20'd0 ;
                    else if(end_cnt_base == 1'b1)
                        cnt <= cnt + 1'b1 ;
        default   :     cnt <= 20'd0 ;
        endcase
    // reg     [3:0]       data_bit ;
    always @(posedge sys_clk or negedge sys_rst_n)
        if(~sys_rst_n)
            data_bit <= 5'd0 ;
        else case (state_c)
        INIT      : data_bit <= 5'd0 ;
        WR_CMD    : if(end_cnt_base == 1'b1 && cnt == 60 && data_bit == 15)
                        data_bit <= 5'd0 ;
                    else if(end_cnt_base == 1'b1 && cnt == 60)
                        data_bit <= data_bit + 1'b1 ;
                    else 
                        data_bit <= data_bit ;
        WAIT      : data_bit <= 5'd0 ;
        INIT_AGIN : data_bit <= 5'd0 ;
        RD_CMD    : if(end_cnt_base == 1'b1 && cnt == 60 && data_bit == 15)
                        data_bit <= 5'd0 ;
                    else if(end_cnt_base == 1'b1 && cnt == 60)
                        data_bit <= data_bit + 1'b1 ;
                    else 
                        data_bit <= data_bit ;
        RD_TEMP   : if(end_cnt_base == 1'b1 && cnt == 10 && data_bit == 16) // 第十微秒的时候采样。
                        data_bit <= 5'd0 ;
                    else if(end_cnt_base == 1'b1 && cnt == 10)
                        data_bit <= data_bit + 1'b1 ;
                    else 
                        data_bit <= data_bit ;
        default   :     data_bit <= 5'd0 ;
        endcase

    // reg                 flag_respond ;
    always @(posedge sys_clk or negedge sys_rst_n)
        if(~sys_rst_n)
            flag_respond <= 1'b0 ;
        else if(state_c != INIT && state_c != INIT_AGIN)
            flag_respond <= 1'b0 ;
        else if((state_c == INIT || state_c == INIT_AGIN) && cnt == 590 && dq == 1'b0)
            flag_respond <= 1'b1 ;
        else 
            flag_respond <= flag_respond ;

    // reg                 data_done ;
    always @(posedge sys_clk or negedge sys_rst_n)
        if(~sys_rst_n)
            data_done <= 1'b0 ;
        else if(state_c != RD_TEMP)
            data_done <= 1'b0 ;
        else if(state_c == RD_TEMP && end_cnt_base == 1'b1 && data_bit == 16)
            data_done <= 1'b1 ;
        else 
            data_done <= data_done ;
    
    // reg     [15:0]      data_temp ;
    always @(posedge sys_clk or negedge sys_rst_n)
        if(~sys_rst_n)
            data_temp <= 16'd0 ;
        else if(state_c == RD_TEMP && end_cnt_base == 1'b1 && cnt == 13)
            data_temp <= {dq,data_temp[15:1]} ;
        else 
            data_temp <= data_temp ;

    // reg                 dq_en  ;
    // reg                 dq_out ;
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) begin
            dq_en  <= 1'b0 ;
            dq_out <= 1'b0 ;
        end else begin
            case (state_c)
            INIT     :  begin
                            if(cnt >= 0 && cnt <= 499) begin
                                dq_en  <= 1'b1 ;
                                dq_out <= 1'b0 ;
                            end else begin
                                dq_en  <= 1'b0 ;
                                dq_out <= 1'b0 ;
                            end     
                        end
            WR_CMD   :  begin
                            if(cnt == 60) begin
                                dq_en  <= 1'b0 ;
                                dq_out <= 1'b0 ;
                            end else begin
                                if(WR_CMD_WORD[data_bit] == 1'b1) begin
                                    if(cnt >= 0 && cnt <= 14) begin
                                        dq_en  <= 1'b1 ;
                                        dq_out <= 1'b0 ;
                                    end else begin
                                        dq_en  <= 1'b0 ;
                                        dq_out <= 1'b0 ;
                                    end
                                end else begin
                                    dq_en  <= 1'b1 ;
                                    dq_out <= 1'b0 ;
                                end
                            end     
                        end
            WAIT     :  begin
                            dq_en  <= 1'b1 ;
                            dq_out <= 1'b1 ;
                        end
            INIT_AGIN:  begin
                            if(cnt >= 0 && cnt <= 499) begin
                                dq_en  <= 1'b1 ;
                                dq_out <= 1'b0 ;
                            end else begin
                                dq_en  <= 1'b0 ;
                                dq_out <= 1'b0 ;
                            end     
                        end
            RD_CMD   :  begin
                            if(cnt == 60) begin
                                dq_en  <= 1'b0 ;
                                dq_out <= 1'b0 ;
                            end else begin
                                if(RD_CMD_WORD[data_bit] == 1'b1) begin
                                    if(cnt >= 0 && cnt <= 14) begin
                                        dq_en  <= 1'b1 ;
                                        dq_out <= 1'b0 ;
                                    end else begin
                                        dq_en  <= 1'b0 ;
                                        dq_out <= 1'b0 ;
                                    end
                                end else begin
                                    dq_en  <= 1'b1 ;
                                    dq_out <= 1'b0 ;
                                end
                            end     
                        end
            RD_TEMP  :  begin
                            if(cnt == 0 || cnt == 1) begin
                                dq_en  <= 1'b1 ;
                                dq_out <= 1'b0 ;
                            end else begin
                                dq_en  <= 1'b0 ;
                                dq_out <= 1'b0 ;
                            end
                        end
            default:    begin
                            dq_en  <= 1'b0 ;
                            dq_out <= 1'b0 ;
                        end
            endcase
        end
    end

/***********************************************************************/
    // wire            dq          
    assign dq = (dq_en == 1'b1) ? dq_out : 1'bz ;

    // reg     [19:0]  data        
    always @(posedge sys_clk or negedge sys_rst_n)
        if(~sys_rst_n)
            data <= 20'd0 ;
        else if(state_c == RD_TEMP && data_done == 1'b1) 
                if(data_temp[15] == 1'b0)
                    data <= data_temp[10:0] * 10'd625;
                else 
                    data <= (~data_temp[10:0]  + 1'b1 ) * 10'd625;
        else 
            data <= data ;

    // reg             sign 
    always @(posedge sys_clk or negedge sys_rst_n)
        if(~sys_rst_n)
            sign <= 1'b0 ;
        else if(state_c == RD_TEMP && data_done == 1'b1)
            sign <= data_temp[15];
        else 
            sign <= sign ;
            
endmodule
module top(
    input       wire        sys_clk   ,
    input       wire        sys_rst_n ,

    inout       wire        dq        ,

    output      wire        ds        ,
    output      wire        oe        ,
    output      wire        shcp      ,
    output      wire        stcp    
);

    wire   [19:0]  data_w   /*synthesis keep */;
    wire           sign_w   ;
    wire   [05:00] point_w  ;
    wire           seg_en_w ;
    assign         seg_en_w= 1'b1       ;
    assign         point_w = 6'b010_000 ;



ds18b20 ds18b20_insert(
    .sys_clk                ( sys_clk   ) ,
    .sys_rst_n              ( sys_rst_n ) ,

    .dq                     ( dq        ) ,

    .data                   ( data_w    ) ,
    .sign                   ( sign_w    )      
);

seg_595_dynamic seg_595_dynamic_insert(
    .sys_clk                ( sys_clk   ) ,
    .sys_rst_n              ( sys_rst_n ) ,
    .data                   ( data_w    ) ,
    .point                  ( point_w   ) ,
    .sign                   ( sign_w    ) ,
    .seg_en                 ( seg_en_w  ) ,

    .ds                     ( ds        ) ,
    .oe                     ( oe        ) ,
    .shcp                   ( shcp      ) ,
    .stcp                   ( stcp      )    
);

endmodule

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值