FPGA 驱动数码管动态显示(Verilog&Vivado)

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

应用实例:
(1)使用串口发送实现ACX720开发板时钟显示


前言

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

提示:以下是本篇文章正文内容,下面案例可供参考

一、数码管驱动原理

其中 8 段数码管的结构图如下图所示,
FPGA 驱动数码管动态显示(Verilog&Vivado)

由上图可以看出数码管有两种结构:共阴极与共阳极。这两者的区别在于,公共端是连接到地还是高电平,对于共阴数码管需要给对应段以高电平才会使其点亮,而对于共阳极数码管则需要给低电平才会点亮。ACX720 上板载的是共阳数码管。同时为了显示数字或字符,必须对数字或字符进行编码译码。这里先不考虑小数点也就是简化为 7 段数码管,其编码译码格式如下表所示:
FPGA 驱动数码管动态显示(Verilog&Vivado)
段式数码管工作方式有两种:静态显示方式和动态显示方式。静态显示的特点是每个数码管的段选必须接一个 8 位数据线来保持显示的字形码。当送入一次字形码后,显示字形可一直保持,直到送入新字形码为止。这种方法由于每一个数码管均需要独立的数据线因此硬件电路比较复杂,成本较高,很少使用。为了节约 IO 以及成本一般采用如下图所示的电路结构,这样 3 个数码管接在一起就比静态的少了 7*2 个 I/O。
FPGA 驱动数码管动态显示(Verilog&Vivado)
这样就实现了另一种显示模式,动态显示。动态显示的特点是将所有位数码管的段选线并联在一起,由位选线控制是哪一位数码管有效。选亮数码管采用动态扫描显示。所谓动态扫描显示即轮流向各位数码管送出字形码和相应的位选,利用发光管的余辉和人眼视觉暂留作用,使人的感觉好像各位数码管同时都在显示。

二、设计思路

现在举例假设将扫描时间定为 1S,这三个数码管分成 3s,第 1 秒时 sel 数据线上为b100,这时数码管 0 被选中,这时 a=0,数码管 0 的 LED0 就可以点亮;第 2 秒时 sel 数据线上为b010,这时数码管 1 被选中,这时 b=0,数码管 1 的 LED1 就可以点亮;第 3 秒时 sel 数据线上为b001,这时数码管 2 被选中,这时 c=0,数码管 2 的 LED2 就可以点亮。这时的效果会是数码管 0 的 LED0 亮一秒后数码管 1 的 LED1 亮一秒最后是数码管 2 的 LED2 亮一秒,这样再次循环。
这样如果使用 1ms 刷新时间的话由于数码管的余辉效应以及人的视觉暂留这样就会出现数码管 0 的 LED0、数码管 1 的 LED1 以及数码管 2 的 LED2 “同时”亮,并不会有闪烁感。

由上面的分析可以得出如下图的输入输出框图,其接口列表如下表所示:
FPGA 驱动数码管动态显示(Verilog&Vivado)
原理图:
FPGA 驱动数码管动态显示(Verilog&Vivado)

三、实现代码

module hex8(
    Clk,
    Reset_n,
    Disp_Data,
    SEL,
    SEG
);
    
    input Clk;
    input Reset_n;
    input [31:0]Disp_Data;
    output reg[7:0]SEL;
    output reg[7:0]SEG;//seg[0]-a,seg[1]-b...seg[7]-h
    
    reg clk_1k;
    reg [15:0]div_cnt;
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)
        div_cnt <= 0;
    else if(div_cnt >= 49999)
        div_cnt <= 0;
    else
        div_cnt <= div_cnt + 1'b1;
        
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)
        clk_1k <= 0;
    else if(div_cnt == 49999)
        clk_1k <= 1'b1;
    else
        clk_1k <= 0;
      
    reg [2:0]num_cnt;
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)
        num_cnt <= 0;
    else if(clk_1k)
        num_cnt <= num_cnt + 1'b1;
        
    always@(posedge Clk)
        case(num_cnt)
            0: SEL = 8'b00000001;
            1: SEL = 8'b00000010;
            2: SEL = 8'b00000100;
            3: SEL = 8'b00001000;
            4: SEL = 8'b00010000;
            5: SEL = 8'b00100000;
            6: SEL = 8'b01000000;
            7: SEL = 8'b10000000;
        endcase

    reg[3:0]disp_tmp;
    always@(posedge Clk)
        case(num_cnt)
            7: disp_tmp = Disp_Data[31:28];
            6: disp_tmp = Disp_Data[27:24];
            5: disp_tmp = Disp_Data[23:20];
            4: disp_tmp = Disp_Data[19:16];
            3: disp_tmp = Disp_Data[15:12];
            2: disp_tmp = Disp_Data[11:8];
            1: disp_tmp = Disp_Data[7:4];
            0: disp_tmp = Disp_Data[3:0];
        endcase   

     always@(posedge Clk)
        case(disp_tmp)
            0: SEG = 8'hc0;
            1: SEG = 8'hf9;
            2: SEG = 8'ha4;
            3: SEG = 8'hb0;
            4: SEG = 8'h99;
            5: SEG = 8'h92;
            6: SEG = 8'h82;
            7: SEG = 8'hf8;
            8: SEG = 8'h80;
            9: SEG = 8'h90;
            4'ha: SEG = 8'h88;
            4'hb: SEG = 8'h83;
            4'hc: SEG = 8'hc6;
            4'hd: SEG = 8'ha1;
            4'he: SEG = 8'h86;
            4'hf: SEG = 8'h8e;
        endcase   

