FPGA project : DHT11

我犯下的错误:

1,在START状态跳转到REPLAY状态,sda会由高电平跳转到低电平。这个下降沿是传感器产生低电平响应而产生的。而不是传感器准备高电平结束而产生的。
REPLAYtoWAIT_2S     = ( state_c == REPLAY  ) && (nege && flag0 == 1'b0 && flag1 == 1'b0 && cnt_us >= 30) ; // 这里错过,cnt_us >= 30 是后加上去的;

2,RD_DATAtoWAIT_2S    = ( state_c == RD_DATA ) && (pose && data_done == 1); // 写错了,应该用data_done 。之前把flag_base 与了上去。这就导致状态机卡在了RD_DATA状态。因为pose是随机的。虽然做了同步打拍同步,和flag_base是同一时钟域但是他俩几乎不可能同时满足。

总结:在时序比较简单的工程,容易出错的地方大概率是状态机,而状态机容易出错的地方就是状态转移条件描述了。所以以后设计状态机时,要格外慎重。

3,在编译时的一个警告:

这个是状态机,状态参数定义时,忘记改值,导致的。

4,被quartus优化的信号。

 在Quartus中,使用/*synthesis noprune*/,/*synthesis preserve*/等语句,注意,这些语句如果是用于信号的定义时,需要放在定义的语句尾部。

在Vivado中,使用(* keep="true" *),(* keep_hierarchy="yes" *)语句。这些语句是放在信号定义之前的

 

 

