集成电路技术分享

 找回密码
 我要注册

QQ登录

只需一步,快速开始

搜索
查看: 10856|回复: 21

FPGA初级课程第四讲 数码管

[复制链接]
lcytms 发表于 2016-11-2 20:59:34 | 显示全部楼层 |阅读模式
FPGA初级课程
第四讲 数码管

Hi,大家好!我是至芯科技的李老师。
今天讲课的题目是:数码管。
本节课我先简要地介绍一下数码管的物理原理,然后实际演示一下数码管驱动逻辑电路的建模与仿真,最后下板查看效果。



本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?我要注册

x
 楼主| lcytms 发表于 2016-11-2 21:03:06 | 显示全部楼层
首先打开ZX_1开发板电路图《ZX_NO1.pdf》文件,我们看一下六个七段数码管的电路图。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?我要注册

x
 楼主| lcytms 发表于 2016-11-2 21:08:12 | 显示全部楼层
然后,我们打开至芯科技编写的《17.炼狱传奇-数码管之战.pdf》文件。

这一节,我们来学习如何驱动数码管,数码管作为一种外设,首先我们需要了解它的工作原理以及它和外设电路的对应关系,七段数码管原理图如下图所示。

顾名思义,七段数码管就是使用七段点亮的线段来拼成常见的数字和某些字母,这种显示方式我们在数字电路中非常容易见到。
再加上右下角显示的小数点,实际上一个显示单元包括了8根信号线。
根据电路设计的不同,这些信号线可能高有效也可能低有效。
我们通过FPGA控制这些线段的亮灭,达到显示效果。

对于多个数码管的显示模块,将每一个都连接到FPGA的管脚会耗用大量FPGA的管脚资源。
因此我们同样引入一种类似矩阵键盘的扫描方式。
任何时刻我们只使用8根信号点亮一个数码管,但是8个数码管是随着时钟步调交替点亮的,只要时钟的速度够快,我们观察到数码管就好像几个同时点亮一样。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?我要注册

x
 楼主| lcytms 发表于 2016-11-2 21:11:23 | 显示全部楼层
再回到至芯ZX_1开发板原理图。

如图所示,我们的开发板使用的是六位共阳极数码管,六个PNP型三极管分别作为六组数码管电源的输入开关,也就是我们常说的位选信号,PNP三极管为低电平导通,所以我们的位选信号低有效。
在这里,为了节约FPGA的IO资源,我们把六个位选信号连接到了三八译码器74HC138D,该三八译码器的真值表如下:

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?我要注册

x
 楼主| lcytms 发表于 2016-11-2 21:16:33 | 显示全部楼层
由此,我们可以得出结论,当{SEL2, SEL1, SEL0}=3’b000时,Y0变为低电平,而由于Y0连接到了第一个数码管,所以第一个数码管点亮。
当{SEL2, SEL1, SEL0}=3’b001时,对应第二个数码管点亮,以此类推。
SEG_0到SEG_7分别对应二极管a-g以及“小数点”,即我们所说的段选信号。
由于是共阳极数码管,所以二极管只要给低电平就可以点亮,根据点亮的二极管不同,就可以显示出不同的字符。
假如我们要点亮第一个数码管,并且显示出字符“A”,那么我们就只需要选中第一个数码管{SEL2, SEL1, SEL0}=3’b000,而且SEG=8’b1000_1000。

如果要让数码管“全部亮起来”,并同时显示相同字符,那么我们只能通过比较快速地切换位选信号来实现这一目的。
但切换频率如果过高,数码管显示也会出现不稳定的状态,这和器件的工艺有关,我们可以选择切换的经验频率1kHz,那么这时,我们就需要用到分频模块,将50MHz的晶振时钟分频成我们所需要的1kHz。

 楼主| lcytms 发表于 2016-11-2 21:24:11 | 显示全部楼层
好了,既然思路和原理已经明了于心,那么接下来我们可以开始写驱动代码,验证思路是否可以实现。

