二、19【FPGA】数码管动态显示实验

前言

学习说明此文档为本人的学习笔记,注重实践,关于理论部分会给出相应的学习链接。

学习视频:是根据野火FPGA视频教程——第二十二讲
https://www.bilibili.com/video/BV1nQ4y1Z7zN?p=3

理论学习

1、数码管动态显示

“天下武功唯快不破”  “看到的不一定为真”

眼睛的视觉暂留:光信号传入大脑需要短暂时间,只要变化的频率大于传输的的频率,那么你看到的事物将是一直存在的,并不会出现闪动,这就是视觉的暂留现象。

数码管的余晖效应:当停止向发光二极管亮度仍然维持一段时间。

动态扫描,当数码管的闪烁时间间隔为1ms时,眼睛将不会察觉有闪烁感。以6ms为一个周期,每个数码管显示1ms,循环显示方法。

2、二进制转BCD码

BCD 码(Binary-Coded Decimal),又称二 - 十进制码,使用 4 位二进制数来表示 1 位十进制数中的 0~9 10 个数码,是一种二进制的数字编码形式,用二进制编码的十进制代码。

分为:有权码和无权码

 将其每位二进制数乘以它的权值然后相加。十进制 5 8421BCD 码为 0101,即:1×1 + 0×2 + 1×4+ 0×8 = 5,每4位代表一个十进制数

 十进制:234            二进制:1110_1010           BCD:0010_0011_0100

如何通过二进制求出每一位的十进制数:

  • stp1:在相应二进制前面补(十进制位数*4),如10则补8位0,234则补12位
  • stp2:判断每四位二进制数(一位十进制数)是否大于4,当>4时每四位二进制数加3(+0011)
  • stp3:向左移1位
  • stp4:循环stp2和stp3
  • stp5:直到将输入二进制数全都移位完成。需要移的位数就是二进制码的位数,得到BCD码每四位的十进制数就是需要显示的数。

实战演练

一、设计规划

1.1 实验要求

让6位数码管显示从十进制数0开始计数,每次0.1s加1,一直加到十进制数999999。到达999999之后回到0开始重新计数。

1.2 硬件资源

和静态显示的硬件资源相同

二、模块框图绘制

2.1 功能模块框图

2.2 Data_gen 数据生成模块

  • 波形图

  • 程序代码 
module data_gen
#(
    parameter CNT_MAX = 23'd4999999,
    parameter DATA_MAX = 20'd999999             
)
(
    input wire sys_clk,
    input wire sys_rst_n,
    output reg [19:0] data,
    output wire [5:0] point,
    output reg seg_en,
    output wire sign
    );
    reg [22:0] cnt_100ms;
    reg  cnt_flag;
    always@(posedge sys_clk or negedge sys_rst_n)
        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 + 1'b1;
    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(data == DATA_MAX && cnt_100ms == CNT_MAX)
            data <= 20'd0;
        else if(cnt_flag == 1'b1)
            data <= data + 1'b1;
        else 
            data <= data;   
    assign point = 6'b000000;
    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;
    reg sys_rst_n;
    
    initial begin
        sys_clk = 1'b1;
        sys_rst_n <= 1'b0;
        #20
        sys_rst_n <= 1'b1;
    end 
    always #10 sys_clk = ~sys_clk;


    data_gen
    #(
        .CNT_MAX (9),
        .DATA_MAX(5)             
    )
    data_gen_inst
    (
        .sys_clk  (sys_clk  ),
        .sys_rst_n(sys_rst_n)    
    );
endmodule
  • 仿真波形

通过与绘制的波形对比,可知绘制波形图是正确的

2.3 bcd_8421二进制转十进制模块

  • 波形图

cnt_shift对是否完成移位进行判断

移位判断计数器,前面我们说到我们输入转换的二进制码有多少位我们就需要进行多少次判断移位操作,这里我们 data 数据的位宽为 20 位,所以这里我们声明移位判断计数器对移位 20 次进行判断控制。