module dht11(
    input       wire            sys_clk     ,
    input       wire            sys_rst_n   ,
    input       wire            key_in      ,

    inout       wire            sda         ,

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

    // localparam
    localparam          WAIT_2S = 4'b0001 ,
                        START   = 4'b0010 ,
                        REPLAY  = 4'b0100 ,
                        RD_DATA = 4'b1000 ;
    // wire signal define 
    wire                nege              ;
    wire                pose              ;
    wire                flag_base         ;
    wire                WAIT_2StoSTART    ;
    wire                STARTtoREPLAY     ;
    wire                REPLAYtoRD_DATA   ;
    wire                REPLAYtoWAIT_2S   ;
    wire                RD_DATAtoWAIT_2S  ;
    // reg signal define
    reg                 sda_reg0  ;
    reg                 sda_reg1  ;
    reg                 sda_reg2  ;
    reg                 sda_en    ;
    reg                 sda_out   ;
    reg                 flag0     ;
    reg                 flag1     ;
    reg                 key_flag  ;
    reg                 data_done ;
    reg     [ 5:0]      cnt_base  ;
    reg     [ 3:0]      state_c   /*synthesis preserve*/;
    reg     [ 3:0]      state_n   ;
    reg     [ 5:0]      cnt_bit   ;
    reg     [20:0]      cnt_us    ;
    reg     [39:0]      data_temp ;

/***********************************************************************/
    // 1us 标志信号的产生
    // reg     [5:0]       cnt_base  ;
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) begin
            cnt_base <= 6'd0 ;
        end else begin
            if(flag_base) begin
                cnt_base <= 6'd0 ;
            end else begin
                cnt_base <= cnt_base + 1'b1 ;
            end
        end
    end
    // wire                flag_base ;
    assign flag_base = (cnt_base == 49) ? 1'b1 : 1'b0 ;

    // 同步与打两拍
    // reg sda_reg0 // reg sda_reg1 // reg sda_reg2  ;
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) begin
            sda_reg0 <= 1'b1 ;
            sda_reg1 <= 1'b1 ;
            sda_reg2 <= 1'b1 ;
        end else begin
            sda_reg0 <= sda      ;
            sda_reg1 <= sda_reg0 ;
            sda_reg2 <= sda_reg1 ;
        end
    end

    // sda总线上升沿与下降沿的检测
    // wire                nege      ;
    // wire                pose      ;
    assign  nege = ~sda_reg1 &&  sda_reg2 ;
    assign  pose =  sda_reg1 && ~sda_reg2 ;

    // 三段式状态机 状态转移描述 状态转移条件描述 输出描述(与状态转移有关量描述)
    // reg     [ 4:0]      state_c   ;
    // reg     [ 4:0]      state_n   ;
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) begin
            state_c <= WAIT_2S ;
        end else begin
            state_c <= state_n;
        end
    end
    always @(*) begin
        case (state_c)
        WAIT_2S:begin
                    if(WAIT_2StoSTART) begin
                        state_n <= START ;
                    end else begin
                        state_n <= WAIT_2S ;
                    end
                end
        START  :begin
                    if(STARTtoREPLAY) begin
                        state_n <= REPLAY ;
                    end else begin
                        state_n <= START ;
                    end
                end
        REPLAY :begin
                    if(REPLAYtoRD_DATA) begin
                        state_n <= RD_DATA ;
                    end else begin
                        if(REPLAYtoWAIT_2S) begin
                            state_n <= WAIT_2S ;
                        end else begin
                            state_n <= REPLAY ;
                        end
                    end
                end
        RD_DATA:begin
                    if(RD_DATAtoWAIT_2S) begin
                        state_n <= WAIT_2S ;
                    end else begin
                        state_n <= RD_DATA ;
                    end
                end 
        default: state_n <= WAIT_2S ;
        endcase
    end
    assign  WAIT_2StoSTART      = ( state_c == WAIT_2S ) && (flag_base && cnt_us == 1_999_999) ;
    assign  STARTtoREPLAY       = ( state_c == START   ) && (flag_base && cnt_us == 20_012   ) ;
    assign  REPLAYtoRD_DATA     = ( state_c == REPLAY  ) && (nege && flag0 && flag1)           ;
    assign  REPLAYtoWAIT_2S     = ( state_c == REPLAY  ) && (nege && flag0 == 1'b0 && flag1 == 1'b0 && cnt_us >= 30) ; // 这里错过一次,cnt_us >= 30 是后加上去的;因为第一次的低电平是传感器响应低电平拉低的,并不是响应高电平结束拉低的。
    assign  RD_DATAtoWAIT_2S    = ( state_c == RD_DATA ) && (pose && data_done == 1); // 写错了,应该用data_done 。而且pose 和 flag_base 是两个时钟域下的,根本不能同时满足。逻辑错误。
    // reg     [20:0]      cnt_us    ;
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) begin
            cnt_us <= 21'd0 ;
        end else begin
            case (state_c)
            WAIT_2S:begin
                        if(flag_base && cnt_us == 1_999_999) begin
                            cnt_us <= 21'd0 ;
                        end else begin
                            if(flag_base) begin
                                cnt_us <= cnt_us + 1'b1 ;
                            end else begin
                                cnt_us <= cnt_us ;
                            end
                        end
                    end
            START  :begin
                        if(flag_base && cnt_us == 20_012) begin
                            cnt_us <= 21'd0 ;
                        end else begin
                            if(flag_base) begin
                                cnt_us <= cnt_us + 1'b1 ;
                            end else begin
                                cnt_us <= cnt_us ;
                            end
                        end
                    end
            REPLAY :begin
                        if(nege || pose) begin
                            cnt_us <= 21'd0 ;
                        end else begin
                            if(flag_base) begin
                                cnt_us <= cnt_us + 1'b1 ;
                            end else begin
                                cnt_us <= cnt_us ;
                            end
                        end
                    end
            RD_DATA:begin
                        if(nege || pose) begin
                            cnt_us <= 21'd0 ;
                        end else begin
                            if(flag_base) begin
                                cnt_us <= cnt_us + 1'b1 ;
                            end else begin
                                cnt_us <= cnt_us ;
                            end
                        end
                    end
                default: cnt_us <= 21'd0 ;
            endcase
        end
    end
    // reg                 flag0     ;
    // reg                 flag1     ;
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) begin
            flag0 <= 1'b0 ;
            flag1 <= 1'b0 ;
        end else begin
            if(state_c == REPLAY) begin
                if(cnt_us >= 81 && sda == 0) begin // 这里其实可能有一个小问题,就是响应时序的低电平不足81拉高了,但是响应时序的高电平满足。那么也会判定为满足响应。
                    flag0 <= 1'b1 ;
                end else begin
                    flag0 <= flag0 ;   // 所以,在设计flag0信号的时候,还得加上一条,sda == 0
                end

                if(cnt_us >= 85 && sda == 1) begin
                    flag1 <= 1'b1 ;
                end else begin
                    flag1 <= flag1 ;
                end
            end else begin
                flag0 <= 1'b0 ;
                flag1 <= 1'b0 ;
            end
        end
    end
    // reg     [5:0]       cnt_bit   ;
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) begin
            cnt_bit <= 6'd0 ;
        end else begin
            if(state_c == RD_DATA) begin
                if(nege) begin // 判断cnt_us 的值 是给data_temp 赋值时要考虑的事情。这里只是cnt_bit + 1
                    cnt_bit <= cnt_bit + 1'b1 ;
                end else begin
                    if(pose && cnt_bit == 40) begin
                        cnt_bit <= 6'd0 ;
                    end else begin
                        cnt_bit <= cnt_bit ;
                    end
                end
            end else begin
                cnt_bit <= 6'd0 ;
            end
        end
    end
    // reg                 data_done ;
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) begin
            data_done <= 1'b0 ;
        end else begin
            if(state_c == RD_DATA && cnt_bit == 40) begin
                data_done <= 1'b1 ;
            end else begin
                data_done <= 0 ;
            end
        end
    end
    // reg     [39:0]      data_temp ;
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) begin
            data_temp <= 40'd0 ;
        end else begin
            if(state_c == RD_DATA) begin
                if(nege) begin
                    if(cnt_us >= 23 && cnt_us <= 27) begin
                        data_temp[39 - cnt_bit] <= 1'b0 ;
                    end else begin
                        if(cnt_us >= 68 && cnt_us <= 74) begin
                            data_temp[39 - cnt_bit] <= 1'b1 ;
                        end else begin
                            data_temp[39 - cnt_bit] <= 1'b0 ;
                        end
                    end
                end else begin
                    data_temp <= data_temp ;
                end
            end
        end
    end
    // reg                 key_flag  ;
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) begin
            key_flag <= 1'b0 ;
        end else begin
            if(key_in) begin
                key_flag <= ~key_flag ;
            end else begin
                key_flag <=  key_flag ;
            end
        end
    end
    // 三态使能与输出
    // reg                 sda_en    ;
    // reg                 sda_out   ;
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) begin
            sda_en  <= 1'b1 ;
            sda_out <= 1'b1 ;
        end begin
            case (state_c)
            WAIT_2S :   begin
                           sda_en  <= 1'b1 ;
                           sda_out <= 1'b1 ;
                        end // 由于使用reg 类型,这里在start状态会多拉高20ns的高电平。
            START   :   begin
                            sda_en  <= 1'b1 ;
                            if(cnt_us <= 19_999) begin
                                sda_out <= 1'b0 ;
                            end else begin
                                sda_out <= 1'b1 ;
                            end
                        end
            REPLAY  :   begin
                            sda_en  <= 1'b0 ;
                            sda_out <= 1'b1 ;
                        end
            RD_DATA :   begin
                            sda_en  <= 1'b0 ;
                            sda_out <= 1'b1 ;
                        end
                default: begin
                            sda_en  <= 1'b0 ;
                            sda_out <= 1'b1 ;
                        end
            endcase
        end
    end
    