endmodule

四、hex8_tb文件

`timescale 1ns / 1ps
module hex8_tb();

    reg Clk;
    reg Reset_n;
    reg [31:0]Disp_Data;
    wire [7:0]SEL;
    wire [7:0]SEG;
    
    hex8 hex8(
        Clk,
        Reset_n,
        Disp_Data,
        SEL,
        SEG
    );  
    
    initial Clk = 1;
    always#10 Clk = ~Clk;
    
    initial begin
        Reset_n = 0;
        Disp_Data = 32'h00000000;
        #201;
        Reset_n = 1;
        #2000;
        Disp_Data = 32'h12345678;
        #10000000;
        Disp_Data = 32'h9abcdef0;
        #10000000;
        $stop;
    end
    
endmodule

五、上板测试

由于我使用的ACX720开发板数码管输出没有八个管脚,acx720 电路设计用到了芯片 74HC595,该芯片的作用是移位寄存器,通过移位的方式,节省 FPGA 的管脚。FPGA 只需要输出 3 个管脚,即可达到发送数码管数据的目的,与传统段
选位选方式相比,大大节省了 IO 设计资源。74HC595 的具体使用方法和技术参数如下:在数据手册中可以看出,不同工作温度和工作电压下 74HC595 的芯片工作频率值不相同,分别如表 15.5 与 15.6 所示。由于在学习板中芯片采用 3.3V 供电,这样在设计其工作频率时,直接使用 50M晶振四分频后的时钟作为其工作时钟,使其在 3.3V 状态下工作于12.5M 频率。为了能够上板显示,与是按74HC595芯片的驱动来设计,将8位SEL,和8位SEG输入,变成三位输出。

1.74HC595时序图

FPGA 驱动数码管动态显示(Verilog&Vivado)
从上面的分析可得出所示的框图,其接口列表如上图。
FPGA 驱动数码管动态显示(Verilog&Vivado)
驱动输入输出端口功能描述:
FPGA 驱动数码管动态显示(Verilog&Vivado)

2. HC595_Driver设计

代码设计如下:

module HC595_Driver(
    Clk,
    Reset_n,
    Data,
    S_EN,
    SH_CP,
    ST_CP,
    DS
);
    
    input Clk;
    input Reset_n;
    input [15:0]Data;
    input S_EN;
    output reg SH_CP;
    output reg ST_CP;
    output reg DS;
    parameter CNT_MAX = 2;
    
    reg [15:0]r_data;
    always@(posedge Clk)
        if(S_EN)
            r_data <= Data;

    reg [7:0]divider_cnt;//·ÖƵ¼ÆÊýÆ÷
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)
        divider_cnt <= 0;
    else if(divider_cnt == CNT_MAX - 1'd1)
        divider_cnt <= 0;
    else
        divider_cnt <= divider_cnt + 1'b1;
    
    wire sck_plus;
    assign sck_plus = (divider_cnt == CNT_MAX - 1'd1);
    
    reg [5:0]SHCP_EDGE_CNT;
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)
        SHCP_EDGE_CNT <= 0;
    else if(sck_plus)begin
        if(SHCP_EDGE_CNT == 6'd32)
            SHCP_EDGE_CNT <= 0;
        else
            SHCP_EDGE_CNT <= SHCP_EDGE_CNT + 1'b1;
    end
        
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)begin
        SH_CP <= 0;
        ST_CP <= 0;
        DS <= 0;   
    end
    else begin
        case(SHCP_EDGE_CNT)
            0: begin SH_CP <= 0;ST_CP <= 1'd0;DS <= r_data[15];end
            1: SH_CP <= 1'd1;
            2: begin SH_CP <= 0;DS <= r_data[14];end
            3: SH_CP <= 1'd1;
            4: begin SH_CP <= 0;DS <= r_data[13];end   
            5: SH_CP <= 1'd1;
            6: begin SH_CP <= 0;DS <= r_data[12];end
            7: SH_CP <= 1'd1;
            8: begin SH_CP <= 0;DS <= r_data[11];end   
            9: SH_CP <= 1'd1;
            10: begin SH_CP <= 0;DS <= r_data[10];end
            11: SH_CP <= 1'd1;
            12: begin SH_CP <= 0;DS <= r_data[9];end  
            13: SH_CP <= 1'd1;
            14: begin SH_CP <= 0;DS <= r_data[8];end
            15: SH_CP <= 1'd1;
            16: begin SH_CP <= 0;DS <= r_data[7];end   
            17: SH_CP <= 1'd1;
            18: begin SH_CP <= 0;DS <= r_data[6];end
            19: SH_CP <= 1'd1;
            20: begin SH_CP <= 0;DS <= r_data[5];end   
            21: SH_CP <= 1'd1;
            22: begin SH_CP <= 0;DS <= r_data[4];end
            23: SH_CP <= 1'd1;
            24: begin SH_CP <= 0;DS <= r_data[3];end   
            25: SH_CP <= 1'd1;
            26: begin SH_CP <= 0;DS <= r_data[2];end
            27: SH_CP <= 1'd1;
            28: begin SH_CP <= 0;DS <= r_data[1];end
            29: SH_CP <= 1'd1;
            30: begin SH_CP <= 0;DS <= r_data[0];end
            31: SH_CP <= 1'd1;
            32: ST_CP <= 1'd1;
            default:
                begin
                    SH_CP <= 0;
                    ST_CP <= 0;
                    DS <= 0;   
                end
        endcase
    end

endmodule

3.HC595_Driver_tb文件

HC595_Driver_tb文件展示:

`timescale 1ns / 1ps

