Menu Close

数码管动态扫描显示Verilog实现–秒表

上章内容介绍了数码管的译码显示,并将数码管固定在右边第一个数码管上。本节内容将接上章内容,如何将多个数码管动态显示不同的内容。在FII-PRA006/010以及FII-PRX100-D的系统中都是采用段共享的6数码管结构。其中FII-PRA006/010的原理图连线如图1,

 

%title插图%num

图1

%title插图%num

图2,按键对应的数码管管脚

%title插图%num

 

图3 按键原理图

1.动态扫描原理

动态扫描的基本原理是采用分时复用的方法,在某一时刻只会有一个数码管点亮,其它数码管处在非点亮状态,利用人眼睛的视觉滞留效应,达到看起来所有数码管被同时点亮的效果。在某个数码管点亮的某一时刻,相对应的显示内容为段译码驱动的各个段,使得不同的内容显示在不同的数码管上。图1中,由于ND336P是P沟道小功率MOS管,因此只有栅极为低电平时才会导通,因此为了达到分时复用的目的,每一段时间内只有SEG_3V3_D0, SEG_3V3_D1, SEG_3V3_D2, SEG_3V3_D3, SEG_3V3_D4, SEG_3V3_D5只有对应的一位为低电平,其它的位都为高电平,依次轮流扫描。

2. 变量描述

针对动态扫描的数码管,这里定义3个变量SEVEN_SEG[6:0],DP,SEAT[5:0],对应关系如下:

  • SEVEN_SEG[6:0]对应A,B,C,D,E,F,G七段,DP对应数码管上的小数点,见表一。由于PRA006/10采用共阳极数码管,而各段经过限流电阻直接连接到FPGA(I/O)管脚上,因此FPGA对应的管脚在输出低电平时点亮对应的数码管的某一段。
  • SEAT[5:0] 对应数码管的位,即在某一时刻到底哪一个数码管应该点亮,SEAT[5:0] 与SEG_3V3_D0, SEG_3V3_D1, SEG_3V3_D2, SEG_3V3_D3, SEG_3V3_D4, SEG_3V3_D5一一对应,见表1。
  • 引入时钟信号inclk和按键KEY3(在FII-PRA006上对应PB0),如表1。从图2. 3可以看出,按键在按下后,对应的FPGA管脚为高电平,按键释放后,FPGA对应的管脚为高电平,这一点与PRX100D 的开发板不同,因此在Verilog程序设计中应有所改变。

表1

程序信号名 网络标号 FPGA管脚 端口说明
clk C10_50MCLK 91 输入时钟
rst KEY3 11 复位按键
SEAT[5] SEG_3V3_D5 124 位选信号第5位
SEAT[4] SEG_3V3_D4 127 位选信号第4位
SEAT[3] SEG_3V3_D3 129 位选信号第3位
SEAT[2] SEG_3V3_D2 141 位选信号第2位
SEAT[1] SEG_3V3_D1 142 位选信号第1位
SEAT[0] SEG_3V3_D0 136 位选信号第0位
SEVEN_SEG[6] SEG_PG 135 段选信号第7位
SEVEN_SEG[5] SEG_PF 138 段选信号第6位
SEVEN_SEG[4] SEG_PE 126 段选信号第5位
SEVEN_SEG[3] SEG_PD 125 段选信号第4位
SEVEN_SEG[2] SEG_PC 133 段选信号第3位
SEVEN_SEG[1] SEG_PB 137 段选信号第2位
SEVEN_SEG[0] SEG_PA 132 段选信号第1位
DP SEG_DP 128 段选信号第0位

3. 程序设计

设计秒表程序,要求如下:右边两个数码管显示1/100秒的显示,范围0-99。第3,4数码管显示秒计数,计数范围0-59,最左边的数码管显示分计数,范围0-59。当按键按下(rst为高)时,清零所有的计数器,按键释放后,秒表开始计数。代码如下:

 /*
 
 
  mapping :
 
 
  SEVEN_SEG[0]  SEVEN_SEG[1]  SEVEN_SEG[2]  SEVEN_SEG[3]  SEVEN_SEG[4]  SEVEN_SEG[5]  SEVEN_SEG[6]
 
 
  *** A*****    *****B*****   *****C*****    *****D****   ******E*****  *****F*****   *****G******
 
 
*/
 
 
module scan_8seg
(
    input            inclk,
    input            rst,
    output reg [6:0] SEVEN_SEG,
    output reg       DP,
    output reg [5:0] SEAT
);
 
reg [3:0]  count_msa, count_msb;
reg [3:0]  count_sa, count_sb;
reg [3:0]  count_ma, count_mb;
reg [15:0] div_count_ms;
reg        f_1ms;
reg [3:0]  div_count_10ms;
reg        f_10ms;
reg [3:0]  count_sel;
 
 //毫秒分频
always@(posedge inclk or posedge rst )
if(rst) 
begin
    div_count_ms <= 0;
    f_1ms <= 0;
end
else 
begin
    f_1ms <= 0;
    if(div_count_ms == 49999)
    begin
        div_count_ms <= 0;
        f_1ms <= 1'b1;
    end
    else 
    begin
        div_count_ms <= div_count_ms + 1;
    end