/**********************************output signal*****************************************/
    // wire            sda         ,
    assign sda = (sda_en == 1'b1) ? sda_out : 1'bz ; // 注意三态输出赋值z
    // reg     [19:0]  data_out    ,
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) begin
            data_out <= 20'd0 ;
        end else begin
            if(key_flag == 1'b0) begin // 显示湿度 前8位是整数,后8位是小数。
                data_out <= (data_temp[39:24] >> 8) * 20'd10 ; // 因为数码管的最后一位是显示小数的,所以×10。
            end else begin
                data_out <= data_temp[23:16] * 20'd10 + data_temp[11:8] ;                     
            end
        end
    end
    // 目前 DHT11 温度只能精确到 0.1℃,所以温度 8bit 小数数据的值是小于 10 的,
    // 我们应用时用小数数据的低四位来表示
    // 温度的小数值,最高位表示温度的正负即可。
    // reg             sign
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) begin
            sign <= 1'b0 ;
        end else begin
            if(data_done && (data_temp[7:0] == (data_temp[15:8] + data_temp[23:16] + data_temp[31:24] + data_temp[39:32]))) begin
                if(data_temp[15] == 1'b1) begin
                    sign <= 1'b1 ;
                end else begin
                    sign <= 1'b0 ;
                end
            end
        end
    end

endmodule
module top(
    input       wire        sys_clk     ,
    input       wire        sys_rst_n   ,
    input       wire        key         ,

    inout       wire        dht11       ,

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

    // 例化连线
    wire                    key_out_w ;
    wire        [19:00]     data_w    ;
    wire                    sign_w    ;
    wire        [ 5: 0]     point_w   ;
    wire                    en_w      ;
    assign       point_w = 6'b000_010 ;
    assign       en_w    = 1'b1       ;

key_filter key_filter_insert(
    .sys_clk                ( sys_clk   ) ,
    .sys_rst_n              ( sys_rst_n ) ,
    .key_in                 ( key       ) ,

    .key_out                ( key_out_w )         
);

dht11 dht11_insert(
    .sys_clk                ( sys_clk    ) ,
    .sys_rst_n              ( sys_rst_n  ) ,
    .key_in                 ( key_out_w  ) ,

    .sda                    ( dht11      ) ,

    .data_out               ( 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                 ( en_w       ) ,

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

endmodule

 木有仿真,只有signaltap抓取的波形,但我忘记截屏了。

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
卷积神经网络(Convolutional Neural Network,CNN)是一种广泛应用于图像识别和计算机视觉任务的深度学习模型。而FPGA(Field-Programmable Gate Array)是一种可编程逻辑器件,可以根据需要进行灵活的硬件设计和重新配置。 卷积神经网络在计算过程中需要大量的矩阵运算和卷积操作,这些操作对于传统的通用处理器来说可能会导致较高的计算延迟和能耗。而使用FPGA可以将卷积神经网络的计算任务进行硬件加速,提高计算性能和效率。 Convolutional FPGA是指使用FPGA来实现卷积神经网络的加速。通过将卷积神经网络的计算任务映射到FPGA上,可以利用FPGA的并行计算能力和高速存储器来加速卷积操作,从而提高图像识别和计算机视觉任务的处理速度。 Convolutional FPGA的优势包括: 1. 高性能:FPGA可以实现高度并行的计算,能够加速卷积神经网络的计算任务。 2. 低功耗:相比于传统的通用处理器,FPGA在执行卷积操作时能够提供更高的能效。 3. 灵活性:FPGA可以根据具体的应用需求进行重新配置,适应不同的卷积神经网络结构和算法。 然而,Convolutional FPGA也存在一些挑战: 1. 设计复杂性:将卷积神经网络映射到FPGA上需要进行硬件设计和优化,对于开发者来说具有一定的技术门槛。 2. 存储器带宽限制:FPGA的存储器带宽可能成为性能瓶颈,需要合理设计数据传输和存储方案。 3. 硬件资源限制:FPGA的资源有限,可能无法满足较大规模的卷积神经网络模型。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值