`default_nettype none module dht11_interface #( parameter CLK_FREQ = 27_000_000 )( input wire i_clk, inout wire io_dht11_sig, input wire i_start, output reg o_dht11_data_ready, output reg o_busy, output reg [15:0] o_temp_data, output reg [15:0] o_hum_data, output reg [7:0] o_checksum, output reg [3:0] o_state ); // === DHT11 INTERFACE === // === PARAMÈTRES === localparam T_18MS = CLK_FREQ * 18 / 1_000; // cycles pour 18ms a partir localparam T_80US = CLK_FREQ * 90 / 1_000_000; localparam T_79US = CLK_FREQ * 70 / 1_000_000; localparam T_71US = CLK_FREQ * 81 / 1_000_000; localparam T_51US = CLK_FREQ * 58 / 1_000_000; localparam T_50US = CLK_FREQ * 50 / 1_000_000; localparam T_49US = CLK_FREQ * 49 / 1_000_000; localparam T_40US = CLK_FREQ * 40 / 1_000_000; localparam T_28US = CLK_FREQ * 32 / 1_000_000; localparam T_26US = CLK_FREQ * 25 / 1_000_000; localparam T_20US = CLK_FREQ * 18 / 1_000_000; // === Signal bidirectionnel === reg sig_dir; reg sig_out; reg sig_in; assign io_dht11_sig = sig_dir ? sig_out : 1'bz; // Si sig_dir = 1, on force la valeur de sig_out sur la ligne, sinon on laisse la ligne libre (1'bz) // === REGISTRES === reg [3:0] state; reg [31:0] timer; reg [2:0] bit_count; reg [5:0] bit_index; reg [39:0] raw_data; reg [15:0] checksum; // === FSM === localparam IDLE = 4'd0, // Pull up la ligne START = 4'd1, // Pull low 18ms WAIT_RESPONSE = 4'd2, // Release la ligne (entre 20 et 40us) RESPONSE_LOW = 4'd3, // DHT11 pull low 80us RESPONSE_HIGH = 4'd4, // DHT11 pull high 80us READ_BITS_LOW = 4'd5, READ_BITS_HIGH = 4'd6, DONE = 4'd7, ERROR = 4'd8; // === INITIALISATION === initial begin sig_dir = 0; sig_out = 1; timer = 0; state = IDLE; bit_index = 0; raw_data = 0; o_dht11_data_ready = 0; end // === FSM principale === always @(posedge i_clk) begin sig_in <= io_dht11_sig; case (state) IDLE: begin sig_dir <= 0; //sig_out <= 1; timer <= 0; bit_index <= 0; raw_data <= 0; o_busy <= 0; if (i_start) begin sig_dir <= 1; sig_out <= 0; timer <= 0; o_busy <= 1; state <= START; o_dht11_data_ready <= 0; end end START: begin timer <= timer + 1; if (timer >= T_18MS) begin sig_dir <= 0; // libérer la ligne timer <= 0; state <= WAIT_RESPONSE; end end WAIT_RESPONSE: begin o_state <= state; timer <= timer + 1; if (sig_in == 0) begin state <= RESPONSE_LOW; timer <= 0; end end RESPONSE_LOW: begin o_state <= state; timer <= timer + 1; if (sig_in == 1 ) begin timer <= 0; state <= RESPONSE_HIGH; end end RESPONSE_HIGH: begin timer <= timer + 1; o_state <= state; if (sig_in == 0) begin timer <= 0; state <= READ_BITS_LOW; end end READ_BITS_LOW: begin o_state <= state; timer <= timer + 1; if (sig_in == 1) begin timer <= 0; state <= READ_BITS_HIGH; end end READ_BITS_HIGH: begin // entre 26 et 28us = 0 et ~70us = 1 o_state <= state; timer <= timer + 1; if (sig_in == 0) begin raw_data <= {raw_data[38:0], (timer > T_40US)}; timer <= 0; bit_index <= bit_index + 1; if (bit_index == 40) begin state <= DONE; end else begin state <= READ_BITS_LOW; end end end DONE: begin o_state <= state; o_hum_data <= raw_data[39:24]; o_temp_data <= raw_data[23:8]; o_checksum <= raw_data[7:0]; o_dht11_data_ready <= 1; o_busy <= 0; state <= IDLE; end endcase end always_comb begin checksum = raw_data[39:32] + raw_data[31:24] + raw_data[23:16] + raw_data[15:8]; end endmodule