module dht11_model ( inout wire data, // Ligne de données bidirectionnelle input wire clk, // Horloge système (50 MHz) input wire rst_n // Reset actif bas ); // Paramètres pour les timings (basés sur une horloge de 50 MHz, période 20 ns) localparam CLK_FREQ = 50_000_000; // 50 MHz localparam START_LOW_TIME = 18_000 / 20; // 18 ms pour le signal de démarrage localparam START_HIGH_TIME = 40_000 / 20; // 20-40 µs pour le relâchement localparam RESPONSE_LOW = 80_000 / 20; // 80 µs pour la réponse basse localparam RESPONSE_HIGH = 80_000 / 20; // 80 µs pour la réponse haute localparam BIT0_LOW = 50_000 / 20; // 50 µs pour bit '0' localparam BIT1_LOW = 70_000 / 20; // 70 µs pour bit '1' localparam DATA_BITS = 40; // 40 bits de données // États de la machine à états localparam IDLE = 3'd0, START = 3'd1, RESPONSE = 3'd2, SEND_DATA = 3'd3, ENDED = 3'd4; reg [2:0] state, next_state; reg [15:0] counter; // Compteur pour les timings reg [5:0] bit_index; // Index du bit à envoyer reg data_out; // Valeur de sortie sur la ligne data reg data_oe; // Contrôle de l'output enable (1 = sortie, 0 = haute impédance) wire data_in; // Valeur lue sur la ligne data // Données simulées (exemple : humidité = 45.0%, température = 23.0°C) reg [7:0] humidity_int = 8'h2D; // 45 en décimal reg [7:0] humidity_dec = 8'h00; // 0 reg [7:0] temp_int = 8'h17; // 23 en décimal reg [7:0] temp_dec = 8'h00; // 0 reg [7:0] checksum; // Checksum = sum des 4 octets reg [39:0] data_shift; // Registre pour les 40 bits de données // Gestion de la ligne bidirectionnelle assign data = data_oe ? data_out : 1'bz; assign data_in = data; // Calcul du checksum always @(posedge clk or negedge rst_n) begin if (!rst_n) begin checksum <= 8'h00; end else begin checksum <= humidity_int + humidity_dec + temp_int + temp_dec; end end // Concaténation des données à envoyer always @(posedge clk or negedge rst_n) begin if (!rst_n) begin data_shift <= 40'b0; end else begin data_shift <= {humidity_int, humidity_dec, temp_int, temp_dec, checksum}; end end // Machine à états always @(posedge clk or negedge rst_n) begin if (!rst_n) begin state <= IDLE; counter <= 16'b0; bit_index <= 6'b0; data_out <= 1'b1; data_oe <= 1'b0; end else begin state <= next_state; case (state) IDLE: begin counter <= 16'b0; bit_index <= 6'b0; data_out <= 1'b1; data_oe <= 1'b0; end START: begin counter <= counter + 1; data_out <= 1'b0; data_oe <= 1'b1; end RESPONSE: begin counter <= counter + 1; if (counter < RESPONSE_LOW) begin data_out <= 1'b0; data_oe <= 1'b1; end else begin data_out <= 1'b1; data_oe <= 1'b1; end end SEND_DATA: begin counter <= counter + 1; if (counter == 0) begin data_out <= 1'b0; // Début du bit (toujours bas) data_oe <= 1'b1; end else if (counter == (data_shift[39-bit_index] ? BIT1_LOW : BIT0_LOW)) begin data_out <= 1'b1; // Fin du bit data_oe <= 1'b1; end else if (counter >= (data_shift[39-bit_index] ? BIT1_LOW + 50 : BIT0_LOW + 50)) begin counter <= 16'b0; bit_index <= bit_index + 1; end end ENDED: begin data_out <= 1'b1; data_oe <= 1'b0; counter <= 16'b0; end endcase end end // Logique de transition des états always @(*) begin next_state = state; case (state) IDLE: begin if (data_in == 1'b0) // Détection du signal de démarrage next_state = START; end START: begin if (counter >= START_LOW_TIME && data_in == 1'b1) next_state = RESPONSE; end RESPONSE: begin if (counter >= RESPONSE_LOW + RESPONSE_HIGH) next_state = SEND_DATA; end SEND_DATA: begin if (bit_index >= DATA_BITS) next_state = ENDED; end ENDED: begin next_state = IDLE; end endcase end endmodule