1.原理
data_reg寄存,只寄存符号位和数据位不包含小数点位。
动态数码管每个显示1ms,所以计数到5*10^4-1
为了将sel和seg同步,把sel打了一拍。
6位都使用到了可以这么计算,6位都显示的是数据。或者最高位显示的是小数点,低5位是数据,
因为数码管是共阳数码管,低电平才能点亮。
2.代码
2.1 seg_dynamic.v
module seg_dynamic(
input wire sys_clk ,
input wire sys_rst_n ,
input wire[19:0] data ,
input wire[5:0] point ,
input wire sign ,
input wire seg_en ,
output reg[7:0] seg ,//因为一个数码管包括小数点位有8位
output reg[5:0] sel //因为总共有6个数码管需要显示
);
parameter CNT_MAX=16'd499_99;
wire [3:0] unit;
wire [3:0] ten;
wire [3:0] hun;
wire [3:0] tho;
wire [3:0] t_tho;
wire [3:0] h_hun; //999_999需要这6个位
reg [23:0] data_reg; //6个数码管,每个数码管是BCD码表示,一共有4位,因为上面的ten是4位
reg [15:0] cnt_1ms;//因为计数1ms
reg flag_1ms;
reg [2:0] cnt_sel; //因为要计数6个数码管表示一次扫描周期的结束
reg [5:0] sel_reg; //这个是位选信号,控制哪个数码管亮
reg [3:0] data_disp; //这是上面的data_reg的每个位数的拆分,控制它显示十六进制码
reg dot_disp;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
data_reg<=24'd0;
else if((h_hun)||(point[5]))
data_reg<={h_hun,t_tho,tho,hun,ten,unit};
else if(((t_tho)||(point[4]))&&(sign==1'b0)) //sign=0就是要使用符号位的意思
data_reg<={4'd11,t_tho,tho,hun,ten,unit};
else if(((t_tho)||(point[4]))&&(sign==1'b1))
data_reg<={4'd10,t_tho,tho,hun,ten,unit};
else if(((tho)||(point[3]))&&(sign==1'b0))
data_reg<={4'd11,4'd11,tho,hun,ten,unit};
else if(((tho)||(point[3]))&&(sign==1'b1))
data_reg<={4'd11,4'd10,tho,hun,ten,unit};
else if(((hun)||(point[2]))&&(sign==1'b0))
data_reg<={4'd11,4'd11,4'd11,hun,ten,unit};
else if(((hun)||(point[2]))&&(sign==1'b1))
data_reg<={4'd11,4'd11,4'd10,hun,ten,unit};
else if(((ten)||(point[1]))&&(sign==1'b0))
data_reg<={4'd11,4'd11,4'd11,4'd11,ten,unit};
else if(((ten)||(point[1]))&&(sign==1'b1))
data_reg<={4'd11,4'd11,4'd11,4'd10,ten,unit};
else if(((unit)||(point[0]))&&(sign==1'b0))
data_reg<={4'd11,4'd11,4'd11,4'd11,4'd11,unit};
else
data_reg<={4'd11,4'd11,4'd11,4'd11,4'd10,unit};
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
cnt_1ms<=16'd0;
else if(cnt_1ms==CNT_MAX)
cnt_1ms<=16'd0;
else
cnt_1ms<=cnt_1ms+1'b1;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
flag_1ms<=1'b0;
else if(cnt_1ms==CNT_MAX-1'b1)
flag_1ms<=1'b1;
else
flag_1ms<=1'b0;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
cnt_sel<=3'd0;
else if((flag_1ms==1'b1)&&(cnt_sel==3'd5))
cnt_sel<=3'd0;
else if(flag_1ms==1'b1)
cnt_sel<=cnt_sel+1'b1;
else
cnt_sel<=cnt_sel;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
sel_reg<=6'd0;
else if ((cnt_sel==3'd0)&&(flag_1ms==1'b1))
sel_reg<=6'b000_001;
else if(flag_1ms==1'b1)
sel_reg<=sel_reg<<1;
else
sel_reg<=sel_reg;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
data_disp<=4'd0;
else if((seg_en==1'b1)&&(flag_1ms==1'b1))
case(cnt_sel)
3'd0: data_disp<=data_reg[3:0];
3'd1: data_disp<=data_reg[7:4];
3'd2: data_disp<=data_reg[11:8];
3'd3: data_disp<=data_reg[15:12];
3'd4: data_disp<=data_reg[19:16];
3'd5: data_disp<=data_reg[23:20];
default: data_disp<=4'b0;
endcase
else
data_disp<=data_disp;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
dot_disp<=1'b1;
else if(flag_1ms==1'b1)
dot_disp<=~point[cnt_sel];
else
dot_disp<=dot_disp;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
seg<=8'd0;
else
case(data_disp)
4'd0: seg<={dot_disp,7'b100_0000};
4'd1: seg<={dot_disp,7'b111_1001};
4'd2: seg<={dot_disp,7'b010_0100};
4'd3: seg<={dot_disp,7'b011_0000};
4'd4: seg<={dot_disp,7'b011_1001};
4'd5: seg<={dot_disp,7'b001_0010};
4'd6: seg<={dot_disp,7'b000_0010};
4'd7: seg<={dot_disp,7'b111_1000};
4'd8: seg<={dot_disp,7'b000_0000};
4'd9: seg<={dot_disp,7'b001_0000};
4'd10: seg<=8'b1011_1111;//10就是符号,只显示中间的那条杠,因此是
4'd11: seg<=8'b1111_1111;//就是显示0
default:seg<=8'b1100_0000;
endcase
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
sel<=6'd0;
else
sel<=sel_reg;
bcd_8421 bcd_8421_inst(
.sys_clk (sys_clk ) ,
.sys_rst_n (sys_rst_n) ,
.data (data ) ,
.unit (unit ) ,
.ten (ten ) ,
.hun (hun ) ,
.tho (tho ) ,
.t_tho (t_tho ) ,
.h_hun (h_hun )
);
endmodule
2.2 tb_seg_dynamic.v
module tb_seg_dynamic();
reg sys_clk ;
reg sys_rst_n ;
reg[19:0] data ;
reg[5:0] point ;
reg sign ;
reg seg_en ;
wire[7:0] seg;
wire[5:0] sel;
initial
begin
sys_clk=1'b1;
sys_rst_n<=1'b0;
data<=20'd0;
point<=6'b000_000;
sign<=1'b0;
seg_en<=1'b0;
#30
sys_rst_n<=1'b1;
data<=20'd98_76;
point<=6'b000_010;
sign<=1'b1;
seg_en<=1'b1;
end
always #10 sys_clk=~sys_clk;
defparam seg_dynamic_inst.CNT_MAX=20'd5;
seg_dynamic seg_dynamic_inst(
.sys_clk (sys_clk ) ,
.sys_rst_n (sys_rst_n),
.data (data ),
.point (point ),
.sign (sign ),
.seg_en (seg_en ),
.seg (seg ) ,
.sel (sel )
);
endmodule