动态数码管显示分为多个模块如下图
以下先介绍数据产生模块。
目标:六位数码管,循环动态显示从000_000—999_999,时间间隔为0.1s。
思路:
①0.1s计数器cnt_100ms,50MHz晶振,则计数器从0开始计数到4999_999为0.1s,每满每0.1s则重新开始计数。
②标志信号cnt_flag,每次计数器计数到最大值减1时,产生一个时钟周期的高电平。
③数码管显示数据的产生data,即每次计数满0.1s时自增加1,同样可由标志信号控制,当计满999_999时且标志信号为高电平时清零。
④point为小数点位、sign区分正负号、seg_en为使能信号。
Visio波形图如下:
Verilog仿真代码如下
module data_gen
#(
parameter CNT_MAX=23'd4999_999,
parameter DATA_MAX=20'd999_999
)
(
input wire sys_clk,
input wire sys_rst_n,
output reg [19:0]data,
output wire [5:0]point,
output wire sign,
output reg seg_en
);
reg [22:0]cnt_100ms;
reg cnt_flag;
always@(posedge sys_clk or negedge sys_rst_n)//0.1s计数器
if(sys_rst_n==1'b0)
cnt_100ms<=23'd0;
else if(cnt_100ms==CNT_MAX)
cnt_100ms<=23'd0;
else
cnt_100ms<=cnt_100ms+23'd1;
always@(posedge sys_clk or negedge sys_rst_n)//标志信号
if(sys_rst_n==1'b0)
cnt_flag<=1'b0;
else if(cnt_100ms==CNT_MAX-1'b1)
cnt_flag<=1'b1;
else
cnt_flag<=1'b0;
always@(posedge sys_clk or negedge sys_rst_n)//显示数据的产生
if(sys_rst_n==1'b0)
data<=20'd0;
else if((cnt_flag==1'b1)&&(data==DATA_MAX))
data<=20'd0;
else if(cnt_flag==1'b1)
data<=data+20'd1;
else
data<=data;
assign point=6'b000_000;
assign sign=1'b0;
always@(posedge sys_clk or negedge sys_rst_n)//使能信号
if(sys_rst_n==1'b0)
seg_en<=1'b0;
else
seg_en<=1'b1;
endmodule
仿真测试代码如下:
`timescale 1ns / 1ns
module tb_data_gen();
reg sys_clk; //需要用initial进行赋值,所以用reg型
reg sys_rst_n;
wire [19:0]data; //仿真测试代码中的输出信号必须为wire型
wire [5:0]point;
wire sign;
wire seg_en;
initial
begin
sys_clk=1'b1;
sys_rst_n<=1'b0;
#30
sys_rst_n<=1'b1;
end
always #10 sys_clk=~sys_clk;
data_gen
#(
.CNT_MAX(23'd49),
.DATA_MAX(20'd9)
)
data_gen_inst
(
.sys_clk(sys_clk),
.sys_rst_n(sys_rst_n),
.data(data),
.sign(sign),
.seg_en(seg_en),
.point(point)
);
endmodule
vivado仿真波形图
各个信号的初值情况
当计数到CNT_MAX的时候,data自加1,且当计数到CNT_MAX-1时,产生一个时钟周期的脉冲。
为了便于仿真CNT_MAX最大值在仿真测试代码中设置为49,DATA_MAX代码设置为9,每次记满时清零,重新开始计数。