module HC595_Driver_tb;

    reg Clk;
    reg Reset_n;
    reg [15:0]Data;
    reg S_EN;
    wire SH_CP;
    wire ST_CP;
    wire DS;
    
    HC595_Driver HC595_Driver(
        Clk,
        Reset_n,
        Data,
        S_EN,
        SH_CP,
        ST_CP,
        DS
    );
    
    initial Clk = 1;
    always #10 Clk = ~Clk;
    
    initial begin
        Reset_n = 0;
        Data = 0;
        S_EN = 0;
        #201;
        Reset_n = 1;
        #500;
        Data = 16'h47a9;
        S_EN = 1;
        #20;
        S_EN = 0;
        #4000;
        
        Data = 16'h5832;
        S_EN = 1;
        #20;
        S_EN = 0;
        #4000;       
        $stop;    
    end
endmodule

4.上板代码展示

于是上板代码如下:

module top_test(
    Clk,
    Reset_n,
    SEL,
    SEG,
    SH_CP,
    ST_CP,
    DS
);
    
    input Clk;
    input Reset_n;

    output [7:0]SEL;
    output [7:0]SEG;//seg[0]-a,seg[1]-b...seg[7]-h
    
    output SH_CP;
    output ST_CP;
    output DS;
    
    wire [31:0]Disp_Data;
    
    hex8 hex8(
        Clk,
        Reset_n,
        Disp_Data,
        SEL,
        SEG
    ); 
    wire [15:0]Data;
    assign Data = {SEG,SEL};
    
    wire S_EN;
    assign S_EN = 1;
    
    HC595_Driver HC595_Driver(
        Clk,
        Reset_n,
        Data,
        S_EN,
        SH_CP,
        ST_CP,
        DS
    );
    
    assign Disp_Data = 32'h12345678;    
    
endmodule

