下冰雹 · 2022年03月09日

【安路 EG4S20 版本】数码管动态显示实验

实验7 数码管动态显示一

在这部分的实验中,将结合之前介绍的模块化设计思想以及数字电路中组合逻辑与时序逻辑的知识,分享三个在FPGA开发板上实现数码管动态显示的案例。

数码管动态显示原理

在开展本章实验之前,我们需要先了解一下数码管动态显示的原理。在之前的实验三和四中,曾介绍过数码管的显示原理和静态显示的方法。
由于多位数码管的段选信号是连接在一起的,即数码管是共享段码的,那么所有点亮的数码管在同一时刻只能显示相同的图案。这看似大大局限了数码管的显示效果,但其实也有办法让多位的数码管在人眼看来能“同时”显示不同的图案,以获得更多样性的显示效果。其实现方法就是利用人眼的视觉暂留效应,轮流点亮数码管,并且在各位数码管点亮的期间给出对应的段码,只要进行这一过程的速度控制得当,人眼就来不及观察到各个数码管依次点亮,而是能看到多位数码管稳定地显示各自的图案。
在上个链接的文章,即介绍模块化设计的文章中,有一个实例是利用拨码开关手动地控制数码管的位选。而在实现数码管动态显示时,这个轮流选通的过程其实也是类似的,不过该过程需要电路能“自动”完成,且对位选通的时间间隔有一定要求,这一时间间隔既不能过长,否则人眼观察时有闪烁感,也不能过短,否则观察时数码管亮度会比较低。对于这篇文章中演示时使用的FPGA开发板来说,板载数码管共有四位,可以将数码管位选通的时间间隔设置为1ms。
实例一将分享一个基本的数码管动态显示案例。其实现目标是通过开发板上的两组拨码开关SW3-SW0、SW7-SW4分别控制四位数码管(高两位和低两位显示内容一致)进行十六进制显示。根据数码管动态显示的原理和模块化设计的思想,该实例的电路框图设想如下:
image.png
实例一电路框图
如上图所示,既然涉及数码管显示,显示译码的部分是必不可少的,该模块由两个译码器组成,分别负责数码管位选译码和段码译码,进行段码译码的译码器还需要通过多路复用器与数据输入进行连接。另外,由于板载的晶振时钟频率为50MHz,要实现动态显示原理中介绍的以1ms为时间间隔进行位扫描,需要对时钟进行分频,得到1KHz的时钟,所以电路中需要一个时钟分频的模块。最后,便是实现数码管的轮流选通以实现动态显示,为了能在某位数码管被选通的同时能给出对应该位数码管的段码,需要有一个模块指明当前点亮的是哪一位数码管,在该设计中采用的是计数器来充当这一模块。该计数器以分频得到的时钟作为输入,计数输出既作为位选译码器的输入也作为多路复用器的控制信号输入,这样就可以实现数码管在轮流选通的同时,也得到对应的段码输出。

代码解析

下面给出了实例一中负责显示译码功能的两个模块的参考代码,实质都是译码器,分别是数码管的位选译码模块和段码译码模块。这两个模块可在涉及数码管显示的工程中复用,复用时如果使用的数码管位数不同,只需要调整位选译码模块端口声明中bit_disp的位宽以及位选译码部分的代码即可,段码译码模块一般不需要作调整。

module seg_sel_decoder(bit_disp,seg_sel);
    input [1:0] bit_disp;
    output reg [3:0] seg_sel;
    always@(bit_disp)
        case(bit_disp)
    2'b00 : seg_sel = 4'b1110;
2'b01 : seg_sel = 4'b1101;
    2'b10 : seg_sel = 4'b1110;
    2'b11 : seg_sel = 4'b1101;
default : seg_sel = 4'b1111;       
 endcase
endmodule