data_shift左移补0,右移补1。需要寄存器来储存移位前后的变量

移位判断数据寄存器,该寄存器用于存储移位判断操作过程中的数据,这里我们输入的二进制位宽为 20 位,待转换成的 BCD 码位宽为 24 位,所以这里我们声明该寄存器的位宽为输入的二进制位宽和待转换完成的 BCD 码位宽之和,即 44 位。根据波形图可知,这里我们设计当移位计数器等于 0 时寄存器的低 20 位即为待转换数据,而由于还没开始进行转换,高 24 位的 BCD 码我们补 0 即可。

shift_flag有判断和移位两种状态,上升沿的前一时刻都是0,只有一个状态,因此需要将一个时钟周期变化一次值,这时上升沿前一时刻可以是0也可以是1,有两个状态。

移位判断操作标志信号。前面说到我们需要对数据进行移位和判断,判断在前移位在后,所以这里我们声明一个标志信号,用于控制判断和移位的先后顺序,当shift_flag 为低时对数据进行判断,当 shift_flag 为高时对数据进行移位。需要注意的是无论是移位操作和判断操作都是在单个系统时钟下完成的,故我们判断 20 次移位 20 次在 40 个系统时钟内就能完成。

  • 程序代码 
module bcd_8421
#(
    parameter DATA_MAX = 5'd21          //由于存在一步补0操作,所以最大执行次数=移位次数+1
)
(
    input wire        sys_clk,
    input wire        sys_rst_n,
    input wire [19:0] data,
    
    output reg [3:0] unit,
    output reg [3:0] ten,
    output reg [3:0] hun,
    output reg [3:0] tho,
    output reg [3:0] t_tho,
    output reg [3:0] h_hum    
    );
    reg [4:0] cnt_shift ;
    reg [43:0] data_shift;
    reg        shift_flag;
    always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            shift_flag <= 1'b0;
        else 
            shift_flag <= ~shift_flag;        
    always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            cnt_shift <= 5'd0;
        else if((cnt_shift == DATA_MAX) && (shift_flag == 1'b1))
            cnt_shift <= 5'd0;
        else if(shift_flag == 1'b1)
            cnt_shift <= cnt_shift + 1'b1;
        else 
            cnt_shift <= cnt_shift;
    always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)    
            data_shift <= 44'b0;     //6*4=24(6位十进制)+20(20位二进制)=44   
        else if(cnt_shift == 5'd0)
            data_shift <= {24'b0,data};
        else if((cnt_shift <= 5'd20)&&(shift_flag == 1'b0))
        begin
            data_shift[23:20] <= (data_shift[23:20] > 4)?(data_shift[23:20]+2'd3) : data_shift[23:20];
            data_shift[27:24] <= (data_shift[27:24] > 4)?(data_shift[27:24]+2'd3) : data_shift[27:24];
            data_shift[31:28] <= (data_shift[31:28] > 4)?(data_shift[31:28]+2'd3) : data_shift[31:28];
            data_shift[35:32] <= (data_shift[35:32] > 4)?(data_shift[35:32]+2'd3) : data_shift[35:32];
            data_shift[39:36] <= (data_shift[39:36] > 4)?(data_shift[39:36]+2'd3) : data_shift[39:36];
            data_shift[43:40] <= (data_shift[43:40] > 4)?(data_shift[43:40]+2'd3) : data_shift[43:40];
        end
        else if((cnt_shift <= 5'd20)&&(shift_flag == 1'b1))
            data_shift <= data_shift << 1'b1;
        else
            data_shift <= data_shift;
    always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)   
            begin
            unit   <= 4'd0;
            ten    <= 4'd0;
            hun    <= 4'd0;
            tho    <= 4'd0;
            t_tho  <= 4'd0;
            h_hum  <= 4'd0;                                  
            end
        else    if(cnt_shift == 5'd21)
            begin
            unit   <= data_shift[23:20];
            ten    <= data_shift[27:24];
            hun    <= data_shift[31:28];
            tho    <= data_shift[35:32];
            t_tho  <= data_shift[39:36];
            h_hum  <= data_shift[43:40];                                  
            end 
endmodule
  • 仿真代码
`timescale 1ns / 1ns
//
// Company: 追逐者——桥的小作坊
// Create Date: 2022/05/24 10:45:57
// Design Name: 二进制码转bcd码
// Module Name: tb_bcd_8421
//
module tb_bcd_8421();
    reg        sys_clk;
    reg        sys_rst_n;
    reg [19:0] data;
    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_hum;
    initial begin
        sys_clk = 1'b1;
        sys_rst_n <= 1'b0;
        #20
        sys_rst_n <= 1'b1;
        data <= 20'd123_456;
        #3000 data <= 20'd654_321;
        #3000 data <= 20'd987_654;
        #3000 data <= 20'd999_999;
    end
    always #10 sys_clk = ~sys_clk;
            
bcd_8421
#(
    .DATA_MAX(5'd21)          //由于存在一步补0操作,所以最大执行次数=移位次数+1
)
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_hum     (h_hum)
    );
endmodule
  • 仿真波形图

如下图,仿真波形图由于数据的二进制位数为20,且需要每次赋初值,需要先进行判断后移位,因此移位计数器在数字1-20进行移位即移动了20位。

2.4 seg_dynamic 数码管驱动模块

驱动方式:动态扫描,当数码管的闪烁时间间隔为1ms时,眼睛将不会察觉有闪烁感。以6ms为一个周期,每个数码管显示1ms,循环显示方法。

  • 波形图

 point输入小数点控制信号,高电平有效,这里我们假设要让第二个数码管显示小数点,其余数码管不显示小数点,那么此时 point 的输入的值就应该是 6’b000010

seg_en:数码管使能信号,这里一直让其拉高即可。

data:输入的十进制数据,假设这里我们输入的十进制数为 9876

sign:符号位控制信号,高电平有效。假设我们需要显示的是负数,那么这里就让符号位控制信号为高即可。

unit、tenhunthot_thoh_hun这六个信号就是我们例化的 bcd_8421 模块转化的 8421BCD 码,也就是说这六个 BCD 码就是输入十进制数 9876 各个位的 BCD 码。所以 这里个位(unit)是 6,十位(ten)是 7,百位(hun)是 8,千位(tho)是 9,万位和十 万位都为 0。 data_reg:数码管待显示内容寄存器,因为这里我们假设输入要显示的十进制数为9876,并且显示负号,所以前五个数码管就会显示-9876 的数值,此时最高位数码管什么都 不显示,我们用 X 表示,所以这里六个数码管显示的内容就是:X-9876。

cnt_1ms前面讲到要让显示的数码管不会有闪烁感,我们需要使用 1ms 的扫描时间去 扫描各个数码管。所以这里我们需要一个 1ms 的计数器对 1ms 进行循环计数。

flag_1ms1ms 计数标志信号,当 1ms 计数器计到 1ms 时拉高该标志信号,我们使用该标志信号去控制位选数码管计数器的计数。

cnt_sel位选数码管计数器。我们在理论学习中说到动态扫描方式是用 1ms 的刷新时间让六个数码管轮流显示:第 1ms 点亮第一个数码管,第 2ms 点亮第二个数码管,以此类推依次点亮六个数码管,6ms 一个轮回,也就是说每个数码管每 6ms 点亮一次。那问题是我们怎么去选中这个要显示的数码管并且给其要显示的值呢?这个时候我们就引入了一个cnt_sel 信号,让其从 0~5 循环计数,1 个数代表一个数码管,可以看做是给数码管编号。这样的话我们只要选择计数器的值就相当于选中了其中对应的数码管。特别要说明的是我们的 cnt_sel 计数器必须与数码管的刷新状态一致,也就是 1ms 1 个数。

sel_reg:数码管位选信号寄存器,为了让数码管位选信号和段选信号同步,这里我们先将位选信号进行寄存。刷新到哪个数码管就将 sel 中对应位(6 个位宽,每一位对应一个数码管)给高点亮即可。选中点亮的数码管后我们需要给其要显示的值,所以我们引入一个新的信号。

data_disp:当前点亮数码管显示的值。若我们此时点亮的是第一个数码管,那么我们就需要给第一个数码管显示值 6,若刷新到第二个数码管,那么我们就需要给第二个数码管显示值 7,以此类推;当刷新到第五个数码管时,此时显示的是负号,那么我们该如何表示呢?这里我们让该信号的值为 10 来表示,也就是说当 data_disp 的值为 10 时就让数码管显示负号,同理这里我们定义 data_disp 的值为 11 时让数码管什么也不显示,即不点亮数码管。

dot_disp当前数码管显示的小数点,我们输入的 point 信号是点亮第二个数码管的小数点,而我们的数码管是低电平点亮,所以这里当扫描到第二个数码管时让 dot_disp 信号为低即可。

seg:数码管段选信号,我们根据数码管编码译码表当扫描到哪个数码管显示需要显示的值时,我们将对于的段点亮即可。

sel:数码管位选信号。将数码管位选信号寄存器打一拍即可,这样就能实现数码管段选信号和位选信号的同步。

  • 程序代码
module seg_dynamic(
    input wire          sys_clk   ,
    input wire          sys_rst_n ,
    input wire          sign      ,   //符号位
    input wire          seg_en    ,   //数码管使能
    input wire   [5:0]  point     ,   //小数点
    input wire   [19:0] data      ,   //数据二进制码
    output reg  [7:0]   seg       ,   //段选
    output reg  [5:0]   sel           //位选(同步统一后)
    );    
    parameter CNT_MAX =16'd49_999,
              CNT_SEL_MAX = 3'd5;
    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_hum;
    reg [23:0] data_reg;      //data的数据转存
    reg [15:0] cnt_1ms;       //时间计数器
    reg        flag_1ms;      //时间标志
    reg [2:0]  cnt_sel;       //数码管遍历计数
    reg [5:0]  sel_reg;       //位选信号
    reg [3:0]  data_disp;     //每位待显示数字
    reg        dot_disp;      //每位待显示小数点
//实例化内部模块    
bcd_8421
#(
    .DATA_MAX(5'd21)   //由于存在一步补0操作,所以最大执行次数=移位次数+1
)
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_hum    (h_hum)
    ); 
//data数据转存为显示寄存
    always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            data_reg <= 24'b0;
        //如果高位不为0或有小数点时对其显示
        else if((h_hum)||(point[5]))
            data_reg <= {h_hum, t_tho, tho, hun, ten, unit};
        //如果高位不为0或有小数点、有负号时对其显示
        else if(((t_tho)||(point[4]))&&(sign == 1'b1))//显示负号
                data_reg <= {4'd10, t_tho, tho, hun, ten, unit};
            else if(((t_tho) || (point[4])) && (sign == 1'b0))
                data_reg <= {4'd11,t_tho,tho,hun,ten,unit};//4'd11 我们定义为不显示                  
        else if(((tho)||(point[3]))&&(sign == 1'b1))
                data_reg <= {4'd11, 4'd10, tho, hun, ten, unit};  
            else if(((tho) || (point[3])) && (sign == 1'b0)) 
                data_reg <= {4'd11,4'd11,tho,hun,ten,unit};            
        else if(((hun)||(point[2]))&&(sign == 1'b1))
                data_reg <= {4'd11, 4'd11, 4'd10, hun, ten, unit};  
            else if(((hun) || (point[2])) && (sign == 1'b0))
                data_reg <= {4'd11,4'd11,4'd11,hun,ten,unit};           
        else if(((ten)||(point[1]))&&(sign == 1'b1))
                data_reg <= {4'd11, 4'd11, 4'd11, 4'd10, ten, unit};  
            else if(((ten) || (point[1])) && (sign == 1'b0))
                data_reg <= {4'd11,4'd11,4'd11,4'd11,ten,unit};
        else if(((unit)||(point[0]))&&(sign == 1'b1))
            data_reg <= {4'd11, 4'd11, 4'd11, 4'd11, 4'd10, unit};             
        else
            data_reg <= {4'd11, 4'd11, 4'd11, 4'd11, 4'd11, unit};
//时间计数器1ms            
    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 == CNT_SEL_MAX))
            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'b000_000;
        else if((flag_1ms == 1'b1) && (cnt_sel == 3'd0))
            sel_reg <= 6'b000_001;          //这里是位的变化所以用移位就可以了
        else if(flag_1ms == 1'b1)
            sel_reg <= sel_reg << 1'b1;
        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'b1111_1111;
        else case(data_disp)
                4'd0: seg <= {dot_disp,7'b100_0000};   //显示数字0:
                4'd1: seg <= {dot_disp,7'b111_1001};   //显示数字1:
                4'd2: seg <= {dot_disp,7'b010_0100};   //显示数字2:
                4'd3: seg <= {dot_disp,7'b011_0000};   //显示数字3:
                4'd4: seg <= {dot_disp,7'b001_1001};   //显示数字4:
                4'd5: seg <= {dot_disp,7'b001_0010};   //显示数字5:
                4'd6: seg <= {dot_disp,7'b000_0010};   //显示数字6:
                4'd7: seg <= {dot_disp,7'b111_1000};   //显示数字7:
                4'd8: seg <= {dot_disp,7'b000_0000};   //显示数字8:
                4'd9: seg <= {dot_disp,7'b001_0000};   //显示数字9:
                4'd10: seg <= 8'b1011_1111;   //显示负号
                4'd11: seg <= 8'b1111_1111;   //不显示      
                default: seg <= 8'b1100_0000;
            endcase
    always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0) 
            sel <= 6'b000_000;
        else 
            sel <= sel_reg;    
endmodule
  • 仿真代码
`timescale 1ns / 1ns
//
// Company:  追逐者——桥的小作坊
// Create Date: 2022/05/25 10:14:19
// Design Name: 数码管驱动模块
// Module Name: tb_seg_dynamic
module tb_seg_dynamic();
    reg          sys_clk   ;
    reg          sys_rst_n ;
    reg          sign      ;  //符号位
    reg          seg_en    ;  //数码管使能
    reg   [5:0]  point     ;  //小数点
    reg   [19:0] data      ;  //数据二进制码
    wire  [7:0]   seg      ;   //段选
    wire  [5:0]   sel      ;   //位选(同步统一后)
    initial begin
        sys_clk = 1'b1;
        sys_rst_n <= 1'b0;
        sign <= 1'b0;
        seg_en <= 1'b0;
        point <= 6'b0;
        data <= 20'd0;
        #30
        sys_rst_n <= 1'b1;
        sign <= 1'b1;
        seg_en <= 1'b1;
        point <= 6'b000_010;
        data <= 20'd9876;
    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),
    .sign     (sign     ),   //符号位
    .seg_en   (seg_en   ),   //数码管使能
    .point    (point    ),   //小数点
    .data     (data     ),   //数据二进制码
    .seg      (seg      ),   //段选
    .sel      (sel      )    //位选(同步统一后)
    );
endmodule
  • 仿真波形 

 根据上图与绘制波形图并没有什么问题。

2.5 top_seg_dynamic 数码管显示顶层模块

  • 程序代码
module top_seg_dynamic(
    input wire sys_clk,
    input wire sys_rst_n,
    output wire [5:0] sel,
    output wire [7:0] seg
    );
    
    wire [19:0] data   ;
    wire [5:0]  point  ;
    wire seg_en ;
    wire sign   ;
        
data_gen
    #(
        .CNT_MAX (23'd4999999),
        .DATA_MAX( 20'd999999)             
    )
    data_gen_inst
    (
        .sys_clk  (sys_clk  ),
        .sys_rst_n(sys_rst_n),
        .data     (data     ),
        .point    (point    ),
        .seg_en   (seg_en   ),
        . sign    ( sign    )        
    ); 
seg_dynamic seg_dynamic_inst(
    .sys_clk  (sys_clk  ),
    .sys_rst_n(sys_rst_n),
    .sign     (sign     ),   //符号位
    .seg_en   (seg_en   ),   //数码管使能
    .point    (point    ),   //小数点
    .data     (data     ),   //数据二进制码
    .seg      (seg      ),   //段选
    .sel      (sel  )        //位选(同步统一后)
    );     
    
endmodule
  • 仿真代码
`timescale 1ns / 1ns
//
// Company:  追逐者——桥的小作坊
// Create Date: 2022/05/25 10:56:06
// Design Name: 数码管动态显示顶层模块
// Module Name: tb_top_seg_dynamic
module tb_top_seg_dynamic();
    reg sys_clk;
    reg sys_rst_n;
    wire [5:0] sel;
    wire [7:0] seg;
    initial begin
        sys_clk = 1'b1;
        sys_rst_n <= 1'b0;
        #20
        sys_rst_n <= 1'b1;
    end 
    always #10 sys_clk = ~sys_clk;
    
defparam top_seg_dynamic_inst.data_gen_inst.CNT_MAX = 19;
defparam top_seg_dynamic_inst.seg_dynamic_inst.CNT_MAX = 199;
top_seg_dynamic top_seg_dynamic_inst(
    .sys_clk  (sys_clk  ),
    .sys_rst_n(sys_rst_n),
    .sel      (sel      ),
    .seg      (seg      )
    );
endmodule

四、上板验证

4.1 管脚绑定

set_property PACKAGE_PIN W19 [get_ports sys_clk]
set_property PACKAGE_PIN Y19 [get_ports sys_rst_n]
set_property PACKAGE_PIN H18 [get_ports {sel[0]}]
set_property PACKAGE_PIN H20 [get_ports {sel[1]}]
set_property PACKAGE_PIN G20 [get_ports {sel[2]}]
set_property PACKAGE_PIN L16 [get_ports {sel[3]}]
set_property PACKAGE_PIN K16 [get_ports {sel[4]}]
set_property PACKAGE_PIN K18 [get_ports {sel[5]}]
set_property PACKAGE_PIN U22 [get_ports {seg[0]}]
set_property PACKAGE_PIN P19 [get_ports {seg[1]}]
set_property PACKAGE_PIN W21 [get_ports {seg[2]}]
set_property PACKAGE_PIN V22 [get_ports {seg[3]}]
set_property PACKAGE_PIN AB20 [get_ports {seg[4]}]
set_property PACKAGE_PIN W22  [get_ports {seg[5]}]
set_property PACKAGE_PIN AA20 [get_ports {seg[6]}]
set_property PACKAGE_PIN AA21 [get_ports {seg[7]}]

set_property IOSTANDARD LVCMOS33 [get_ports sys_clk]
set_property IOSTANDARD LVCMOS33 [get_ports sys_rst_n]
set_property IOSTANDARD LVCMOS33 [get_ports {seg[4]}]
set_property IOSTANDARD LVCMOS33 [get_ports {sel[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {seg[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {seg[7]}]
set_property IOSTANDARD LVCMOS33 [get_ports {seg[6]}]
set_property IOSTANDARD LVCMOS33 [get_ports {sel[5]}]
set_property IOSTANDARD LVCMOS33 [get_ports {seg[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {seg[5]}]
set_property IOSTANDARD LVCMOS33 [get_ports {sel[4]}]
set_property IOSTANDARD LVCMOS33 [get_ports {seg[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {sel[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {sel[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {seg[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {sel[2]}]

4.2 程序下载

数码管动态显示

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

追逐者-桥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值