end

//10毫秒分频
 
always@(posedge inclk or posedge rst )
if(rst) 
begin
    div_count_10ms <= 0;
    f_10ms <= 0;
end
else 
begin
    f_10ms <= 0;
    if(f_1ms) 
    begin
        if(div_count_10ms == 9)
        begin
            div_count_10ms <= 0;
            f_10ms <= 1'b1;
        end
        else 
        begin
            div_count_10ms <= div_count_10ms + 1;
        end
    end
end
 
//计数,毫秒(精度为10毫秒),秒,分
always@(posedge inclk or posedge rst )
if(rst) 
begin
    count_msa <= 0;
    count_msb <= 0;
    count_sa <= 0;
    count_sb <= 0;
    count_ma <= 0;
    count_mb <= 0;
end
else 
begin
    if(f_10ms) 
    begin
        if(count_msa == 9) 
        begin
            count_msa <= 0;
            if(count_msb == 9) 
            begin
                count_msb <= 0;
                if(count_sa == 9) 
                begin
                    count_sa <= 0;
                    if(count_sb == 5) 
                    begin
                        count_sb <= 0;
                        if(count_ma == 9) 
                        begin
                            count_ma <= 0;
                            if(count_mb == 5) 
                                count_mb <= 0;
                            else
                                count_mb <= count_mb + 1;
                        end
                        else
                            count_ma <= count_ma + 1;
                    end
                    else
                        count_sb <= count_sb + 1;
                end
                else
                    count_sa <= count_sa + 1;
            end
            else
                count_msb <= count_msb + 1;
        end
        else
            count_msa <= count_msa + 1;
    end 
end
 
//====================  数码管扫描
 
always@(posedge inclk or posedge rst )
if(rst) 
begin
    SEAT <= 6'b11_1111;
    count_sel <= 0;
    DP <= 1'b1;
end
else 
begin
    if(f_1ms) 
    begin
        case (SEAT)
        6'b11_1110:     
        begin
            SEAT <= 6'b11_1101;
            count_sel <= count_msb;
            DP <= 1'b1;
        end
        6'b11_1101: 
        begin
            SEAT <= 6'b11_1011;
            count_sel <= count_sa;
            DP <= 1'b0;
        end
        6'b11_1011: 
        begin
            SEAT <= 6'b11_0111;
            count_sel <= count_sb;
            DP <= 1'b1;
        end
        6'b11_0111: 
        begin
            SEAT <= 6'b10_1111;
            count_sel <= count_ma;
            DP <= 1'b0;
        end
        6'b10_1111: 
        begin
            SEAT <= 6'b01_1111;
            count_sel <= count_mb;
            DP <= 1'b1;
        end
        6'b01_1111: 
        begin
            SEAT <= 6'b11_1110;
            count_sel <= count_msa;
            DP <= 1'b1;
        end
        default: SEAT <= 6'b01_1111;
        endcase
    end
end
 //7段显示译码
always@(*)
case(count_sel)
0:       SEVEN_SEG = 7'b100_0000;
1:       SEVEN_SEG = 7'b111_1001;
2:       SEVEN_SEG = 7'b010_0100;
3:       SEVEN_SEG = 7'b011_0000;
4:       SEVEN_SEG = 7'b001_1001;
5:       SEVEN_SEG = 7'b001_0010;
6:       SEVEN_SEG = 7'b000_0010;
7:       SEVEN_SEG = 7'b111_1000;
8:       SEVEN_SEG = 7'b000_0000;
9:       SEVEN_SEG = 7'b001_0000;
4'ha:    SEVEN_SEG = 7'b000_1000;
4'hb:    SEVEN_SEG = 7'b000_0011;
4'hC:    SEVEN_SEG = 7'b100_0110;
4'hd:    SEVEN_SEG = 7'b010_0001;
4'hE:    SEVEN_SEG = 7'b000_0110;
4'hF:    SEVEN_SEG = 7'b000_1110;
default: SEVEN_SEG = 7'b111_1111;   
endcase
 
endmodule

 

  1. 编译,管脚锁定,重新编译下载,测试。
  2. 测试中几个方法:
    1. 由于最低位的数码管显示的1/100秒,变化速度太快,无法看清计数是否正确,可以将f_10ms在分频调慢50倍,用于调式,调试结束后,还原到1/100秒的分频。
    2. 分计数器,依赖秒计数的进位,因此验证分计数器是否正确计数,等待时间过长,可以将f_10ms再调快100倍用于测试,测设完成后,还原到最初的分屏程序。

思考题:

  1. DP的显示是如何在正确的位置上的?
  2. SEVEN_SEG是否可以利用时钟锁存后输出,有什么差别?如果时钟锁存输出,程序如何修改?

作业题:

参照上文,根据PRX100-D的硬件原理(数码管,按键),在Vivado下完成数码管扫描显示设计,并在PRX100-D实验开发板上完成相关实验,最后编写实验设计报告。

 

Posted in FPGA, FPGA, Quartus II, Verilog, Verilog, 开发工具, 教材与教案, 文章

发表评论

相关链接