module seg_led_decoder(data_disp,seg_led);
    input [3:0] data_disp;
    output reg [7:0] seg_led;
    always@(*)
        case(data_disp)
            4'h0 : seg_led = 8'h3f;
            4'h1 : seg_led = 8'h06;
            4'h2 : seg_led = 8'h5b;
            4'h3 : seg_led = 8'h4f;
            4'h4 : seg_led = 8'h66;
            4'h5 : seg_led = 8'h6d;
            4'h6 : seg_led = 8'h7d;
            4'h7 : seg_led = 8'h07;
            4'h8 : seg_led = 8'h7f;
            4'h9 : seg_led = 8'h6f;
            4'ha : seg_led = 8'h77;
            4'hb : seg_led = 8'h7c;
            4'hc : seg_led = 8'h39;
            4'hd : seg_led = 8'h5e;
            4'he : seg_led = 8'h79;
            4'hf : seg_led = 8'h71;
            default :seg_led = 8'h00;
        endcase
endmodule 

下面是时钟分频模块的代码,在上一篇文章中也有介绍,这里为了模块复用的方便,使用了parameter语句进行参数化设计,当需要得到其他频率的时钟时,只需要在例化时更改分频计数值的最大值即可(但该值不可以超过2^32,因为模块中cnt寄存器设置的位宽为32位) 。

module clock_division(clk_in,divclk);
    input clk_in;
    output divclk;
    parameter DIVCLK_CNTMAX = 24999; //时钟分频计数的最大值
    reg [31:0] cnt = 0;              
    reg divclk_reg = 0;
    always@(posedge clk_in) begin
        if(cnt == DIVCLK_CNTMAX) begin
            cnt <= 0;
            divclk_reg <= ~divclk_reg;
        end
        else
            cnt <= cnt + 1;
    end 
    assign divclk = divclk_reg;
endmodule

接下来是计数器模块的参考代码,其功能是在每个输入时钟的上升沿使计数值加1。由于实例一使用了两位数码管,因此计数器设置的最大计数值为2’b11,该计数器模块计数值的循环序列为2’b00、2’b01、2’b10、2’b11。

module counter(clk,cnt);
    input clk;
    output reg [1:0] cnt = 0;
    always@(posedge clk) begin
        if(cnt == 2'b11)
            cnt <= 2'b00;
        else 
            cnt <= cnt + 1'b1;
    end
endmodule

接着是多路复用器模块的参考代码,结合实例一的框图,需要描述一个三选一的多路复用器。

module Mux(sel,ina,inb,data_out);
    input [1:0] sel;
    input [3:0] ina,inb;
    output reg [3:0] data_out;
    always@(*)
        case(sel) 
            2'b00 : data_out = ina;
            2'b01 : data_out = inb;
            2'b10 : data_out = ina;
            2'b11 : data_out = inb;
            default : data_out = 0;
        endcase
endmodule

最后是顶层模块,根据设想的框图将各个模块例化即可,我们可以再次回顾一下例化的意义,其实就是用硬件代码的方式把电路各元件之间的连接关系描述出来。如下是顶层模块的参考代码,可以注意一下例化时钟分频模块时进行参数传递的方式,该方法在进行功能仿真时也会用到。

module TOP(clk_50M,ina,inb,seg_sel,seg_led);
    input clk_50M;
    input [3:0] ina, inb;
    output [3:0] seg_sel;
output [7:0] seg_led;
    parameter DIVCLK_CNTMAX = 24999; //50M/50K = 1K
wire clk_1K;
    //例化时钟分频模块
    clock_division #(
        .DIVCLK_CNTMAX(DIVCLK_CNTMAX)
    )
    my_clock(
        .clk_in(clk_50M),
        .divclk(clk_1K)
);
    //例化计数器模块
    wire [1:0] bit_disp;
    counter counter(
        .clk(clk_1K),
        .cnt(bit_disp)
);
    //例化多路复用器模块
    wire [3:0] data_disp;
    Mux Mux(
        .sel(bit_disp),
        .ina(ina),
        .inb(inb),
        .data_out(data_disp)
);  
    //例化数码管位选译码模块
    seg_sel_decoder seg_sel_decoder(
        .bit_disp(bit_disp),
        .seg_sel(seg_sel)
    );
    //例化数码管段码译码模块
    seg_led_decoder seg_led_decoder(
        .data_disp(data_disp),
        .seg_led(seg_led)
    );
