问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

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

创作时间:
作者:
@小白创作中心

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

引用
1
来源
1.
https://www.cnblogs.com/zclv/p/18799150

本文详细介绍了基于Verilog的7段数码管动态扫描驱动模块设计。通过动态扫描方式驱动6位共阳极7段数码管,支持十六进制显示(0-F),并带异步复位功能。文章提供了完整的Verilog代码实现,包括硬件原理图、模块描述、测试平台和顶层模块,适合电子工程和数字电路设计领域的读者深入学习。

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

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

特性:

  • 支持6位数码管显示(24位输入数据,每4位代表一个数字)
  • 采用动态扫描技术,降低功耗
  • 支持十六进制显示(0-F)
  • 带异步复位功能

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

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

module disp7led_dyna(
    input wire clk, // 系统时钟输入(50MHz)
    input wire rst_n, // 异步复位信号,低电平有效
    input wire [23:0] data_in, // 24位显示数据输入,[23:20]为第1位,[3:0]为第6位
    output reg [5:0] sel6, // 6位数码管位选信号(低电平有效,sel6[0]对应第1位)
    output reg [7:0] seg7 // 7段+小数点输出(低电平有效,seg7[7]为小数点)
);

parameter DELAY_1MS = 16'd50_000; // 1ms延时计数值,数码管扫描时间

// 内部寄存器定义
reg [15:0] count; // 1ms定时计数器(16位宽度可支持最大65535个周期)
reg [2:0] cnt; // 当前显示位计数器(0-5对应6位数码管)
reg [3:0] show_data; // 当前要显示的数字(4位二进制,可表示0-15)

