module ultrasonic_fpga #( parameter integer CLK_FREQ = 27_000_000 // Fréquence d'horloge en Hz )( input wire clk, input wire start, inout wire sig, // Broche bidirectionnelle vers le capteur output reg [15:0] distance, // Distance mesurée en cm output reg [2:0] state ); reg [15:0] trig_counter = 0; reg [31:0] echo_counter = 0; reg [31:0] echo_div_counter = 0; reg [15:0] distance_counter = 0; reg sig_out; reg sig_dir; // 1: output, 0: input assign sig = sig_dir ? sig_out : 1'bz; // bz pour dire que le fpga laisse le fils libre et n'oblige pas de valeur reg sig_int, sig_ok; localparam IDLE = 3'd0, TRIG_HIGH = 3'd1, TRIG_LOW = 3'd2, WAIT_ECHO = 3'd3, MEASURE_ECHO = 3'd4, COMPUTE = 3'd5, DONE = 3'd6, WAIT_NEXT = 3'd7; localparam integer TRIG_PULSE_CYCLES = CLK_FREQ / 100_000; // 10us pulse localparam integer DIST_DIVISOR = (58 * CLK_FREQ) / 1_000_000; // pour conversion us -> cm localparam integer MAX_CM = 350; localparam integer TIMEOUT_CYCLES = (MAX_CM * 58 * CLK_FREQ) / 1000000; localparam WAIT_NEXT_CYCLES = (CLK_FREQ / 1000) * 100; // 60 ms reg [31:0] wait_counter; always @(posedge clk) begin sig_int <= sig; sig_ok <= sig_int; end always @(posedge clk) begin // FSM case (state) IDLE: begin sig_out <= 0; sig_dir <= 0; distance <= 0; if (start) begin state <= TRIG_HIGH; trig_counter <= 0; end end TRIG_HIGH: begin sig_out <= 1; sig_dir <= 1; if (trig_counter < TRIG_PULSE_CYCLES) begin trig_counter <= trig_counter + 1; end else begin trig_counter <= 0; state <= TRIG_LOW; end end TRIG_LOW: begin sig_out <= 0; sig_dir <= 0; // Mettre en entrée if (sig_ok) begin state <= TRIG_LOW; end else state <= WAIT_ECHO; end WAIT_ECHO: begin if (sig_ok) begin echo_counter <= 0; state <= MEASURE_ECHO; end else if (echo_counter >= TIMEOUT_CYCLES) begin distance <= 0; state <= DONE; end else begin echo_counter <= echo_counter + 1; end end MEASURE_ECHO: begin if (sig_ok) begin if (echo_counter < TIMEOUT_CYCLES) begin echo_counter <= echo_counter + 1; end else begin state <= DONE; end end else begin state <= COMPUTE; end end COMPUTE: begin if (echo_counter >= DIST_DIVISOR) begin echo_counter <= echo_counter - DIST_DIVISOR; distance_counter <= distance_counter + 1; state <= COMPUTE; end else begin distance <= distance_counter; state <= DONE; end end DONE: begin if (start) begin wait_counter <= 0; state <= WAIT_NEXT; end else begin state <= IDLE; end end WAIT_NEXT: begin wait_counter <= wait_counter + 1; if (wait_counter >= WAIT_NEXT_CYCLES) begin state <= TRIG_HIGH; trig_counter <= 0; distance_counter <= 0; echo_counter <= 0; end end default: begin state <= IDLE; // Reset to IDLE state in case of an error end endcase end endmodule