endmodule

在TD的原理图工具中可以看到代码的模块化设计:
image.png

功能仿真

下面进行实例一的功能仿真。上一篇文章中也提到过,由于实例中包含时钟分频的部分,如果不修改时钟分频的参数,仿真需要的时间将会过长,而且得到的仿真波形也不利于观察,所以可以在编写testbench时修改时钟分频计数最大值,更快地完成功能仿真,而且同样能观察到时钟分频模块是否正常工作,只是得到的时钟频率不同。实例一的testbench参考代码如下,例化时将分频计数的最大值改为了1,即只对时钟进行四分频,可以加快仿真过程。如下是testbench的参考代码。

module dynamic_disp_instance1_tb;
    reg clk;
    reg [3:0] ina,inb,inc;
    wire [3:0] seg_sel;
    wire [7:0] seg_led;
    TOP #(
        .DIVCLK_CNTMAX(1)
    )
    UUT(
        .clk_50M(clk),
        .ina(ina),
        .inb(inb),
        .seg_sel(seg_sel),
        .seg_led(seg_led)
);
    initial begin
        clk = 1'b0; ina = 4'h0; inb = 4'h0; 
        #200
        ina = 4'h1; inb = 4'h2; 
        #200
        ina = 4'h6; inb = 4'h7;
        #200
        ina = 4'ha; inb = 4'he; 
        #200
        $stop;
    end
    always #10 clk = ~clk;
endmodule

下面给出了在Modelsim中的部分仿真波形,可以观察到由于testbench中将分频计数最大值的参数改为了1,分频模块对时钟进行了四分频,另外,计数器工作正常,显示译码的结果也是正确的。后续两个实例的仿真也是类似的,都可以通过修改参数缩短仿真所需的时间,在过程块中设置不同的输入组合进行简单的功能测试。由于过于相似,在之后的两个实例中就不再重复这一过程,希望读者能自己尝试着编写testbench,养成上板验证前进行仿真的习惯。
image.png
实例一仿真波形

上板验证

仿真完成后在TD中进行综合、管脚约束、布局布线并生成比特流文件,便可以上板观察现象。下面给出了本例的管脚约束。
set_pin_assignment { clk_50M } { LOCATION = R7; }
set_pin_assignment { ina[0] } { LOCATION = A9; }
set_pin_assignment { ina[1] } { LOCATION = A10; }
set_pin_assignment { ina[2] } { LOCATION = B10; }
set_pin_assignment { ina[3] } { LOCATION = A11; }
set_pin_assignment { inb[0] } { LOCATION = A12; }
set_pin_assignment { inb[1] } { LOCATION = B12; }
set_pin_assignment { inb[2] } { LOCATION = A13; }
set_pin_assignment { inb[3] } { LOCATION = A14; }
set_pin_assignment { seg_sel[0] } { LOCATION = C9; IOSTANDARD = LVCMOS33; }
set_pin_assignment { seg_sel[1] } { LOCATION = B6; IOSTANDARD = LVCMOS33; }
set_pin_assignment { seg_sel[2] } { LOCATION = A5; IOSTANDARD = LVCMOS33; }
set_pin_assignment { seg_sel[3] } { LOCATION = A3; IOSTANDARD = LVCMOS33; }
set_pin_assignment { seg_led[0] } { LOCATION = A4; IOSTANDARD = LVCMOS33; }
set_pin_assignment { seg_led[1] } { LOCATION = A6; IOSTANDARD = LVCMOS33; }
set_pin_assignment { seg_led[2] } { LOCATION = B8; IOSTANDARD = LVCMOS33; }
set_pin_assignment { seg_led[3] } { LOCATION = E8; IOSTANDARD = LVCMOS33; }
set_pin_assignment { seg_led[4] } { LOCATION = A7; IOSTANDARD = LVCMOS33; }
set_pin_assignment { seg_led[5] } { LOCATION = B5; IOSTANDARD = LVCMOS33; }
set_pin_assignment { seg_led[6] } { LOCATION = A8; IOSTANDARD = LVCMOS33; }
set_pin_assignment { seg_led[7] } { LOCATION = C8; IOSTANDARD = LVCMOS33; }
实例一管脚约束