//------------------------------------------------------------------
// 1ms定时器生成逻辑
// 功能:产生精确的1ms时间间隔,用于数码管动态扫描
// 工作原理:在50MHz时钟下,每计数50,000次产生一个1ms标志
//------------------------------------------------------------------ 
always@(posedge clk or negedge rst_n)begin
    if(rst_n == 1'b0)
        count <= 16'b0; // 异步复位,计数器清零
    else if(count < DELAY_1MS - 1'b1)
        count <= count + 1'b1; // 计数器递增
    else
        count <= 16'b0; // 达到1ms时计数器归零
end

//------------------------------------------------------------------
// 数码管位选择计数器
// 功能:循环计数0-5,对应6位数码管
// 扫描频率:每1ms切换一位,6ms完成一个完整扫描周期(约167Hz刷新率)
//------------------------------------------------------------------
always@(posedge clk or negedge rst_n)begin
    if(rst_n == 1'b0)
        cnt <= 3'd0; // 复位时指向第1位数码管
    else if(count == DELAY_1MS - 1'b1)begin // 每1ms更新一次
        if(cnt < 3'd6)
            cnt <= cnt + 1'b1; // 循环计数0→1→2→3→4→5
        else
            cnt <= 3'd0; // 计数到5后归零
    end
    else
        cnt <= cnt; // 保持当前计数值
end

//------------------------------------------------------------------
// 数据选择器(多路复用器)
// 功能:根据当前位选择对应4位数据输出
// 注意:这是组合逻辑电路,无时钟延迟
//------------------------------------------------------------------
always@(*)begin
    case(cnt)
        3'd0: show_data = data_in[23:20]; // 选择第1位数据(最高4位)
        3'd1: show_data = data_in[19:16]; // 选择第2位数据
        3'd2: show_data = data_in[15:12]; // 选择第3位数据
        3'd3: show_data = data_in[11:8]; // 选择第4位数据
        3'd4: show_data = data_in[7:4]; // 选择第5位数据
        3'd5: show_data = data_in[3:0]; // 选择第6位数据(最低4位)
        default: show_data = 4'b0000; // 默认情况(理论上不会发生)
    endcase
end

//------------------------------------------------------------------
// 7段译码器(带小数点)
// 功能:将4位二进制数转换为7段数码管控制信号
// 编码规则(共阳极数码管,低电平有效):
// seg7[7] = dp (小数点)
// seg7[6:0] = g f e d c b a (从高位到低位)
// 注意:此实现未使用小数点(默认熄灭)
//------------------------------------------------------------------
always@(posedge clk or negedge rst_n)begin
    if(rst_n == 1'b0)
        seg7 <= 8'b1111_1111; // 复位时关闭所有段
    else
        case(show_data)
            4'd0: seg7 = 8'b1100_0000; // 显示"0"
            4'd1: seg7 = 8'b1111_1001; // 显示"1" 
            4'd2: seg7 = 8'b1010_0100; // 显示"2"
            4'd3: seg7 = 8'b1011_0000; // 显示"3"
            4'd4: seg7 = 8'b1001_1001; // 显示"4"
            4'd5: seg7 = 8'b1001_0010; // 显示"5"
            4'd6: seg7 = 8'b1000_0010; // 显示"6"
            4'd7: seg7 = 8'b1111_1000; // 显示"7"
            4'd8: seg7 = 8'b1000_0000; // 显示"8"
            4'd9: seg7 = 8'b1001_0000; // 显示"9"
            4'd10:seg7 = 8'b1000_1000; // 显示"A" 
            4'd11:seg7 = 8'b1000_0011; // 显示"b"
            4'd12:seg7 = 8'b1100_0110; // 显示"C"
            4'd13:seg7 = 8'b1010_0001; // 显示"d"
            4'd14:seg7 = 8'b1000_0110; // 显示"E"
            4'd15:seg7 = 8'b1000_1110; // 显示"F"
            default: seg7 <= 8'b1111_1111; // 默认关闭所有段
        endcase
end

//------------------------------------------------------------------
// 位选信号生成器
// 功能:根据当前位计数器生成对应的位选信号
// 特性:
// - 低电平有效(0表示选中对应位数码管)
// - 每次只选中一位,实现动态扫描
//------------------------------------------------------------------
always@(posedge clk or negedge rst_n)begin
    if(rst_n == 1'b0)
        sel6 <= 6'b11_1111; // 复位时关闭所有位数码管
    case(cnt)
        3'd0: sel6 <= 6'b11_1110; // 选中第1位数码管(sel6[0]=0)
        3'd1: sel6 <= 6'b11_1101; // 选中第2位数码管(sel6[1]=0)
        3'd2: sel6 <= 6'b11_1011; // 选中第3位数码管(sel6[2]=0)
        3'd3: sel6 <= 6'b11_0111; // 选中第4位数码管(sel6[3]=0)
        3'd4: sel6 <= 6'b10_1111; // 选中第5位数码管(sel6[4]=0)
        3'd5: sel6 <= 6'b01_1111; // 选中第6位数码管(sel6[5]=0)
        default: sel6 <= 6'b11_1111; // 默认关闭所有位数码管
    endcase
end

endmodule 

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

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

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

`timescale 1ns/1ns // 仿真时间单位1ns,精度1ns

module disp7led_dyna_tb();

// 测试信号定义
reg clk; // 模拟系统时钟信号(50MHz,周期20ns)
reg rst_n; // 模拟异步复位信号,低电平有效
reg [23:0] data_in; // 模拟24位显示数据输入,[23:20]为第1位,[3:0]为第6位

wire [5:0] sel6; // 监测位选信号输出(低电平有效,sel6[0]对应第1位)
wire [7:0] seg7; // 监测段选信号输出(低电平有效,seg7[7]为小数点)

// 实例化被测模块
disp7led_dyna uut( 
    .clk (clk), // 连接测试时钟
    .rst_n (rst_n), // 连接测试复位信号
    .data_in (data_in), // 连接测试数据输入
    .sel6 (sel6), // 连接位选信号输出
    .seg7 (seg7) // 连接段选信号输出
);

// 修改被测模块参数(缩短仿真时间)
// 将原1ms扫描间隔缩短为50个时钟周期(1us)
defparam uut.DELAY_1MS = 50;

// 时钟信号生成(50MHz)
initial clk = 1'b0; // 初始时钟置0
always #10 clk = ~clk; // 每10ns翻转一次(周期20ns)

// 测试激励生成
initial begin
    rst_n = 1'b0; // 复位信号有效(低电平)
    data_in = 24'h123456; // 测试数据:6位数码管显示1-2-3-4-5-6
    #203; // 等待203ns(超过10个时钟周期)
    rst_n = 1'b1; // 释放复位(开始正常工作)

    // 观察完整扫描周期
    // 等待2个完整扫描周期(6位数×50周期×2次)
    #(20*50*6*2);
    $stop; // 停止仿真(在Modelsim等工具中暂停)
end

endmodule 

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

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

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

// 7段数码管动态扫描驱动顶层模块
// 功能:实例化动态扫描驱动模块并提供测试数据
// 特性:
// 1. 连接系统时钟和复位信号
// 2. 提供固定的24位测试数据(0x123456)
// 3. 输出数码管位选和段选信号
module disp7led_dyna_top(
    input wire clk, // 系统时钟输入(50MHz)
    input wire rst_n, // 异步复位信号,低电平有效
    output wire [5:0] sel6, // 6位数码管位选信号输出,低电平有效,sel6[0]对应最左边的数码管
    output wire [7:0] seg7 // 7段数码管段选信号输出(包含小数点)
);

// 内部信号定义
wire [23:0] data_in; // 24位显示数据线

assign data_in = 24'h123456; // 将24'h123456固定赋值给data_in

// 动态扫描驱动模块实例化
// 将顶层模块的端口与驱动模块连接
disp7led_dyna uut( 
    .clk (clk), // 连接系统时钟
    .rst_n (rst_n), // 连接复位信号
    .data_in (data_in), // 连接显示数据
    .sel6 (sel6), // 连接位选信号输出
    .seg7 (seg7) // 连接段选信号输出
);

endmodule

提示

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

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号