文章目录
概要
在嵌入式系统与数字逻辑设计中,多位数码管的动态扫描显示是一种常见且高效的技术。它通过快速切换数码管的位选信号,利用人眼视觉暂留效应,实现多个数码管同时点亮的视觉效果。本文将详细介绍基于Verilog的数码管动态扫描驱动设计,包括原理分析、电路建模、代码实现及仿真验证,适合FPGA初学者和有一定基础的开发者阅读。
一、数码管动态扫描原理
-
动态扫描基本原理
多位数码管动态扫描的核心是分时复用。通过控制位选信号(SEL)循环选中每个数码管,并在选中的同时输出对应的段选信号(SEG),从而实现不同数码管显示不同内容。
位选控制:例如3位数码管,位选信号可为:
cl = 3'b001 → 选中数码管0
cl = 3'b010 → 选中数码管1
cl = 3'b100 → 选中数码管2
视觉暂留效应:人眼对图像的保留时间约为20ms,只要每个数码管两次点亮间隔小于20ms,就不会出现闪烁现象。
2. 电路结构
典型的动态扫描电路包括:
bash
分频计数器:实现1ms定时,控制位切换节奏
位选择计数器:循环生成0~7的数码管编号
三八译码器:将3位计数器转换为8位位选信号
查找表(LUT):实现字符到段码的映射
八选一多路选择器:根据当前位选信号选择对应显示数据
二、Verilog实现细节
- 模块定义与端口
c
module hex8(
input clk,
input reset_n,
input [31:0] disp_data,
output reg [7:0] SEL,
output reg [7:0] SEG
);
- 1ms分频计数器
c
parameter CLK_FREQ = 50_000_000; // 50MHz
parameter TURN_FREQ = 1000; // 1kHz → 1ms
parameter MCNT = CLK_FREQ / TURN_FREQ - 1;
reg [29:0] div_cnt;
//1ms的分频计数器
always@(posedge clk or negedge reset_n)
if(!reset_n)
div_cnt<=0;
else if(div_cnt == mcnt)
div_cnt<=0;
else
div_cnt<=div_cnt+1'd1;
- 位选择计数器
c
//位选择计数器
reg [2:0]cnt_sel;// 3位计数器,范围0-7
always@(posedge clk or negedge reset_n)
if(!reset_n)
cnt_sel <= 0;
else if(div_cnt == mcnt)
cnt_sel <= cnt_sel+1'd1;
- 三八译码器(位选生成)
c
//三八译码器
always@(posedge clk)
case(cnt_sel)
0:sel <= 8'b0000_0001;
1:sel <= 8'b0000_0010;
2:sel <= 8'b0000_0100;
3:sel <= 8'b0000_1000;
4:sel <= 8'b0001_0000;
5:sel <= 8'b0010_0000;
6:sel <= 8'b0100_0000;
7:sel <= 8'b1000_0000;
endcase
- 八选一多路选择器
c
//组合电路:八路选择器
always@(*)
case(cnt_sel)
0: data_temp <= disp_data[3:0];//0
1: data_temp <= disp_data[7:4];//1
2: data_temp <= disp_data[11:8];//2
3: data_temp <= disp_data[15:12];//3
4: data_temp <= disp_data[19:16];//4
5: data_temp <= disp_data[23:20];//5
6: data_temp <= disp_data[27:24];//6
7: data_temp <= disp_data[31:28];//7
endcase
- 查找表LUT(段码映射)
c
//查找表LUT
reg [3:0]data_temp;
always@(posedge clk)
case(data_temp)
0: seg <= 8'b1100_0000;//0
1: seg <= 8'b1111_1001;//1
2: seg <= 8'b1010_0100;//2
3: seg <= 8'b1011_0000;//3
4: seg <= 8'b1001_1001;//4
5: seg <= 8'b1001_0010;//5
6: seg <= 8'b1000_0010;//6
7: seg <= 8'b1111_1000;//7
8: seg <= 8'b1000_0000;//8
9: seg <= 8'b1001_0000;//9
10: seg <= 8'b1000_1000;//A
11: seg<= 8'b1000_0011;//b
12: seg <= 8'b1100_0110;//C
13: seg <= 8'b1010_0001;//d
14: seg <= 8'b1000_0110;//E
15: seg <= 8'b1000_1110;//F
endcase
三、仿真验证
测试激励
c
`timescale 1ns/1ps
module hex8_tb();
reg clk;
reg reset_n;
reg [31:0]disp_data;
wire [7:0]sel;
wire [7:0]seg;
hex8 hex8(
.clk(clk),
.reset_n(reset_n),
.disp_data(disp_data),
.sel(sel),
.seg(seg)
);
initial clk = 1;
always#10 clk = ~clk;
initial begin
reset_n = 0;
disp_data = 32'h12345678;
#201;
reset_n = 1;
#20000000; //延时20ms
disp_data = 32'h9abcdef0;
#20000000; //延时20ms
$stop;
end
endmodule
四、波形分析

