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

这篇具有很好参考价值的文章主要介绍了二、19【FPGA】数码管动态显示实验。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

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

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

理论学习

1、数码管动态显示

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

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

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

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

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

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

2、二进制转BCD码

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

分为:有权码和无权码

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

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

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

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

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

  • 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 功能模块框图

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

2.2 Data_gen 数据生成模块

  • 波形图

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

  • 程序代码 
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
  • 仿真波形

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

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

2.3 bcd_8421二进制转十进制模块

  • 波形图

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

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位。

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

2.4 seg_dynamic 数码管驱动模块

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

  • 波形图

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

 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
  • 仿真波形 

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

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

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 程序下载

数码管动态显示文章来源地址https://www.toymoban.com/news/detail-401496.html

到了这里,关于二、19【FPGA】数码管动态显示实验的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • FPGA基本实验之数码管的静态显示

    此实验基于FPGA征途pro开发板实现, 数码管是一种半导体发光器件,其基本单元是发光二极管。数码管按段数一般分为七 段数码管和八段数码管,八段数码管比七段数码管多一个发光二极管(多一个小数点显 示)。当然也还有一些其他类型的数码管如“N”形管、“米”字管

    2024年02月03日
    浏览(48)
  • 实验三 基于FPGA的数码管动态扫描电路设计 quartus/数码管/电路模块设计

    源文件的链接放在最后啦 实验目的: (1) 熟悉7段数码管显示译码电路的设计。 (2) 掌握数码管显示原理及静态、动态扫描电路的设计。 实验任务: (1) 基本任务1:利用FPGA硬件平台上的4位数码管做静态显示,用SW0-3输入BCD码,用SW4-7控制数码管位选; (2) 基本任务

    2024年02月07日
    浏览(55)
  • FPGA项目(5)--FPGA控制数码管动态显示的原理

            数码管是现在电子产品上常用的显示器件,它有驱动简单、显示清晰、价格低廉等优势。数码管的实物图:          数码管的内部结构图如下所示:          从图中可以看出,它由八个段组成,即A B C D E F G DP(小数点),只要将这八个段按规律组合点亮,就

    2024年02月11日
    浏览(50)
  • <微机原理>[汇编语言]-[实验七]数码管动态显示实验

    实验一 软件开发环境和简单程序设计 实验二 I_O输入输出实验 实验三 键盘扫描显示实验 实验四 中断实验 实验五 定时器实验 实验六 串行口实验 实验七 数码管动态显示实验 实验八 矩阵键盘应用实验 实验九 电子时钟 微机原理实验课程,会陆续根据目录更新文章 掌握LED八段

    2024年02月07日
    浏览(38)
  • FPGA 驱动数码管动态显示(Verilog&Vivado)

    应用实例: (1)使用串口发送实现ACX720开发板时钟显示 本章将实现 FPGA 驱动数码管动态显示并提取出实现的电路结构,从电路结构入手编写代码,仿真对设计进行验证。最终板级调试时使用 Virtual Input/Output(VIO,虚拟输入/输出端口工具),输入需要显示的数据,数码管则显

    2023年04月12日
    浏览(52)
  • verilog学习笔记- 15)动态数码管显示实验

    目录 简介: 实验任务: 硬件设计: 程序设计: 下载验证: 由于一般的静态驱动操作虽然方便,但占用的 I/0 口较多,例如要驱动6 位 8 段数码管,以静态驱动方式让数码管各个位显示不同的数值,如“123456”,需要占用6 × 8 = 48个I/O 口,虽然对于 FPGA 这种 I/O 口较多的芯片

    2024年02月07日
    浏览(45)
  • 【数电实验】实验 5 数码管动态扫描显示电路设计

    【2023-11-16:修改Y为4位宽,支持显示学号8和9】 实验要求 一、实验目的 1. 学习动态扫描显示数码管的使用。 2. 学习数据选择器及其信号分配方法。 3. 巩固 Verilog HDL 层次化设计电路的方法。 利用modelsim仿真 模块代码 1.modelsim仿真代码 2.程序源代码 RTL电路图 验收波形图 引脚

    2024年02月03日
    浏览(48)
  • FPGA_数码管显示

    一位数码管: 数码管等效电路(共阴极 和 共阳极) 数码管显示的值: 假设我们需要b,c亮,我们只需要给b,c接高电平,其他接低电平就可。 seg[7:0]  = 8\\\'b0000_0110 对于数码管显示的值,seg值如下图: 多位数码管-----如下图(以3位为例) 假设现在需要LED1亮,那么就让sel0为1,

    2024年01月23日
    浏览(46)
  • FPGA学习—数码管显示

    数码管动态显示采用了人眼暂存的原理,即时分复用,在数码管实现动态显示。 整个实验设计流程框架如下图所示: 开发板采用共阳极数码管,即低电平点亮。 本实验准备设计一个定时器,6为数码管显示24小时制的时间,所以编写一个计数模块。 改变变量COUNT的数值,可实

    2024年02月09日
    浏览(42)
  • Intel FPGA:数码管显示

    个人说明: 限于时间紧迫以及作者水平有限,本文错误、疏漏之处恐不在少数,恳请读者批评指正。意见请留言或者发送邮件至:“Email:noahpanzzz@gmail.com” 。 本博客的工程文件均存放在:GitHub:https://github.com/panziping。 本博客的地址:CSDN:https://blog.csdn.net/ZipingPan 。 参考: 芯

    2024年04月15日
    浏览(36)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包