4. 数码管动态扫描
任务目标
在FPGA开发板上驱动4位共阴极数码管,通过动态扫描方式稳定显示一组数字(例如"1234")。核心是掌握扫描时序设计:任一时刻仅点亮一位数码管,以较高频率循环轮询各位,利用视觉暂留效应形成多位同时显示的观感。
硬件连接与依赖
- 4位数码管为共阴极,段选信号(a~g, dp)接FPGA引脚,位选信号(sel0~sel3)分别控制4个位的公共阴极。
- 本案例以DE0/DE1开发板为参考,若实际板卡不同,需根据原理图调整引脚分配。
- 时钟输入:50MHz系统时钟。
核心原理
动态扫描的关键参数是刷新频率。每位数码管在一个扫描周期内被点亮1/4时间,若扫描频率低于50Hz,人眼会感到明显闪烁。本设计将扫描周期设为1ms(每位点亮250μs),整体刷新率为1kHz,远高于闪烁阈值。段选数据由位选信号控制的多路选择器输出,确保当前被点亮的位显示其对应的数字。
完整代码
module seg_dynamic_scan (
input clk, // 50MHz
input rst_n, // 异步复位,低有效
output reg [6:0] seg, // {a,b,c,d,e,f,g} 共阴极段码
output reg [3:0] sel // 位选,高电平选中
);
// 待显示数字(BCD码):千位=1,百位=2,十位=3,个位=4
reg [3:0] num [0:3];
initial begin
num[0] = 4'd1; // 千位
num[1] = 4'd2; // 百位
num[2] = 4'd3; // 十位
num[3] = 4'd4; // 个位
end
// 共阴极段码表(0~9)
function [6:0] seg_code;
input [3:0] bcd;
begin
case (bcd)
4'd0: seg_code = 7'b1000000; // 0
4'd1: seg_code = 7'b1111001; // 1
4'd2: seg_code = 7'b0100100; // 2
4'd3: seg_code = 7'b0110000; // 3
4'd4: seg_code = 7'b0011001; // 4
4'd5: seg_code = 7'b0010010; // 5
4'd6: seg_code = 7'b0000010; // 6
4'd7: seg_code = 7'b1111000; // 7
4'd8: seg_code = 7'b0000000; // 8
4'd9: seg_code = 7'b0010000; // 9
default: seg_code = 7'b1111111; // 全灭
endcase
end
endfunction
// 扫描计数器:1ms周期(50MHz / 1000 = 50000)
reg [15:0] cnt;
reg [1:0] scan_pos;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
cnt <= 16'd0;
scan_pos <= 2'd0;
end else if (cnt == 16'd49999) begin
cnt <= 16'd0;
scan_pos <= scan_pos + 2'd1; // 轮换位选
end else begin
cnt <= cnt + 16'd1;
end
end
// 位选与段码输出
always @(*) begin
case (scan_pos)
2'd0: begin sel = 4'b0001; seg = seg_code(num[0]); end // 千位
2'd1: begin sel = 4'b0010; seg = seg_code(num[1]); end // 百位
2'd2: begin sel = 4'b0100; seg = seg_code(num[2]); end // 十位
2'd3: begin sel = 4'b1000; seg = seg_code(num[3]); end // 个位
default: begin sel = 4'b0000; seg = 7'b1111111; end
endcase
end
endmodule
引脚约束(Quartus .qsf示例)
set_location_assignment PIN_N2 -to clk
set_location_assignment PIN_B8 -to rst_n
set_location_assignment PIN_C15 -to seg[0]
set_location_assignment PIN_E15 -to seg[1]
set_location_assignment PIN_F15 -to seg[2]
set_location_assignment PIN_G15 -to seg[3]
set_location_assignment PIN_H15 -to seg[4]
set_location_assignment PIN_J15 -to seg[5]
set_location_assignment PIN_K15 -to seg[6]
set_location_assignment PIN_L14 -to sel[0]
set_location_assignment PIN_M14 -to sel[1]
set_location_assignment PIN_N14 -to sel[2]
set_location_assignment PIN_P14 -to sel[3]
以上引脚编号仅为示例,实际需根据开发板原理图修改。
运行与验证
- 在Quartus中新建工程,将上述Verilog代码设为顶层实体,添加引脚约束后编译综合。
- 下载bitstream至FPGA开发板。
- 通过标准:4位数码管稳定显示"1234",无闪烁、无重影。若出现闪烁,说明扫描频率过低,可减小cnt计数上限(例如改为24999,即0.5ms周期);若出现重影,则需检查位选信号与段码输出的时序对齐,确保切换位选时段码已稳定。
常见问题
- 显示亮度不均:不同位数的LED点亮时间相同,但人眼对某些数字的亮度感知略有差异,属正常现象。若差异明显,可检查各段限流电阻是否一致。
- 高位消隐:若需显示"0001"而非"1",只需将num数组对应位设为0即可,本代码已支持前导零显示。