Implémentation d'un afficheur dynamique à 7 segments sur Zynq-FPGA

Le projet vise à utiliser quatre interrupteurs DIP pour représenter des valeurs binaires (0 ou 1). Ces quatre bits seront convertis en une valeur décimale affichée sur le chiffre le plus significatif d'un afficheur à 6 chiffres. Les quatre chiffres restants présenteront le code BCD correspondant à la valeur lue sur les interrupteurs DIP.

Analyse des Exigences

Correspondance Décimale et Code BCD

Voici la table de correspondance entre les nombres décimaux et leur représentation en code BCD 8421 :


| Code 8421 | Nombre Décimal |
|---|---|
| 0000 | 0 |
| 0001 | 1 |
| 0010 | 2 |
| 0011 | 3 |
| 0100 | 4 |
| 0101 | 5 |
| 0110 | 6 |
| 0111 | 7 |
| 1000 | 8 |
| 1001 | 9 |
 

Principe d'Affichage sur un Afficheur 7 Segments

L'affichage sur un afficheur 7 segments peut être réalisé de deux manières : statique ou dynamique. L'affichage statique présente la même information sur tous les segments, tandis que l'affichage dynamique permet d'afficher des informations différentes sur chaque segment séquentiellement.

  • Affichage Statique : Il requiert deux types de signaux de contrôle : la sélection de l'afficheur (digit select) et la sélection du segment (segment select). Les signaux de sélection de segment sont généralement câblés en commun pour tous les afficheurs. Ainsi, un seul afficheur est activé à la fois par le signal de sélection de digit, et il affiche la valeur définie par les signaux de sélection de segment.
  • Affichage Dynamique : Ce mode exploite la persistance rétinienne de l'œil humain et l'effet rémanent des afficheurs. En faisant défiler rapidement les différentes valeurs sur chaque afficheur, l'observateur perçoit une image stable affichant des informations distinctes simultanément.

Conception des Modules

Le système est décomposé en trois modules principaux :

Module Description
Top_seg Module de niveau supérieur, responsable de l'interconnexion des signaux entre les différents modules.
data_change Module de conversion des données. Il transforme l'entrée binaire des interrupteurs DIP en signaux numériques appropriés pour l'affichage.
Seg_dynamic Module de balayage dynamique pour l'afficheur 7 segments. Il gère le multiplexage des afficheurs pour créer l'effet d'affichage dynamique.

Conception des Formes d'Onde

Le signal Data_BCD représente la valeur binaire des quatre interrupteurs d'entrée. Le signal seg_en est utilisé pour contrôler le balayage dynamique de l'afficheur. Dans cette implémentation, il est maintenu à l'état haut.

Lors de la conception logique séquentielle, il est courant de rencontrer des retards d'un cycle d'horloge dans la propagation des données. Pour assurer la synchronisation des données, des registrse sont utilisés pour mémoriser les valeurs nécessaires.

Implémentation du Code

Module de Haut Niveau (Top-level)


module top_seg(
   input wire sys_clk,
   input wire sys_rst_n,
   input wire key_in_0,
   input wire key_in_1,
   input wire key_in_2,
   input wire key_in_3,

   output wire [5:0] sel,
   output wire [7:0] seg
);

wire [3:0] data_bcd;
wire seg_en;

data_change data_change_inst (
   .sys_clk    (sys_clk),
   .sys_rst_n  (sys_rst_n),
   .key_in_0   (key_in_0),
   .key_in_1   (key_in_1),
   .key_in_2   (key_in_2),
   .key_in_3   (key_in_3),
   .data_bcd   (data_bcd),
   .seg_en     (seg_en)
);

seg_dynamic seg_dynamic_inst (
   .sys_clk    (sys_clk),
   .sys_rst_n  (sys_rst_n),
   .data_bcd   (data_bcd),
   .seg_en     (seg_en),
   .sel        (sel),
   .seg        (seg)
);

endmodule
 

Module de Conversion de Données