【附件:】链接:https://pan.baidu.com/s/1bDwngTNKkZrw6Koj0mjNGw?pwd=sc5t
提取码:sc5t文章来源地址https://www.toymoban.com/news/detail-411256.html

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

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

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

相关文章

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

    学习说明此文档为本人的学习笔记,注重实践,关于理论部分会给出相应的学习链接。 学习视频:是根据野火FPGA视频教程——第二十二讲 https://www.bilibili.com/video/BV1nQ4y1Z7zN?p=3 “天下武功唯快不破”    “看到的不一定为真” 眼睛的视觉暂留:光信号传入大脑需要短暂时间,

    2023年04月08日
    浏览(39)
  • 数码管动态显示Verilog实现(参考小梅哥教程)(视觉暂留)

    一个数码管有八个引脚,控制八段二极管的亮灭,用以显示需要的数字。 当有N个数码管时,一个一个控制的话需要N x 8 个引脚,消耗资源较多。 因此可以利用动态显示的方案通过人眼的视觉暂留特性达到静态显示的效果(动态显示周期20ms),只需N+8个引脚。节省了大量资源

    2024年02月04日
    浏览(44)
  • FPGA基本实验之数码管的动态显示

            关于数码管的基本知识大家可以参考我上一篇文章数码管的静态显示,         使用 1ms 的刷新时间让六个数码管轮 流显示:第 1ms 点亮第一个数码管,第 2ms 点亮第二个数码管,以此类推依次点亮六个数 码管,6ms 一个轮回,也就是说每个数码管每 6ms 点亮

    2024年02月08日
    浏览(41)
  • 基于FPGA的四位数码管显示按键计数器设计(verilog编程)

    软件:Vivado 2022.2 硬件:BASYS 3 设计描述:通过开发板上的四个按键,按下一次记数加一,分别由四个数码管从左到右分别显示四个按键记数情况。 例: 1.初始值为0000,意为无记数 2.当按下第一个按键,记数加一,数码管显示1000 3.再次按下一第一个按键,记数加一,数码管显

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

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

    2024年02月11日
    浏览(55)
  • 【FPGA】Verilog:实现十六进制七段数码管显示 | 7-Segment Display

    写在前面: 本章主要内容为理解七点数码管显示的概念,并使用 Verilog 实现。生成输入信号后通过仿真确认各门的动作,通过 FPGA 检查在 Verilog 中实现的电路的操作。 七段数码管是利用多重输出功能的非常有用的元件。该元件用于字符化,如十进制、十六进制数等。适当配

    2024年02月02日
    浏览(49)
  • FPGA学习日志——74hc595驱动的数码管静态显示seg_595_static

    数码管是一种半导体发光器件,其基本单元是发光二极管。数码管按段数一般分为七段数码管和八段数码管,八段数码管比七段数码管多一个发光二极管(多一个小数点显示)。 八段数码管是一个八字型数码管,分为八段:a、b、c、d、e、f、g、dp,其中dp为小数点,每一段即

    2024年02月08日
    浏览(125)
  • verilog实现数码管静态显示

    六个数码管同时间隔0.5s显示0-f。要求:使用一个顶层模块,调用计时器模块和数码管静态显示模块。 本文介绍了数码管显示原理,数码管驱动方式等等,并通过代码实现了数码管静态显示

    2024年02月16日
    浏览(41)
  • Vivado 实现4个7位数码管显示数字

    目前只是实现了4位分别显示0~9的功能的7位数码管,后期有添加内容还会有删改。 就不用提数码管的原理了(像什么共阳极,共阴极之类的),我会把每一步都解析标注出来。 首先是实现4个数码管显示相同数字。 由于没有具体选择4个数码管的哪一个所以4个都会显示同样的

    2024年02月13日
    浏览(44)
  • 【FPGA】Verilog:组合逻辑电路应用 | 数码管 | 8421BCD编码 | 转换七段数码管段码

    前言: 本章内容主要是演示Vivado下利用Verilog语言进行电路设计、仿真、综合和下载 示例:数码管的使用 功能特性: 采用 Xilinx Artix-7 XC7A35T芯片  配置方式:USB-JTAG/SPI Flash 高达100MHz 的内部时钟速度  存储器:2Mbit SRAM   N25Q064A SPI Flash(样图旧款为N25Q032A) 通用IO:Switch :

    2024年02月03日
    浏览(49)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包