From c6d33d278e4ff70c3ea4e887e66493e209095d98 Mon Sep 17 00:00:00 2001 From: Gamenight77 Date: Fri, 25 Apr 2025 10:21:18 +0200 Subject: [PATCH] Implement distance measurement and display modules: add ultrasonic sensor, FPGA logic, LED display, and WS2812 driver for enhanced distance visualization --- .../distance_display_led.v | 29 ++++ .../tb_distance_display_led.v | 26 ++++ .../Ultrasonic/tb_ultrasonic_fpga.v | 59 ++++++++ .../Ultrasonic/ultrasonic_fpga.v | 127 ++++++++++++++++++ .../Ultrasonic/ultrasonic_sensor.v | 46 +++++-- .../distance_ws2812_display.v | 27 ++++ .../tb_distance_ws2812_display.v | 34 +++++ .../distance_ws2812_display/ws2812_driver.v | 27 ++++ .../tb_top_ultrasonic_led.v | 61 +++++++++ .../top_ultrasonic_led.v | 32 +++++ 10 files changed, 454 insertions(+), 14 deletions(-) create mode 100644 Semaine_2/Capteur_recule_bidirectionel_V2/Distance_display_led/distance_display_led.v create mode 100644 Semaine_2/Capteur_recule_bidirectionel_V2/Distance_display_led/tb_distance_display_led.v create mode 100644 Semaine_2/Capteur_recule_bidirectionel_V2/Ultrasonic/tb_ultrasonic_fpga.v create mode 100644 Semaine_2/Capteur_recule_bidirectionel_V2/Ultrasonic/ultrasonic_fpga.v rename {Semaine_1/Capteur_recule_bidirectionel => Semaine_2/Capteur_recule_bidirectionel_V2}/Ultrasonic/ultrasonic_sensor.v (58%) create mode 100644 Semaine_2/Capteur_recule_bidirectionel_V2/distance_ws2812_display/distance_ws2812_display.v create mode 100644 Semaine_2/Capteur_recule_bidirectionel_V2/distance_ws2812_display/tb_distance_ws2812_display.v create mode 100644 Semaine_2/Capteur_recule_bidirectionel_V2/distance_ws2812_display/ws2812_driver.v create mode 100644 Semaine_2/Capteur_recule_bidirectionel_V2/tb_top_ultrasonic_led.v create mode 100644 Semaine_2/Capteur_recule_bidirectionel_V2/top_ultrasonic_led.v diff --git a/Semaine_2/Capteur_recule_bidirectionel_V2/Distance_display_led/distance_display_led.v b/Semaine_2/Capteur_recule_bidirectionel_V2/Distance_display_led/distance_display_led.v new file mode 100644 index 0000000..701489a --- /dev/null +++ b/Semaine_2/Capteur_recule_bidirectionel_V2/Distance_display_led/distance_display_led.v @@ -0,0 +1,29 @@ +module distance_display_led ( + input wire [8:0] distance, + output reg [5:0] leds +); + + // Constante + parameter MIN_DIST = 2; + parameter MAX_DIST = 349; + parameter LEVELS = 5; + parameter PART_SIZE = (MAX_DIST - MIN_DIST + 1) / LEVELS; + + always @(*) begin + if (distance <= MIN_DIST + PART_SIZE*0) + leds = 6'b111111; + else if (distance <= MIN_DIST + PART_SIZE*1) + leds = 6'b111110; + else if (distance <= MIN_DIST + PART_SIZE*2) + leds = 6'b111100; + else if (distance <= MIN_DIST + PART_SIZE*3) + leds = 6'b111000; + else if (distance <= MIN_DIST + PART_SIZE*4) + leds = 6'b110000; + else if (distance <= MIN_DIST + PART_SIZE*5) + leds = 6'b100000; + else + leds = 6'b000000; + end + +endmodule \ No newline at end of file diff --git a/Semaine_2/Capteur_recule_bidirectionel_V2/Distance_display_led/tb_distance_display_led.v b/Semaine_2/Capteur_recule_bidirectionel_V2/Distance_display_led/tb_distance_display_led.v new file mode 100644 index 0000000..d8968ca --- /dev/null +++ b/Semaine_2/Capteur_recule_bidirectionel_V2/Distance_display_led/tb_distance_display_led.v @@ -0,0 +1,26 @@ +module tb_distance_display_led; + reg [8:0] distance; + wire [5:0] leds; + + distance_display_led uut ( + .distance(distance), + .leds(leds) + ); + + integer i; + + initial begin + $dumpfile("distance_display_led.vcd"); + $dumpvars(0, tb_distance_display_led); + + // Test de la conversion de distance en LED + for (i = 0; i <= 380; i = i + 10) begin + distance = i; + #10; + $display("Distance: %3d cm => LEDs: %b", distance, leds); + end + + $finish; + end + +endmodule diff --git a/Semaine_2/Capteur_recule_bidirectionel_V2/Ultrasonic/tb_ultrasonic_fpga.v b/Semaine_2/Capteur_recule_bidirectionel_V2/Ultrasonic/tb_ultrasonic_fpga.v new file mode 100644 index 0000000..479b846 --- /dev/null +++ b/Semaine_2/Capteur_recule_bidirectionel_V2/Ultrasonic/tb_ultrasonic_fpga.v @@ -0,0 +1,59 @@ +`timescale 1ns/1ps + +module tb_ultrasonic_fpga; + + reg clk = 0; + reg rst = 1; + reg start = 0; + wire sig; + wire [8:0] distance; + + time t_start, t_end; + + // Clock 27MHz => periode = 37ns + always #18 clk = ~clk; + + ultrasonic_fpga uut ( + .clk(clk), + .rst(rst), + .start(start), + .sig(sig), + .distance(distance) + ); + + ultrasonic_sensor sensor ( + .clk(clk), + .signal(sig) + ); + + initial begin + $dumpfile("ultrasonic.vcd"); + $dumpvars(0, tb_ultrasonic_fpga); + + // Reset + #100; + rst = 0; + + // Start + #100; + start = 1; + #40; + start = 0; + + // Attendre que la distance soit mesurée + wait (distance > 0); + #10; // petite marge pour stabiliser + $display("Distance mesurée: %d cm", distance); + + + // Affiche la distance + if (distance > 0) begin + $display("Distance measured: %d cm", distance); + end else begin + $display("No distance measured."); + end + + $finish; + end + +endmodule diff --git a/Semaine_2/Capteur_recule_bidirectionel_V2/Ultrasonic/ultrasonic_fpga.v b/Semaine_2/Capteur_recule_bidirectionel_V2/Ultrasonic/ultrasonic_fpga.v new file mode 100644 index 0000000..742240c --- /dev/null +++ b/Semaine_2/Capteur_recule_bidirectionel_V2/Ultrasonic/ultrasonic_fpga.v @@ -0,0 +1,127 @@ +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 = IDLE +); + reg [15:0] trig_counter; + reg [31:0] echo_counter; + reg [31:0] echo_div_counter; + reg [15:0] distance_counter; + + 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; + + always_ff(@posedge clk) {sig_ok, sig_int} = {sig_int, sig}; + + localparam IDLE = 3'd0, + TRIG_HIGH = 3'd1, + TRIG_LOW = 3'd2, + WAIT_ECHO = 3'd3, + MEASURE_ECHO = 3'd4, + DONE = 3'd5, + WAIT_NEXT = 3'd6; + + 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) / 1_000_000; + + localparam WAIT_NEXT_CYCLES = (CLK_FREQ / 1000) * 100; // 60 ms + + reg [31:0] wait_counter; + + always @(posedge clk) begin // FSM + + case (state) + IDLE: begin + sig_out <= 0; + sig_dir <= 1; + 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 + 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 + distance <= 0; + state <= DONE; + end + end else begin //Comptage par cycle de dist diviseur + echo_counter <= echo_counter + 1; + + if (echo_div_counter >= DIST_DIVISOR - 1) begin + echo_div_counter <= 0; + distance_counter <= distance_counter + 1; + end else begin + echo_div_counter <= echo_div_counter + 1; + end + + 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; + end + end + + endcase + + end + +endmodule \ No newline at end of file diff --git a/Semaine_1/Capteur_recule_bidirectionel/Ultrasonic/ultrasonic_sensor.v b/Semaine_2/Capteur_recule_bidirectionel_V2/Ultrasonic/ultrasonic_sensor.v similarity index 58% rename from Semaine_1/Capteur_recule_bidirectionel/Ultrasonic/ultrasonic_sensor.v rename to Semaine_2/Capteur_recule_bidirectionel_V2/Ultrasonic/ultrasonic_sensor.v index 201886e..18740e6 100644 --- a/Semaine_1/Capteur_recule_bidirectionel/Ultrasonic/ultrasonic_sensor.v +++ b/Semaine_2/Capteur_recule_bidirectionel_V2/Ultrasonic/ultrasonic_sensor.v @@ -1,18 +1,23 @@ -module ultrasonic_sensor(// Simulation of an ultrasonic sensor +module ultrasonic_sensor( // Simulation of an ultrasonic sensor input wire clk, - inout wire signal, // Signal from the ultrasonic sensor + inout wire signal, // Signal from the ultrasonic sensor ); - reg [2:0] state, next_state; - reg sig_dir; // 1: output, 0: input - reg [15:0] trig_counter; // Counter for the trigger pulse - reg [31:0] echo_counter; // Echo signal - reg valid_trig; // Valid trigger signal + parameter integer CLK_FREQ = 27_000_000; - reg echo_sended; // Flag to indicate if echo has been sent + reg [2:0] state, next_state; + reg sig_dir; // 1: output, 0: input + reg [15:0] trig_counter; // Counter for the trigger pulse + reg [31:0] echo_counter; // Echo signal + reg valid_trig; // Valid trigger signal + + reg echo_sended; // Flag to indicate if echo has been sent + + reg signal_out; + assign signal = sig_dir ? signal_out : 1'bz; // Assign the signal to the output if sig_dir is high, otherwise set it to high impedance localparam S_WAIT_TRIG = 3'd0, S_MEASURE_TRIG = 3'd1, - S_SEND_ECHO = 3'd2, + S_SEND_ECHO = 3'd2; localparam integer TRIG_PULSE_CYCLES = CLK_FREQ / 100_000; // 10us pulse @@ -41,12 +46,8 @@ module ultrasonic_sensor(// Simulation of an ultrasonic sensor echo_sended = 0; // Reset flag next_state = S_WAIT_TRIG; end else begin - signal = 1; // Send echo signal - #5800; // Wait for 5800ns (≈ 100 cycles @ 27MHz => ≈ 100 cm aller-retour) - signal = 0; // Stop sending echo signal - echo_sended = 1; // Set flag to indicate echo has been sent + next_state = S_SEND_ECHO; end - next_state = S_WAIT_TRIG; end default: begin @@ -76,4 +77,21 @@ module ultrasonic_sensor(// Simulation of an ultrasonic sensor end end end + + reg [15:0] echo_delay_counter; + + always @(posedge clk) begin + if (state == S_SEND_ECHO) begin + if (echo_delay_counter == 5800) begin // + signal_out <= 0; + echo_sended <= 1; + end else begin + signal_out <= 1; + echo_delay_counter <= echo_delay_counter + 1; + end + end else begin + echo_delay_counter <= 0; + end + end + endmodule \ No newline at end of file diff --git a/Semaine_2/Capteur_recule_bidirectionel_V2/distance_ws2812_display/distance_ws2812_display.v b/Semaine_2/Capteur_recule_bidirectionel_V2/distance_ws2812_display/distance_ws2812_display.v new file mode 100644 index 0000000..ed1af99 --- /dev/null +++ b/Semaine_2/Capteur_recule_bidirectionel_V2/distance_ws2812_display/distance_ws2812_display.v @@ -0,0 +1,27 @@ +module distance_ws2812_display( + input wire clk, + input wire [8:0] distance, // distance mesurer + output wire ws2812_dout // broche de données pour la LED WS2812 +); + + reg [23:0] led_color; // couleur à envoyer à la LED (format RGB) + + always @(posedge clk) begin + // Mapper la distance sur une couleur + if (distance < 100) begin + led_color <= 24'hFF0000; // Rouge (proche) + end else if (distance < 200) begin + led_color <= 24'hFFFF00; // Jaune (distance moyenne) + end else begin + led_color <= 24'h00FF00; // Vert (très loin) + end + end + + // Instance du module de transmission pour WS2812 + ws2812_driver ws2812_inst ( + .clk(clk), + .color(led_color), + .ws2812_dout(ws2812_dout) + ); + +endmodule \ No newline at end of file diff --git a/Semaine_2/Capteur_recule_bidirectionel_V2/distance_ws2812_display/tb_distance_ws2812_display.v b/Semaine_2/Capteur_recule_bidirectionel_V2/distance_ws2812_display/tb_distance_ws2812_display.v new file mode 100644 index 0000000..b889ea3 --- /dev/null +++ b/Semaine_2/Capteur_recule_bidirectionel_V2/distance_ws2812_display/tb_distance_ws2812_display.v @@ -0,0 +1,34 @@ +// Testbench pour distance_ws2812_display +module tb_distance_ws2812_display; + + reg clk; + reg [8:0] distance; + wire ws2812_dout; + + // Instance du module à tester + distance_ws2812_display uut ( + .clk(clk), + .distance(distance), + .ws2812_dout(ws2812_dout) + ); + + always #5 clk = ~clk; + integer i; + initial begin + // Initialiser les signaux + clk = 0; + distance = 0; + + $dumpfile("distance_ws2812_display.vcd"); + $dumpvars(0, tb_distance_ws2812_display); + + // Test de la conversion de distance en LED + for (i = 0; i <= 380; i = i + 10) begin + distance = i; + #10; + $display("Distance: %3d cm => dout: %b", distance, ws2812_dout); + end + + #100 $stop; // Arrêter la simulation après un certain temps + end +endmodule diff --git a/Semaine_2/Capteur_recule_bidirectionel_V2/distance_ws2812_display/ws2812_driver.v b/Semaine_2/Capteur_recule_bidirectionel_V2/distance_ws2812_display/ws2812_driver.v new file mode 100644 index 0000000..c26751d --- /dev/null +++ b/Semaine_2/Capteur_recule_bidirectionel_V2/distance_ws2812_display/ws2812_driver.v @@ -0,0 +1,27 @@ +module ws2812_driver( + input wire clk, + input wire [23:0] color, // couleur RGB (8 bits par composant) + output reg ws2812_dout // broche de données vers la LED +); + reg [7:0] bit_count; // compteur de bits pour envoyer les données + reg [23:0] shift_reg; // registre pour envoyer la couleur + + always @(posedge clk) begin + + if (bit_count == 0) begin + shift_reg <= color; // Charger la couleur à transmettre + ws2812_dout <= 1'b0; // Commencer par envoyer un "0" + end else begin + // Envoyer chaque bit un à un en contrôlant la durée de l'impulsion + ws2812_dout <= shift_reg[23]; // Le bit le plus significatif + shift_reg <= shift_reg << 1; // Décalage des bits + end + // Incrémentation du compteur de bits + if (bit_count < 24) + bit_count <= bit_count + 1; + else + bit_count <= 0; // Réinitialiser pour envoyer la prochaine couleur + + end +endmodule + diff --git a/Semaine_2/Capteur_recule_bidirectionel_V2/tb_top_ultrasonic_led.v b/Semaine_2/Capteur_recule_bidirectionel_V2/tb_top_ultrasonic_led.v new file mode 100644 index 0000000..75dd7db --- /dev/null +++ b/Semaine_2/Capteur_recule_bidirectionel_V2/tb_top_ultrasonic_led.v @@ -0,0 +1,61 @@ +`timescale 1ns/1ps + +module tb_top_ultrasonic_led; + + reg clk; + reg rst; + reg start; + reg echo; + wire trig; + wire [5:0] leds; + + // Instance du module top + top_ultrasonic_led uut ( + .clk(clk), + .rst(rst), + .start(start), + .echo(echo), + .trig(trig), + .leds(leds) + ); + + always #18.5 clk = ~clk; + + initial begin + // Initialisation + $dumpfile("top_ultrasonic_led.vcd"); + $dumpvars(0, tb_top_ultrasonic_led); + + clk = 0; + rst = 1; + start = 0; + echo = 0; + + #100; + rst = 0; + + #50; + start = 1; + #20; + start = 0; + + // Attente du signal trig + wait (trig == 1); + $display("TRIG HIGH at %t", $time); + wait (trig == 0); + $display("TRIG LOW at %t", $time); + + repeat (500) @(posedge clk); + echo = 1; + #12000 + + echo = 0; + + repeat (500) @(posedge clk); + + $display("Leds allumer : %b", leds); + + $finish; + end + +endmodule diff --git a/Semaine_2/Capteur_recule_bidirectionel_V2/top_ultrasonic_led.v b/Semaine_2/Capteur_recule_bidirectionel_V2/top_ultrasonic_led.v new file mode 100644 index 0000000..ae29ccd --- /dev/null +++ b/Semaine_2/Capteur_recule_bidirectionel_V2/top_ultrasonic_led.v @@ -0,0 +1,32 @@ +module top_ultrasonic_led ( + input wire clk, + input wire start, // bouton de déclenchement + inout wire sig, // broche unique pour trigger + echo + output wire [5:0] leds // LEDs pour affichage distance + output wire ws2812_dout // broche de données pour la LED WS2812 (optionnel) +); + + wire [8:0] distance; + + // Module de mesure (version bidirectionnelle du capteur) + ultrasonic_fpga ultrasonic_inst ( + .clk(clk), + .start(start), + .sig(sig), + .distance(distance) + ); + + // Module d'affichage LEDs + distance_display_led led_display_inst ( + .distance(distance), + .leds(leds) + ); + + // Module d'affichage WS2812 (optionnel, si vous souhaitez utiliser une LED RGB) + distance_ws2812_display ws2812_display_inst ( + .clk(clk), + .distance(distance), + .ws2812_dout(ws2812_dout) + ); + +endmodule