module data_change(
   input wire sys_clk,
   input wire sys_rst_n,
   input wire key_in_0,
   input wire key_in_1,
   input wire key_in_2,
   input wire key_in_3,

   output reg [3:0] data_bcd,
   output reg seg_en
);

always @(posedge sys_clk or negedge sys_rst_n) begin
   if (!sys_rst_n) begin
       data_bcd <= 4'd0;
       seg_en <= 1'b0;
   end else begin
       data_bcd <= {key_in_0, key_in_1, key_in_2, key_in_3};
       seg_en <= 1'b1;
   end
end

endmodule
 

Module de Balayage Dynamique d'Afficheur


module seg_dynamic(
   input wire sys_clk,
   input wire sys_rst_n,
   input wire [3:0] data_bcd,
   input wire seg_en,

   output reg [5:0] sel,
   output reg [7:0] seg
);

parameter CNT_MAX = 16'd49_999;

reg [24:0] cnt_1ms;
reg seg_update_flag;
reg [2:0] digit_selector;
reg [5:0] current_digit_sel;
reg [3:0] current_digit_data;

// Compteur pour générer une base de temps (approximativement 1ms avec une horloge de 50MHz)
always @(posedge sys_clk or negedge sys_rst_n) begin
   if (!sys_rst_n) begin
       cnt_1ms <= 16'd0;
   end else if (cnt_1ms == CNT_MAX) begin
       cnt_1ms <= 16'd0;
   end else begin
       cnt_1ms <= cnt_1ms + 1'b1;
   end
end

// Drapeau pour indiquer la fin d'une période de compteur
always @(posedge sys_clk or negedge sys_rst_n) begin
   if (!sys_rst_n) begin
       seg_update_flag <= 1'b0;
   end else if (cnt_1ms == CNT_MAX - 1) begin
       seg_update_flag <= 1'b1;
   end else begin
       seg_update_flag <= 1'b0;
   end
end

// Compteur pour sélectionner le chiffre à afficher
always @(posedge sys_clk or negedge sys_rst_n) begin
   if (!sys_rst_n) begin
       digit_selector <= 3'd0;
   end else if (seg_update_flag) begin
       if (digit_selector == 3'd5) begin // Si on a balayé les 6 chiffres, revenir au premier
           digit_selector <= 3'd0;
       end else begin
           digit_selector <= digit_selector + 1'b1;
       end
   end else begin
       digit_selector <= digit_selector; // Maintenir la valeur si pas de mise à jour
   end
end

// Logique pour sélectionner le chiffre actif (digit select)
always @(posedge sys_clk or negedge sys_rst_n) begin
   if (!sys_rst_n) begin
       current_digit_sel <= 6'b111_111; // Tous les afficheurs désactivés initialement
   end else begin
       case (digit_selector)
           3'd0: current_digit_sel <= 6'b111_110; // Afficher le chiffre le plus significatif (dizaines de milliers)
           3'd1: current_digit_sel <= 6'b111_101; // Chiffre 4
           3'd2: current_digit_sel <= 6'b111_011; // Chiffre 3
           3'd3: current_digit_sel <= 6'b110_111; // Chiffre 2
           3'd4: current_digit_sel <= 6'b101_111; // Chiffre 1
           3'd5: current_digit_sel <= 6'b011_111; // Chiffre 0 (le moins significatif)
           default: current_digit_sel <= 6'b111_111; // Désactivation par défaut
       endcase
   end
end

// Logique pour préparer les données à afficher sur le segment (segment select)
always @(posedge sys_clk or negedge sys_rst_n) begin
   if (!sys_rst_n) begin
       current_digit_data <= 4'd0;
   end else begin
       case (digit_selector)
           3'd0: current_digit_data <= data_bcd; // Les 4 bits des DIP pour le chiffre le plus significatif
           3'd1: current_digit_data <= {4'b00, data_bcd[3]}; // BCD digit 3
           3'd2: current_digit_data <= {4'b00, data_bcd[2]}; // BCD digit 2
           3'd3: current_digit_data <= {4'b00, data_bcd[1]}; // BCD digit 1
           3'd4: current_digit_data <= {4'b00, data_bcd[0]}; // BCD digit 0
           3'd5: current_digit_data <= 4'b0000;       // Afficher 0 pour le chiffre le plus significatif (qui sera le 6ème)
           default: current_digit_data <= 4'b0000;
       endcase
   end
