基于Verilog的7段数码管动态扫描驱动模块设计

1、7段数码管动态扫描驱动模块概述

功能:通过动态扫描方式驱动6位共阳极7段数码管

特性:

(1)支持6位数码管显示(24位输入数据,每4位代表一个数字)

(2)采用动态扫描技术,降低功耗

(3)支持十六进制显示(0-F)

(4)带异步复位功能

2、7段数码管模块硬件原理图+6位一体共阳极数码管

3、7段数码管动态扫描驱动模块的Verilog描述

 

  1 module disp7led_dyna(
  2 
  3     input        wire                 clk,        // 系统时钟输入(50MHz)
  4     input     wire                 rst_n,    // 异步复位信号,低电平有效
  5     input        wire     [23:0]    data_in,    // 24位显示数据输入,[23:20]为第1位,[3:0]为第6位
  6     output     reg    [5:0]        sel6,        // 6位数码管位选信号(低电平有效,sel6[0]对应第1位)
  7     output     reg    [7:0]        seg7        // 7段+小数点输出(低电平有效,seg7[7]为小数点)
  8 );    
  9 
 10     parameter DELAY_1MS = 16'd50_000;    // 1ms延时计数值,数码管扫描时间
 11     
 12     // 内部寄存器定义
 13     reg [15:0]     count;        // 1ms定时计数器(16位宽度可支持最大65535个周期)
 14     reg [2:0]     cnt;            // 当前显示位计数器(0-5对应6位数码管)
 15     reg [3:0]      show_data;    // 当前要显示的数字(4位二进制,可表示0-15)
 16     
 17     
 18      //------------------------------------------------------------------
 19     // 1ms定时器生成逻辑
 20     // 功能:产生精确的1ms时间间隔,用于数码管动态扫描
 21     // 工作原理:在50MHz时钟下,每计数50,000次产生一个1ms标志
 22     //------------------------------------------------------------------    
 23     always@(posedge clk or negedge rst_n)begin
 24         if(rst_n == 1'b0)
 25             count <= 16'b0;            // 异步复位,计数器清零
 26         else if(count < DELAY_1MS - 1'b1)
 27             count <= count + 1'b1;    // 计数器递增
 28         else
 29             count <= 16'b0;             // 达到1ms时计数器归零
 30     end
 31     
 32      //------------------------------------------------------------------
 33     // 数码管位选择计数器
 34     // 功能:循环计数0-5,对应6位数码管
 35     // 扫描频率:每1ms切换一位,6ms完成一个完整扫描周期(约167Hz刷新率)
 36     //------------------------------------------------------------------
 37     always@(posedge clk or negedge rst_n)begin
 38         if(rst_n == 1'b0)
 39             cnt <= 3'd0;        // 复位时指向第1位数码管
 40         else if(count == DELAY_1MS - 1'b1)begin    // 每1ms更新一次
 41             if(cnt < 3'd6)
 42                 cnt <= cnt + 1'b1;    // 循环计数0→1→2→3→4→5
 43             else
 44                 cnt <= 3'd0;    // 计数到5后归零
 45         end
 46         else
 47             cnt <= cnt;            // 保持当前计数值
 48     end
 49     
 50      //------------------------------------------------------------------
 51     // 数据选择器(多路复用器)
 52     // 功能:根据当前位选择对应4位数据输出
 53     // 注意:这是组合逻辑电路,无时钟延迟
 54     //------------------------------------------------------------------
 55     always@(*)begin
 56         case(cnt)
 57             3'd0: show_data = data_in[23:20];    // 选择第1位数据(最高4位)
 58             3'd1: show_data = data_in[19:16];    // 选择第2位数据
 59             3'd2: show_data = data_in[15:12];    // 选择第3位数据
 60             3'd3: show_data = data_in[11:8];        // 选择第4位数据
 61             3'd4: show_data = data_in[7:4];        // 选择第5位数据
 62             3'd5: show_data = data_in[3:0];        // 选择第6位数据(最低4位)
 63         default: show_data = 4'b0000;                // 默认情况(理论上不会发生)
 64         endcase
 65     end
 66     
 67      //------------------------------------------------------------------
 68     // 7段译码器(带小数点)
 69     // 功能:将4位二进制数转换为7段数码管控制信号
 70     // 编码规则(共阳极数码管,低电平有效):
 71     //   seg7[7] = dp (小数点)
 72     //   seg7[6:0] = g f e d c b a (从高位到低位)
 73     // 注意:此实现未使用小数点(默认熄灭)
 74     //------------------------------------------------------------------
 75     always@(posedge clk or negedge rst_n)begin
 76         if(rst_n == 1'b0)
 77             seg7 <= 8'b1111_1111;    // 复位时关闭所有段
 78         else
 79             case(show_data)
 80                 4'd0:    seg7 = 8'b1100_0000;    // 显示"0"
 81                 4'd1:    seg7 = 8'b1111_1001;    // 显示"1"    
 82                 4'd2:    seg7 = 8'b1010_0100;    // 显示"2"
 83                 4'd3:    seg7 = 8'b1011_0000;    // 显示"3"
 84                 4'd4:    seg7 = 8'b1001_1001;    // 显示"4"
 85                 4'd5:    seg7 = 8'b1001_0010;    // 显示"5"
 86                 4'd6:    seg7 = 8'b1000_0010;    // 显示"6"
 87                 4'd7:    seg7 = 8'b1111_1000;    // 显示"7"
 88                 4'd8:    seg7 = 8'b1000_0000;    // 显示"8"
 89                 4'd9:    seg7 = 8'b1001_0000;    // 显示"9"
 90                 4'd10:seg7 = 8'b1000_1000;    // 显示"A"   
 91                 4'd11:seg7 = 8'b1000_0011;    // 显示"b"
 92                 4'd12:seg7 = 8'b1100_0110;    // 显示"C"
 93                 4'd13:seg7 = 8'b1010_0001;    // 显示"d"
 94                 4'd14:seg7 = 8'b1000_0110;    // 显示"E"
 95                 4'd15:seg7 = 8'b1000_1110;    // 显示"F"
 96             default:    seg7 <= 8'b1111_1111;    // 默认关闭所有段
 97             endcase
 98     end
 99     
100      //------------------------------------------------------------------
101     // 位选信号生成器
102     // 功能:根据当前位计数器生成对应的位选信号
103     // 特性:
104     //   - 低电平有效(0表示选中对应位数码管)
105     //   - 每次只选中一位,实现动态扫描
106     //------------------------------------------------------------------
107     always@(posedge clk or negedge rst_n)begin
108         if(rst_n == 1'b0)
109             sel6 <= 6'b11_1111;        // 复位时关闭所有位数码管
110         case(cnt)
111             3'd0: sel6 <= 6'b11_1110;    // 选中第1位数码管(sel6[0]=0)
112             3'd1: sel6 <= 6'b11_1101;    // 选中第2位数码管(sel6[1]=0)
113             3'd2: sel6 <= 6'b11_1011;    // 选中第3位数码管(sel6[2]=0)
114             3'd3: sel6 <= 6'b11_0111;    // 选中第4位数码管(sel6[3]=0)
115             3'd4: sel6 <= 6'b10_1111;    // 选中第5位数码管(sel6[4]=0)
116             3'd5: sel6 <= 6'b01_1111;    // 选中第6位数码管(sel6[5]=0)
117         default: sel6 <= 6'b11_1111;     // 默认关闭所有位数码管
118         endcase
119     end
120     
121 endmodule 

4、7段数码管动态扫描驱动模块的测试平台

功能:对disp7led_dyna模块进行仿真测试

测试内容:复位功能测试、动态扫描时序测试、数据显示正确性测试

 1 `timescale 1ns/1ns    // 仿真时间单位1ns,精度1ns
 2 
 3 module disp7led_dyna_tb();
 4     
 5     // 测试信号定义
 6     reg                 clk;        // 模拟系统时钟信号(50MHz,周期20ns)
 7     reg                rst_n;    // 模拟异步复位信号,低电平有效
 8     reg     [23:0]    data_in;    // 模拟24位显示数据输入,[23:20]为第1位,[3:0]为第6位
 9     
10     wire    [5:0]        sel6;        // 监测位选信号输出(低电平有效,sel6[0]对应第1位)
11     wire    [7:0]        seg7;        // 监测段选信号输出(低电平有效,seg7[7]为小数点)
12     
13      // 实例化被测模块
14     disp7led_dyna uut(            
15         .clk            (clk),         // 连接测试时钟
16         .rst_n        (rst_n),         // 连接测试复位信号
17         .data_in        (data_in),     // 连接测试数据输入
18         .sel6            (sel6),         // 连接位选信号输出
19         .seg7            (seg7)         // 连接段选信号输出
20     );
21     
22     // 修改被测模块参数(缩短仿真时间)
23    // 将原1ms扫描间隔缩短为50个时钟周期(1us)
24     defparam uut.DELAY_1MS = 50;
25     
26     // 时钟信号生成(50MHz)
27     initial clk = 1'b0;        // 初始时钟置0
28     always #10 clk = ~clk;    // 每10ns翻转一次(周期20ns)
29     
30     // 测试激励生成
31     initial begin
32         rst_n = 1'b0;                 // 复位信号有效(低电平)
33         data_in = 24'h123456;    // 测试数据:6位数码管显示1-2-3-4-5-6
34         #203;                            // 等待203ns(超过10个时钟周期)
35         rst_n = 1'b1;                // 释放复位(开始正常工作)
36         
37         // 观察完整扫描周期
38       // 等待2个完整扫描周期(6位数×50周期×2次)
39         #(20*50*6*2);
40         $stop;        // 停止仿真(在Modelsim等工具中暂停)
41     end
42 
43 endmodule 
View Code

提示:当数码管的段选段(seg7)和位选段(sel)不同步时,就会导致选中的管子和想要显示的数字不是完全同步的,由于不同步的时间相对比较少,所以显示出错误的数字的时间较短,点亮的程度就会比较小,称为“鬼影”。

5、7段数码管动态扫描驱动顶层模块+开发板测试

  • 主要用于测试和展示disp7led_dyna模块的功能

  • 实际使用时,可将data_in替换为需要显示的真实数据

 1 // 7段数码管动态扫描驱动顶层模块
 2 // 功能:实例化动态扫描驱动模块并提供测试数据
 3 // 特性:
 4 //   1. 连接系统时钟和复位信号
 5 //   2. 提供固定的24位测试数据(0x123456)
 6 //   3. 输出数码管位选和段选信号
 7 module disp7led_dyna_top(
 8     input        wire                 clk,        // 系统时钟输入(50MHz)
 9     input     wire                 rst_n,    // 异步复位信号,低电平有效
10     output     wire    [5:0]        sel6,        // 6位数码管位选信号输出,低电平有效,sel6[0]对应最左边的数码管
11     output     wire    [7:0]        seg7        // 7段数码管段选信号输出(包含小数点)
12 );
13 
14     // 内部信号定义
15     wire     [23:0]    data_in;    // 24位显示数据线
16     
17     assign data_in = 24'h123456;      // 将24'h123456固定赋值给data_in
18     
19      // 动态扫描驱动模块实例化
20     // 将顶层模块的端口与驱动模块连接
21     disp7led_dyna uut(            
22         .clk            (clk),        // 连接系统时钟
23         .rst_n        (rst_n),        // 连接复位信号
24         .data_in        (data_in),    // 连接显示数据
25         .sel6            (sel6),         // 连接位选信号输出
26         .seg7            (seg7)        // 连接段选信号输出
27     );
28 
29 endmodule

 

posted @ 2025-03-29 11:22  FPGA9161  阅读(279)  评论(0)    收藏  举报