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. »