end

// Mapping des données BCD vers les segments de l'afficheur 7 segments
always @(*) begin // Utilisation d'un bloc always @(*) pour une assignation combinatoire
   case (current_digit_data)
       4'd0: seg = 8'h3f; // '0'
       4'd1: seg = 8'h06; // '1'
       4'd2: seg = 8'h5b; // '2'
       4'd3: seg = 8'h4f; // '3'
       4'd4: seg = 8'h66; // '4'
       4'd5: seg = 8'h6d; // '5'
       4'd6: seg = 8'h7d; // '6'
       4'd7: seg = 8'h07; // '7'
       4'd8: seg = 8'h7f; // '8'
       4'd9: seg = 8'h6f; // '9'
       default: seg = 8'h79; // Par défaut, afficher un caractère non défini ou un espace '---'
   endcase
end

// Assignation finale du signal de sélection du digit
always @(posedge sys_clk or negedge sys_rst_n) begin
   if (!sys_rst_n) begin
       sel <= 6'd0;
   end else begin
       sel <= current_digit_sel;
   end
end

endmodule
 

Vue RTL

La vue RTL révèle des opportunités d'amélioration, notammant dans la partie de sélection multi-voies qui n'est pas complètement implémentée dans sa forme actuelle.

Écriture du Testbench


module tb_seg();

reg sys_clk;
reg sys_rst_n;
reg key_in_0;
reg key_in_1;
reg key_in_2;
reg key_in_3;

wire [5:0] sel;
wire [7:0] seg;

initial begin
   sys_clk <= 1'b1;
   sys_rst_n <= 1'b0;
   key_in_0 <= 1'b0;
   key_in_1 <= 1'b0;
   key_in_2 <= 1'b0;
   key_in_3 <= 1'b0;

   #20; // Attendre un peu
   sys_rst_n <= 1'b1; // Libérer la réinitialisation

   // Générer des valeurs aléatoires pour les entrées après un certain temps
   #100_000; // Attendre un peu avant de changer les entrées
   key_in_0 <= 1'b1; // Activer le MSB pour le premier test
   #200_000;
   key_in_1 <= 1'b1;
   #200_000;
   key_in_2 <= 1'b1;
   #200_000;
   key_in_3 <= 1'b1;
   #200_000;
   key_in_0 <= 1'b0;
   key_in_1 <= 1'b0;
   key_in_2 <= 1'b0;
   key_in_3 <= 1'b0;
   #200_000;

end

// Génération de l'horloge
always #10 sys_clk = ~sys_clk;

// Génération aléatoire pour certaines entrées (optionnel, peut être remplacé par des séquences spécifiques)
// always #100_007 key_in_1 = {$random} % 2;
// always #100_007 key_in_2 = {$random} % 2;
// always #100_007 key_in_3 = {$random} % 2;

// Instanciation du module à tester
top_seg top_seg_inst (
   .sys_clk    (sys_clk),
   .sys_rst_n  (sys_rst_n),
   .key_in_0   (key_in_0),
   .key_in_1   (key_in_1),
   .key_in_2   (key_in_2),
   .key_in_3   (key_in_3),
   .sel        (sel),
   .seg        (seg)
);

endmodule
 

Résultats de Simulation

Test sur Matériel (Board Test)

Contenu Futur

Sans un suivi d'apprentissage systématique, il est difficile de déterminer le prochain projet après la réalisation d'un module. Il est essentiel de planifier les étapes futures à l'avance.

Le prochain projet de la section FPGA sera le dernier : le pilotage d'une caméra. Il permettra d'approfondir des sujets tels que : le protocole de communication IIC, le protocole SPI, la communication UART, les FIFO, la SDRAM, etc.

« Persévérer sans relâche, l'avenir est prometteur. »

Étiquettes: FPGA Zynq Afficheur 7 segments Verilog Système embarqué

Publié le 12 août à 17h04