分析开发板对应数码管原理图可知FPGA只需要输出位选和段选信号即可,而输入要求则是要显示的十六进制数。

新建一个工程文件夹。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?我要注册

x
 楼主| lcytms 发表于 2016-11-2 21:27:24 | 显示全部楼层
单个数码管显示

我们先进行单个数码管显示。
单个数码管显示从0到F的15个数字,对应的输入为4位。
我们新建工程文件夹seg7。
对单个数码管显示驱动电路进行建模。编写seg7.v模块。
module seg7 (clk, rst_n, data, sel, seg);

        input clk, rst_n;
        input [3:0] data;
       
        output reg [2:0] sel;
        output reg [7:0] seg;

        always @ (posedge clk or negedge rst_n)
                begin
                        if (!rst_n)
                                begin
                                        sel <= 3'b000;
                                end
                        else
                                begin
                                        sel <= 3'b000;
                                end
                end

        always @ (*)
                begin
                        if (!rst_n)
                                begin
                                        seg = 8'b1111_1111;
                                end
                        else
                                begin
                                        case (data)
                                        0        :        seg = 8'b1100_0000;                //d0
                                        1        :        seg =        8'b1111_1001;                //d1
                                        2        :        seg =        8'b1010_0100;                //d2
                                        3        :        seg = 8'b1011_0000;                //d3
                                        4        :        seg =        8'b1001_1001;                //d4
                                        5        :        seg = 8'b1001_0010;                //d5
                                        6        :        seg =        8'b1000_0010;                //d6
                                        7        :        seg = 8'b1111_1000;                //d7
                                        8        :        seg =        8'b1000_0000;                //d8
                                        9        :        seg = 8'b1001_0000;                //d9
                                        10        :        seg =        8'b1000_1000;                //dA
                                        11        :        seg = 8'b1000_0011;                //db
                                        12        :        seg =        8'b1100_0110;                //dC
                                        13        :        seg = 8'b1010_0001;                //dd
                                        14        :        seg =        8'b1000_0110;                //dE
                                        15        :        seg = 8'b1000_1110;                //dF
                                        default        :        seg = 8'b1111_1111;                //null
                                        endcase
                                end
                end

endmodule

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?我要注册

x
 楼主| lcytms 发表于 2016-11-2 21:30:36 | 显示全部楼层