实验8 数码管动态显示二_电子秒表

文章来源:https://www.yuque.com/yingmuketang/01/ql25a0

在上一例中,使用了FPGA开发板上的拨码开关控制四位数码管进行动态显示,在本例中,我们将数码管作为一个整体IP,然后用一个计数器驱动它实现一个电子秒表的功能。根据这一实现目标,给出了如下的电路框图构想。
image.png
实验八 电路框图
上图中的许多模块与实例一致,因为涉及数码管的动态显示,所以仍然需要显示译码、时钟分频、多路复用器和计数器模块,我们这里写一个数码管驱动的顶层模块,把这几个模块作为数码管驱动模块的子模块,这样用户在使用数码管时只需要输入一个1KHz时钟,和ina,inb,inc,ind四个要显示的值就可以了。
本例中我们设计了一个电子秒表的计数器模块,从00.00秒计时到1分59.99秒循环,其中59.99秒显示在数码管上,分钟用LED0来显示。SW1用于复位秒表到0:00.00,SW0用于启动和暂停计数器。

代码解析

我们先从顶层文件看起,从顶层文件我们可以看到一共有四个模块:两个时钟分频模块输出1KHz和100Hz两路时钟,100Hz时钟驱动的电子秒表计数模块和1KHz时钟驱动的数码管显示模块:


