Mistakes I made:
1. When the START state jumps to the REPLAY state, sda will jump from high level to low level. This falling edge is caused by the sensor producing a low level response. Rather than being generated when the sensor is ready to end at a high level.
REPLAYtoWAIT_2S = ( state_c == REPLAY ) & amp; & amp; (nege & amp; & amp; flag0 == 1’b0 & amp; & amp; flag1 == 1’b0 & amp; & amp; cnt_us >= 30 ) ; // Missed here, cnt_us >= 30 is added later;
2. RD_DATAtoWAIT_2S = (state_c == RD_DATA) & amp; & amp; (pose & amp; & amp; data_done == 1); // Wrong writing, data_done should be used. Flag_base was added before. This causes the state machine to get stuck in the RD_DATA state. Because pose is random. Although synchronous beat synchronization is performed and it is in the same clock domain as flag_base, it is almost impossible for them to be satisfied at the same time.
Summary: In projects with relatively simple timing, the most likely error-prone part is the state machine, and the most likely error-prone part of the state machine is the description of state transition conditions. Therefore, you must be extra cautious when designing state machines in the future.
3. A warning during compilation:
This is caused by the state machine forgetting to change the value when defining the state parameters.
4. Signals optimized by quartus.
In Quartus, use statements such as /*synthesis noprune*/, /*synthesis preserve*/, etc. Note that if these statements are used to define signals, they need to be placed at the end of the definition statement.
In Vivado, use (* keep=”true” *), (* keep_hierarchy=”yes” *) statements. These statements are placed before the signal definition
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; /****************************************************** ************************/ //Generation of 1us flag signal // 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 ; // Synchronize and beat twice // 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 // Detection of rising and falling edges of sda bus // wire nege; // wire pose ; assign nege = ~sda_reg1 & amp; & amp; sda_reg2 ; assign pose = sda_reg1 & amp; & amp; ~sda_reg2 ; //Three-stage state machine, state transition description, state transition condition description, output description (description of quantities related to state transition) //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 ) & amp; & amp; (flag_base & amp; & amp; cnt_us == 1_999_999) ; assign STARTtoREPLAY = ( state_c == START ) & amp; & amp; (flag_base & amp; & amp; cnt_us == 20_012 ) ; assign REPLAYtoRD_DATA = ( state_c == REPLAY ) & amp; & amp; (nege & amp; & amp; flag0 & amp; & amp; flag1) ; assign REPLAYtoWAIT_2S = ( state_c == REPLAY ) & amp; & amp; (nege & amp; & amp; flag0 == 1'b0 & amp; & amp; flag1 == 1'b0 & amp; & amp; cnt_us >= 30) ; // Missed once here, cnt_us >= 30 is added later; because the first low level is the sensor pulling low in response to the low level, not the end of the low level in response to the high level. assign RD_DATAtoWAIT_2S = (state_c == RD_DATA) & amp; & amp; (pose & amp; & amp; data_done == 1); // Wrong writing, data_done should be used. Moreover, pose and flag_base are in two clock domains and cannot be satisfied at the same time. logical error. // 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 & amp; & amp; 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 & amp; & amp; 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 & amp; & sda == 0) begin // There may actually be a small problem here, that is, the low level of the response timing is lower than 81 and is raised, but the high level of the response timing is satisfied. Then it will also be judged as a satisfactory response. flag0 <= 1'b1; end else begin flag0 <= flag0; // Therefore, when designing the flag0 signal, you have to add one, sda == 0 end if(cnt_us >= 85 & amp; & 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 // Determining the value of cnt_us is something to consider when assigning a value to data_temp. Here is just cnt_bit + 1 cnt_bit <= cnt_bit + 1'b1; end else begin if(pose & amp; & amp; 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 & amp; & amp; 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 & amp; & amp; cnt_us <= 27) begin data_temp[39 - cnt_bit] <= 1'b0; end else begin if(cnt_us >= 68 & amp; & amp; 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 //Three-state enable and output //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 // Due to the use of reg type, the high level will be raised for 20ns in the start state. 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 ; // Note the three-state output assignment 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 // Display humidity. The first 8 digits are integers and the last 8 digits are decimals. data_out <= (data_temp[39:24] >> 8) * 20'd10; // Because the last digit of the digital tube displays decimals, ×10. end else begin data_out <= data_temp[23:16] * 20'd10 + data_temp[11:8]; end end end // At present, the DHT11 temperature can only be accurate to 0.1℃, so the value of the temperature 8-bit decimal data is less than 10. // We use the lower four digits of decimal data to represent it when applying //The decimal value of the temperature, the highest digit indicates the positive or negative temperature. //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 & amp; & amp; (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 ); // Instantiate the connection 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
There is no simulation, only the waveform captured by signaltap, but I forgot to take a screenshot.