然后编写仿真代码。
`timescale 1ns/1ps

module seg7_tb;

        reg clk, rst_n;
        reg [3:0] data;
       
        wire [2:0] sel;
        wire [7:0] seg;
       
        seg7  dut (.clk(clk), .rst_n(rst_n), .data(data), .sel(sel), .seg(seg));
       
        initial
                begin
                        clk = 1;
                        rst_n = 0;
                        data = 4'hA;
                        #200.1
                        rst_n = 1;
               
                        #1000 $stop;
                end
       
        always #10 clk = ~clk;

endmodule

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?我要注册

x
 楼主| lcytms 发表于 2016-11-2 21:33:06 | 显示全部楼层
观察仿真波形

在本模块中,只是测试了显示“A”,有兴趣的话,可以测试显示全部0~F。

观察仿真波形,在复位期间,seg信号为全“1”,数码管熄灭,在复位结束以后,seg信号变成了“10001000”,正好对应“A”,而sel信号一直是000,对应第一个数码管。
仿真波形完全符合设计要求。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?我要注册

x
 楼主| lcytms 发表于 2016-11-2 21:34:24 | 显示全部楼层
本帖最后由 lcytms 于 2016-11-2 21:55 编辑

6个数码管的显示

刚才我们演示了单个数码管显示驱动逻辑电路的建模与仿真,下面我们来进行6个数码管的显示。

一个数码管对应的data位宽为4位,六个数码管就需要24位,而且分时显示需要对六个数码管进行切换。因此我们需要修改原有的seg7.v模块。
同时由于数码管物理特性的限制,根据经验,我们设置它的时钟信号为1kHz,这需要对板载50MHz信号进行分频处理。

module seg7 (clk, rst_n, data, sel, seg);

        input clk, rst_n;
        input [23:0] data;
       
        output reg [2:0] sel;
        output reg [7:0] seg;
       
        reg clk_1k;
       
        parameter T1ms = 25_000; //half width
        reg [19:0] count;
       
        always @ (posedge clk or negedge rst_n)
                begin
                        if (!rst_n)
                                begin
                                        clk_1k <= 1;
                                        count <= 0;
                                end
                        else
                                begin
                                        if (count < T1ms - 1)
                                                begin
                                                        count <= count + 1;
                                                end
                                        else
                                                begin
                                                        count <= 0;
                                                        clk_1k <= ~clk_1k;
                                                end
                                end
                end

        reg [3:0] data_temp;
        reg [2:0] state;
               
        always @ (posedge clk_1k or negedge rst_n)
                begin
                        if (!rst_n)
                                begin
                                        sel <= 3'b000;
                                        data_temp <= 4'h0;
                                        state <= 0;
                                end
                        else
                                begin
                                        case (state)
                                        0        :        begin
                                                                sel <= 3'b000;
                                                                data_temp <= data[23:20];
                                                                state <= 1;
                                                        end
                                       
                                        1        :        begin
                                                                sel <= 3'b001;
                                                                data_temp <= data[19:16];
                                                                state <= 2;
                                                        end
                                       
                                        2        :        begin
                                                                sel <= 3'b010;
                                                                data_temp <= data[15:12];
                                                                state <= 3;
                                                        end
                                       
                                        3        :        begin
                                                                sel <= 3'b011;
                                                                data_temp <= data[11:8];
                                                                state <= 4;
                                                        end
                                       
                                        4        :        begin
                                                                sel <= 3'b100;
                                                                data_temp <= data[7:4];
                                                                state <= 5;
                                                        end
                                       
                                        5        :        begin
                                                                sel <= 3'b101;
                                                                data_temp <= data[3:0];
                                                                state <= 0;
                                                        end
                                       
                                        default        :        state <= 0;
                                       
                                        endcase
                                end
                end

        always @ (*)
                begin
                        if (!rst_n)
                                begin
                                        seg = 8'b1111_1111;
                                end
                        else
                                begin
                                        case (data_temp)
                                        0        :        seg = 8'b1100_0000;                //d0
                                        1        :        seg =        8'b1111_1001;                //d1
                                        2        :        seg =        8'b1010_0100;                //d2
                                        3        :        seg = 8'b1011_0000;                //d3
                                        4        :        seg =        8'b1001_1001;                //d4
                                        5        :        seg = 8'b1001_0010;                //d5
                                        6        :        seg =        8'b1000_0010;                //d6
                                        7        :        seg = 8'b1111_1000;                //d7
                                        8        :        seg =        8'b1000_0000;                //d8
                                        9        :        seg = 8'b1001_0000;                //d9
                                        10        :        seg =        8'b1000_1000;                //dA
                                        11        :        seg = 8'b1000_0011;                //db
                                        12        :        seg =        8'b1100_0110;                //dC
                                        13        :        seg = 8'b1010_0001;                //dd
                                        14        :        seg =        8'b1000_0110;                //dE
                                        15        :        seg = 8'b1000_1110;                //dF
                                        default        :        seg = 8'b1111_1111;                //null
                                        endcase
                                end
                end

endmodule

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?我要注册

x
您需要登录后才可以回帖 登录 | 我要注册

本版积分规则

关闭

站长推荐上一条 /1 下一条

QQ|小黑屋|手机版|Archiver|集成电路技术分享 ( 京ICP备20003123号-1 )

GMT+8, 2024-5-18 05:31 , Processed in 0.077659 second(s), 20 queries .

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表