实现8个数字显示在8个数码管上

功能描述

给8个数字,范围在[0,15]。要求把这8个数字显示到8个数码管上。
此处应该有上板运行的效果,但是,我没板子,所以XD们自行想象。
是不是想不出来?我去百度上截了一张图,放出来
在这里插入图片描述

知识准备

  • 数码管

在这里插入图片描述
这是8段数码管。后面我们只用到它的七段,也就是不包括h那个小数点。要让abcdefg亮某几段,以实现显示数字。
这是肯定有小伙伴问了,这只有一个数码管,10怎么显示呢?好问题,所以此时我们用16进制,来显示
图是盗的图是盗的
所以数字和数码管每段的对应表为:
图还是盗的

  • 多个数码管的显示

加入有3个数码管012,其中,sel0,sel1,sel2分别控制数码管0,1,2是否工作。右下角的abcdefgh对应八段数码管的8个段。假如此时要让数码管0显示0,那就让sel0为1,然后abcdefgh的值分别为00000011。
图还是盗的
现在有一个问题,看图,我们发现,这三个数码管是共用abcdefgh的。如果我现在要让数码管0显示0,数码管1显示1,数码管2显示2,那怎么做?
嘿嘿!是不是发现问题了?这三个数码管不能同时工作。怎么办呢?老板就是要让我实现它啊!注意,硬件的时钟很小,经常以纳秒为单位,我们可以借用操作系统的并发与并行来理解这个过程。宏观上我们看着三个数码管是同时显示的,微观上它们三是轮流给信号的。也就是:

  • 第1个ns:sel0=1,sel1=sel2=0 abcdegfh=[数码管0要显示的数字]
  • 第2个ns:sel1=1,sel0=sel3=0 abcdegfh=[数码管1要显示的数字]
  • 第3个ns:sel2=1,sel0=sel1=0 abcdegfh=[数码管2要显示的数字]

分析功能

现在我们要实现,8个数字显示在8个数码管上,先上图,再来解释。
图是盗的

  • disp_data是32位的数据,我们让disp_data[3:0]显示在第一个数码管上,disp_data[7:4]显示在第二个数码管上…
  • data_tmp[3:0]就是此时要显示的数据
  • divider是一个分频器,实际上它是一个计数器。Clk是20ns为一个周期,现在我们想要美20ms切换一个数码管显示,所以需要分频率,Clk_1K的频率就是1KHz
  • shift8是循环移位器。这个器件是给0000_0001实现循环左移的。移位的结果保存到sel_r[7:0]中
  • sel[7:0]:这是用来选择哪一个数码管亮,对应功能如下:
    在这里插入图片描述
  • mux2:二选一选择器。如果使能信号en为1的话,则选择某一个数码管亮,sel就是sel_r的值;如果en为0的话,则所有数码管都不亮,sel的值全是0
  • mux8:8选一选择器。按照sel的值,选择显示哪一个数
  • LUT:查找表。这就是来查找某个数字,对应到7段数码管上abcdefg各是什么值,LUT就相当于下面这张表:
    在这里插入图片描述

代码实现

OK,Talk is cheap. Show you the code.
大神的名言

`timescale 1ns / 1ps

module HXE8(clk,rst,en,disp_data,sel,seg);
    input clk;//50MHz
    input rst;
    input [31:0]disp_data;
    input en;

    output [7:0]sel;//选择8个数码管中的某一个
    output reg[6:0]seg;//七段数码管

    //制作分频器
    //分频器实际就是计数器。把原本周期为20ns的改成1ms。
    //所以频率从50MHz改成1kHz。所以是模50_000的计数器
    //但是,一个周期信号需要变化两次,所以计数到25_000就让信号变化
    //25_000需要15位二进制来表示,所以divider_cnt是15位
    reg [14:0]divider_cnt;
    reg clk_1k;
    always @(posedge clk or negedge rst) begin
        if(!rst)begin
            divider_cnt<=15'b0;
            clk_1k<=1'b0;
        end
        else if (!en) divider_cnt<=15'b0;
        else if(divider_cnt==24999)begin
             divider_cnt<=15'b0;
             clk_1k<=~clk_1k;
        end
        else divider_cnt<=divider_cnt+1'b1;
    end

    //循环移位器shift8
    reg [7:0]sel_r;
    always @(posedge clk_1k or negedge rst) begin
        if (!rst)sel_r<=8'b0000_0001;
        else if(sel_r==8'b1000_0000)
            sel_r<=8'b0000_0001;
        else sel_r<=sel_r<<1;
    end

    //mux8(组合逻辑)
    reg [3:0]data_tmp;//待显示数据缓存
    always @(*) begin
        case(sel_r)
            8'b0000_0001:data_tmp=disp_data[3:0];
            8'b0000_0010:data_tmp=disp_data[7:4];
            8'b0000_0100:data_tmp=disp_data[11:8];
            8'b0000_1000:data_tmp=disp_data[15:12];
            8'b0001_0000:data_tmp=disp_data[19:16];
            8'b0010_0000:data_tmp=disp_data[23:20];
            8'b0100_0000:data_tmp=disp_data[27:24];
            8'b1000_0000:data_tmp=disp_data[31:28];
            default:data_tmp=4'b0;
        endcase
    end

    //LUT(组合逻辑)
    //组合逻辑中,reg的赋值可以用= 时序逻辑的话,用<=
    always @(*) begin
        case(data_tmp)
            4'd0:seg=7'b100_0000;
            4'd1:seg=7'b111_1001;
            4'd2:seg=7'b010_0100;
            4'd3:seg=7'b011_0000;
            4'd4:seg=7'b001_1001;
            4'd5:seg=7'b001_0010;
            4'd6:seg=7'b000_0010;
            4'd7:seg=7'b111_1000;
            4'd8:seg=7'b000_0000;
            4'd9:seg=7'b001_0000;
            4'ha:seg=7'b000_1000;
            4'hb:seg=7'b000_0011;
            4'hc:seg=7'b100_0110;
            4'hd:seg=7'b010_0001;
            4'he:seg=7'b000_0110;
            4'hf:seg=7'b000_1110;
        endcase
    end
    //二选一多路器
    assign sel=(en)?sel_r:8'b0000_0000;


endmodule

仿真代码:

`timescale 1ns / 1ns
`define  clock_period 20


module HXE8_tb;
    reg clk,rst,en;
    reg [31:0]disp_data;
    wire [7:0]sel;
    wire [6:0]seg;
    HXE8 HXE80(
        .clk(clk),
        .rst(rst),
        .en(en),
        .disp_data(disp_data),
        .sel(sel),
        .seg(seg));

    //产生时钟
    initial clk=1;
    always #(`clock_period/2)clk=~clk;

    initial begin
        rst=1'b0;
        en=1;
        disp_data=32'h12345678;
        #(`clock_period*20);
        rst=1;
        #(`clock_period*20);
        #20000000;
        disp_data=32'h87654321;
        #20000000;
        disp_data=32'h89abcdef;
        #20000000;
        $stop;
    end

endmodule

仿真结果:
在这里插入图片描述
例如,在此刻,disp_data是12345679(16进制的),sel[7:0]为0000_1000,那么选中5这个数字,而5对应的7段数码管是001_0010,和我们的设计相符合!

结语

有点遗憾,没能上板,上板了的小伙伴可以发出来,让俺瞧瞧~
菜鸟一枚,如果有错,欢迎指出。

参考

【小梅哥FPGA设计思想与验证方法视频教程】https://www.bilibili.com/video/BV1KE411h7AZ?p=10&vd_source=a104a55bfae98f2c7faf58a3a2332bfe

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值