module TOP(clk_50M,seg_sel,seg_led,sw,min);
    input clk_50M;
    input [1:0] sw;    
    output min;
    output [3:0] seg_sel;
    output [7:0] seg_led;

    //50M/50K = 1K
    parameter DIVCLK_CNTMAX_1000 = 24999;
    wire clk_1K;
   //50M/500K = 100
    parameter DIVCLK_CNTMAX_100 = 249999;
    wire clk_100;    

    //例化时钟分频模块1
    clock_division #(
        .DIVCLK_CNTMAX(DIVCLK_CNTMAX_1000)
    )
    clk_1000Hz(
        .clk_in(clk_50M),
        .divclk(clk_1K)
    );        
    //例化时钟分频模块2
    clock_division #(
        .DIVCLK_CNTMAX(DIVCLK_CNTMAX_100)
    )
    clk_100Hz(
        .clk_in(clk_50M),
        .divclk(clk_100)
    );              
    //例化秒表计数模块              
    wire min;
    wire[3:0] sec_0_01,sec_0_1,sec_1,sec_10;   
    Stopwatch mystopwatch    
    (    
     .clk_100(clk_100),    
     .sw(sw),     
     .sec_0_01(sec_0_01),     
     .sec_0_1(sec_0_1),     
     .sec_1(sec_1),     
     .sec_10(sec_10),     
     .min(min)     
      );    
  //例化数码管显示模块 
  Digitron4bits mydigitron        
   (.clk_1K(clk_1K),  
    .ina(sec_0_01),   
    .inb(sec_0_1),   
    .inc(sec_1),    
    .ind(sec_10),    
    .dot(3'b111),
    .seg_sel(seg_sel),
    .seg_led(seg_led));  
endmodule

通过TD可以得到如下的原理图:
image.png
其中mydigitron模块就是我们把实验7里的数码管显示程序“打包得到”,在Project中可以看可到mydigitron下面的各个模块程序:
image.png
双击原理图中的mydigitron模块就可以看到跟实验7相似的模块组成:
image.png
mystopwatch即是我们这次写的电子秒表的计数程序:


 module Stopwatch(clk_100,sw,sec_0_01,sec_0_1,sec_1,sec_10,min);
    input clk_100;
    input [1:0] sw;    
    output reg min;
    output reg[3:0] sec_0_01,sec_0_1,sec_1,sec_10;     
 always@(posedge clk_100)//每1/100秒处理计时和设置
    begin
      if (sw[1]==0) //复位
          begin   
                    sec_0_01<=0;
                    sec_0_1<=0;
                    sec_1<=0;                    
                    sec_10<=0;  
                     min<=0;               
           end                       
         else if (sw[1]==1)           
           if (sw[0] == 0)         
               sec_0_01 <= sec_0_01;           
             else if (sw[0] == 1)               
              begin                 
                 sec_0_01 <= sec_0_01 + 1;  
              if (sec_0_01==10)
                      begin
                    sec_0_01<=0;
                      sec_0_1<=sec_0_1+1;              
                       if (sec_0_1 == 9)              
                          begin                
                             sec_0_1 <= 0;                  
                              sec_1 <= sec_1 + 1;                    
                                if (sec_1 == 9)              
                               begin                
                                 sec_1 <= 0;                  
                                   sec_10 <= sec_10 + 1;                            
                                  if (sec_10 == 5)              
                                   begin                
                                     sec_10 <= 0;                  
                                      min <= min + 1;                         
                                     if (min == 1)                          
                                        min <= 0;                                                                  end                                         
                                end 
                            end 
                        end                                           
                     end                      
        end                          
endmodule          


实际上就是多个十进制计数器和6进制计数器的级联。

上板验证



set_pin_assignment { clk_50M } { LOCATION = R7; }

set_pin_assignment { sw[0] } { LOCATION = A9; }

set_pin_assignment { sw[1] } { LOCATION = A10; }

set_pin_assignment { min } { LOCATION = B14; }

set_pin_assignment { seg_sel[0] } { LOCATION = C9; IOSTANDARD = LVCMOS33; }

set_pin_assignment { seg_sel[1] } { LOCATION = B6; IOSTANDARD = LVCMOS33; }

set_pin_assignment { seg_sel[2] } { LOCATION = A5; IOSTANDARD = LVCMOS33; }

set_pin_assignment { seg_sel[3] } { LOCATION = A3; IOSTANDARD = LVCMOS33; }

set_pin_assignment { seg_led[0] } { LOCATION = A4; IOSTANDARD = LVCMOS33; }

set_pin_assignment { seg_led[1] } { LOCATION = A6; IOSTANDARD = LVCMOS33; }

set_pin_assignment { seg_led[2] } { LOCATION = B8; IOSTANDARD = LVCMOS33; }

set_pin_assignment { seg_led[3] } { LOCATION = E8; IOSTANDARD = LVCMOS33; }

set_pin_assignment { seg_led[4] } { LOCATION = A7; IOSTANDARD = LVCMOS33; }

set_pin_assignment { seg_led[5] } { LOCATION = B5; IOSTANDARD = LVCMOS33; }

set_pin_assignment { seg_led[6] } { LOCATION = A8; IOSTANDARD = LVCMOS33; }

set_pin_assignment { seg_led[7] } { LOCATION = C8; IOSTANDARD = LVCMOS33; }

实例二管脚约束

实验9 数码管动态显示三_倒计时器

下面将介绍数码管显示的最后一个实例,该例的实现目标为通过拨码开关输入BCD码设置起始时间(单位为秒,高两位和低两位显示相同的数据,中间用:分开),由数码管显示倒计时的过程。通过前面两个实例,相信读者对数码管进行动态显示所必需的这部分电路已经很熟悉了,需要关心的是如何能得到正确的数据来进行显示译码。根据实例三想要实现的主要功能倒计时,可以很容易联想到计数器,倒计时本身就是一种向下计数的过程,所以可以通过设计一个向下计数器来实现。由于倒计时一般是十进制显示,因此本例需要限制拨码开关的输入为BCD码输入,同样地,上面提到的向下计数器也需要专门设计为BCD码向下计数器。通过两个BCD码计数器进行级联,就可以实现起始数据为两位数的向下计数。
image.png
实例三电路框图
通过上面的分析,数码管显示部分已经被我们做成了一个整体模块,下面我们主要关注BCD码向下计数器的设计。根据实例三的实现目标,要能实现通过拨码开关设置倒计时起始时间的功能,BCD码向下计数器需要设置有置数的功能,另外为了进行级联,还需要设置用于级联的输入输出信号。BCD码向下计数器的参考设计如下图所示。
image.png
BCD码向下计数器
下面给出了BCD码向下计数器的参考代码,计数值为4位的BCD码,在每个时钟上升沿,若借位输入有效则进行向下计数,当向下计数至0时若借位输入仍有效,则拉高借位输出。该计数器还带有异步复位和同步置数的功能。

module BCD_downcounter(
    input clk,              //时钟输入
    input rst_n,              //异步复位输入
    input bin,              //借位输入
    input preset_n,           //同步预置数输入
    input [3:0] BCD_i,       //BCD码计数输入
    output [3:0] BCD_o,     //BCD码计数输出
    output bout           //借位输出
);
    reg [3:0] cnt;
    always@(posedge clk or negedge rst_n) begin
        if(!rst)
            cnt <= 0;
        else if(!preset_n)
            cnt <= BCD_i;
        else if(bin) begin
            if(cnt == 4'd0)
                cnt <= 4'd9;
            else
                cnt <= cnt - 1'b1;
        end
    end
    assign BCD_o = cnt;
    assign bout = bin && (cnt == 4'd0); //向下计数至0时同步输出bout信号
endmodule

如下给出了顶层模块的参考代码,编写时同样要注意各模块例化时的端口连接。本例中需要例化两个时钟分频模块,一个产生1KHz(周期为1ms)的时钟用于数码管依次选通位选信号,另一个产生1Hz(周期为1s)的时钟作为BCD码向下计数器的输入时钟以实现倒计时的功能。BCD码向下计数器模块的例化和级联也需要注意,级联的方法是将进行个位计数器的借位输出连接到进行十位计数器的借位输入。另外参考代码中将个位计数器的借位输入与两个计数器BCD码输出的逻辑或相连接,目的是在倒计时至0后停止计数,若想要进行循坏计数,可以在例化个位的BCD码向下计数器时将借位输入bin直接拉高。

module TOP(clk_50M,units,tens,rst_n,preset_n,seg_sel,seg_led,row);
    input clk_50M;
    input [3:0] units,tens;
    input rst_n;
    input preset_n;
    output [3:0] seg_sel;
    output [7:0] seg_led;    
    output [3:0] row;
//将行列键盘的行输出0
    assign row = 4'b0000;    

    //50M/1K = 5K
    parameter DIVCLK_CNTMAX_1ms = 24999;
    wire clk_1ms;
    //50M/1 = 50M
    parameter DIVCLK_CNTMAX_1s = 24999999;
    wire clk_1s;

    //例化时钟分频模块,得到周期为1ms的时钟
    clock_division #(
        .DIVCLK_CNTMAX(DIVCLK_CNTMAX_1ms)
    )
    my_clock_0(
        .clk_in(clk_50M),
        .divclk(clk_1ms)
    );

    //例化时钟分频模块,得到周期为1s的时钟
    clock_division #(
        .DIVCLK_CNTMAX(DIVCLK_CNTMAX_1s)
    )
    my_clock_1(
        .clk_in(clk_50M),
        .divclk(clk_1s)
    );

    //例化BCD码向下计数器模块,并进行级联
    wire bin;
    wire bout_0;
    wire bout_1;
    wire [3:0] units_disp;
    wire [3:0] tens_disp;
    assign bin = units_disp || tens_disp;
    BCD_downcounter downcounter_0(
        .clk(clk_1s),
        .rst_n(rst_n),
        .bin(bin),
        .preset_n(preset_n),
        .BCD_i(units),
        .BCD_o(units_disp),
        .bout(bout_0)
    );        

    BCD_downcounter downcounter_1(
        .clk(clk_1s),
        .rst_n(rst_n),
        .bin(bout_0),
        .preset_n(preset_n),
        .BCD_i(tens),
        .BCD_o(tens_disp),
        .bout(bout_1)
    );
  //例化数码管显示模块 
  Digitron4bits mydigitron        
   (.clk_1K(clk_1ms),  
    .ina(units_disp),   
    .inb(tens_disp),   
    .inc(units_disp),    
    .ind(tens_disp),    
    .dot(3'b110),
    .seg_sel(seg_sel),
    .seg_led(seg_led));  
endmodule

实例三管脚约束

set_pin_assignment    { clk_50M }    { LOCATION = R7; }
set_pin_assignment    { units[0] }    { LOCATION = A9; }
set_pin_assignment    { units[1] }    { LOCATION = A10; }
set_pin_assignment    { units[2] }    { LOCATION = B10; }
set_pin_assignment    { units[3] }    { LOCATION = A11; }
set_pin_assignment    { tens[0] }    { LOCATION = A12; }
set_pin_assignment    { tens[1] }    { LOCATION = B12; }
set_pin_assignment    { tens[2] }    { LOCATION = A13; }
set_pin_assignment    { tens[3] }    { LOCATION = A14; }
set_pin_assignment    { seg_sel[0] }    { LOCATION = C9; IOSTANDARD = LVCMOS33; }
set_pin_assignment    { seg_sel[1] }    { LOCATION = B6; IOSTANDARD = LVCMOS33; }
set_pin_assignment    { seg_sel[2] }    { LOCATION = A5; IOSTANDARD = LVCMOS33; }
set_pin_assignment    { seg_sel[3] }    { LOCATION = A3; IOSTANDARD = LVCMOS33; }
set_pin_assignment    { seg_led[0] }    { LOCATION = A4; IOSTANDARD = LVCMOS33; }
set_pin_assignment    { seg_led[1] }    { LOCATION = A6; IOSTANDARD = LVCMOS33; }
set_pin_assignment    { seg_led[2] }    { LOCATION = B8; IOSTANDARD = LVCMOS33; }
set_pin_assignment    { seg_led[3] }    { LOCATION = E8; IOSTANDARD = LVCMOS33; }
set_pin_assignment    { seg_led[4] }    { LOCATION = A7; IOSTANDARD = LVCMOS33; }
set_pin_assignment    { seg_led[5] }    { LOCATION = B5; IOSTANDARD = LVCMOS33; }
set_pin_assignment    { seg_led[6] }    { LOCATION = A8; IOSTANDARD = LVCMOS33; }
set_pin_assignment    { seg_led[7] }    { LOCATION = C8; IOSTANDARD = LVCMOS33; }
//行列键盘的行输出
set_pin_assignment    { row[0] }    { LOCATION = E10; IOSTANDARD = LVCMOS33; }
set_pin_assignment    { row[1] }    { LOCATION = C10; IOSTANDARD = LVCMOS33; }
set_pin_assignment    { row[2] }    { LOCATION = F9; IOSTANDARD = LVCMOS33; }
set_pin_assignment    { row[3] }    { LOCATION = D9; IOSTANDARD = LVCMOS33; }
//使用列按键col[1]做为置位输入,按下key1或key5或key9或key13都可以置位,注意这个低电平是用1Hz的时钟采样的,因为按键保持的时间可能需要长一点
set_pin_assignment    { preset_n}    { LOCATION = D11; IOSTANDARD = LVCMOS33; }
//使用列按键col[0]做为置位输入,按下key0或key4或key8或key12都可以置位,注意这个低电平是用1Hz的时钟采样的,因为按键保持的时间可能需要长一点
set_pin_assignment    { rst_n }    { LOCATION = E11; IOSTANDARD = LVCMOS33; }

至此,关于数码管动态显示的三个实例就分享完毕了,本期文章中介绍了数码管动态显示的原理,分享的三个实例都采用了模块化设计的思想进行实现,同时还应用到了数字电路中组合逻辑和时序逻辑的知识。

END

文章来源:
https://www.yuque.com/yingmuketang/01/luqfxd#oBMfU
https://www.yuque.com/yingmuketang/01/cur4ku

推荐内容

更多内容请关注走进FPGA专栏
推荐阅读
关注数
1615
内容数
27
本专栏将以【安路EG4S开发板】为例,从基础板卡信息及使用教程,基础实验设计与实现及综合性实验设计与实现带大家学习FPGA。
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息