01_FPGA之点亮四位数码管

FPGA之点亮四位数码管

​ 距离比赛开始还有五天,这五天从入门到精通赛灵思的FPGA,请跟我一起加油。本学习笔记使用正点原子的达芬奇PROT35开发板,板载型号为xc7a35tfgg484-2,在Vivado中选型时注意选择正确的型号。

一.新建工程

  1. 双击打开Vivado

请添加图片描述

​ 2.新建工程

请添加图片描述

请添加图片描述

请添加图片描述

请添加图片描述

请添加图片描述

请添加图片描述

创建文件,名称跟着工程名一致即可
请添加图片描述

创建模块名

请添加图片描述

如此,一个模块创建好了

请添加图片描述

二.阅读原理图

​ 前面的步骤主要用来熟悉软件操作,下一步阅读原理图,分析数码管的驱动方式。分模块进行设计,最后实现一个四位数码管的显示计数的功能。

​ 根据扩展板原理图可知,四位数码管的位选信号是由一个74LS138芯片,及38译码器组成,位码0,1,2,3分别对应数码管K1,K2,K3,K4。通过译码器按时序依次给K1,K2,K3,K4供电。通过位选信号对数码管的位置进行刷新选择显示,通过段选信号对单个数码管显示具体数字或者字母。

请添加图片描述

​ 该数码管是共阴极数码管,共阴数码管是数码管所有的负极连接在一起,这个端口被称之为位选端口 ;

其余的数码管引脚a-h都为段选端口 。

请添加图片描述

下图所示真值表。

段选信号(八进制)显示值dpgfedcba
3F000111111
06100001011
5B201011011
4F301001111
66401101101
6D501101101
7D601111101
07700000111
7F801111111
6F901101111
77A01100110
7CB01111111
39C00111001
5ED01011110
79E01111001
71F01110001
76H01110110
38L00111000
37n00110111
3Eu00111110
73P01110011
5Co01011100
40-04000000
00熄灭00000000

模块一.数码管驱动模块

​ 数码管驱动模块输入信号有sys_clk,sys_rst_n,num,分别对应系统时钟,系统复位信号,输入数字。输出信号为dis_sel,dis_seg,dis_dp,分别对应数码管位选信号,数码管段选信号,小数点信号。

请添加图片描述

`timescale 1ns / 1ps

module Nixie(
    input sys_clk,//定义系统时钟
    input sys_rst_n,//定义复位信号
    input [15:0] num,//定义输入信号的数字
    output reg [2:0] dis_sel,//定义数码管位选信号
    output reg [6:0] dis_seg,//定义数码管段选信号
    output dis_dp//定义数码管小数点的信号
    );
    
    reg [31:0] cnt_1ms; //定义1ms计数器位宽
    reg [15:0] split_num; //定义显示数字位宽
    reg [2:0]  dis_num; //定义位选信号位宽

    wire [3:0] num_r1; //定义第一位显示的数字
    wire [3:0] num_r2; //定义第二位显示的数字
    wire [3:0] num_r3; //定义第三位显示的数字
    wire [3:0] num_r4; //定义第四位显示的数字

    parameter num0 = 8'h3f; //显示"0"
    parameter num1 = 8'h06; //显示"1"
    parameter num2 = 8'h5b; //显示"2"
    parameter num3 = 8'h4f; //显示"3"
    parameter num4 = 8'h66; //显示"4"
    parameter num5 = 8'h6d; //显示"5"
    parameter num6 = 8'h7d; //显示"6"
    parameter num7 = 8'h07; //显示"7"
    parameter num8 = 8'h7f; //显示"8"
    parameter num9 = 8'h6f; //显示"9"
    parameter numA = 8'h77; //显示"a"
    parameter numB = 8'h7c; //显示"b"
    parameter numC = 8'h39; //显示"c"
    parameter numD = 8'h5e; //显示"d"
    parameter numE = 8'h79; //显示"e"
    parameter numF = 8'h71; //显示"f"

    //时序逻辑,设置1ms定时器
    always @(posedge sys_clk or negedge sys_rst_n)begin
        if(!sys_rst_n)//复位初始化
            cnt_1ms <= 2'b0;
        else if(cnt_1ms == 49_999)//计数到清零
            cnt_1ms <= 2'b0;
        else
            cnt_1ms <= cnt_1ms+2'b1;//自增
    end

    //每1ms扫描一位数码管
    always @(posedge sys_clk or negedge sys_rst_n)begin
        if(!sys_rst_n)begin//复位初始化
            dis_sel <= 1'b0;
            end
        else  if(cnt_1ms == 49_999)begin//1ms定时到,扫描下一位,依次0,1,2,3四位数码管
            dis_sel <= dis_sel + 1'b1;
            if(dis_sel == 3)//位选计数到3时清零
                dis_sel <= 1'b0;
            end
        else
            dis_sel <= dis_sel;//复位保持
    end
	
    //将数字信号取位
    assign dis_dp = 1'b0;//小数点置零
    assign num_r1 = num % 10;			//个位
    assign num_r2 = num / 10 % 10;		//十位
    assign num_r3 = num / 100 % 10;		//百位
    assign num_r4 = num / 1000 % 10;	//千位
    
	//简易BCD码转换
    always @(posedge sys_clk or negedge sys_rst_n)begin
        if(!sys_rst_n)//复位清零
            split_num <= 16'haaaa;
        else if(num_r4)//千位数
           split_num <= {num_r4,num_r3,num_r2,num_r1};
        else if(num_r3)begin//百位数
            split_num[11:0] <= {num_r3,num_r2,num_r1};
            split_num[15:12] <= 4'ha;
        end
        else if(num_r2)begin//十位数
            split_num[7:0] <= {num_r2,num_r1};
            split_num[15:8] <= 8'haa;
        end
        else if(num_r1)begin//个位数
            split_num[3:0] <= num_r1;
            split_num[15:4] <= 12'haaa;
        end   
    end
    //位选
    always @(posedge sys_clk or negedge sys_rst_n)begin
        if(!sys_rst_n)//复位清零
            dis_num <= 0;
        else
            case(dis_sel)//位选显示对应数字
                0: dis_num <= split_num[3:0];
                1: dis_num <= split_num[7:4];
                2: dis_num <= split_num[11:8];
                3: dis_num <= split_num[15:12];
                default:dis_num <= 0;
            endcase
    end
    
    //段选
    always @(posedge sys_clk or negedge sys_rst_n)begin
        if(!sys_rst_n)//复位置一
            dis_seg <= 7'b111_1111;
        else
            case(dis_num)//将十进制数转化成对应的段码
                4'h0 : dis_seg <= num0;
                4'h1 : dis_seg <= num1;
                4'h2 : dis_seg <= num2;
                4'h3 : dis_seg <= num3;
                4'h4 : dis_seg <= num4;
                4'h5 : dis_seg <= num5;
                4'h6 : dis_seg <= num6;
                4'h7 : dis_seg <= num7;
                4'h8 : dis_seg <= num8;
                4'h9 : dis_seg <= num9;
                default:dis_seg <= 7'b000_0000;//无对应的数字不显示
            endcase
    end

  
endmodule

模块二.计数器

​ 计数器模块分别设置了一个10Hz的分频信号和一个0~9999的计数器,作为数字信号输出给数码管模块

请添加图片描述

`timescale 1ns / 1ps

module Get_data(
    input sys_clk,//时钟引脚定义
    input sys_rst_n,//系统复位引脚定义
    output reg [15:0] data//输出数字信号
    );
    
reg [31:0] cnt_100ms;
//5MHz->10Hz 
always @ (posedge sys_clk or negedge sys_rst_n)begin
    if(!sys_rst_n)
        cnt_100ms <= 0;
    else if(cnt_100ms == (5000_000 - 1))
        cnt_100ms <= 0;
    else
        cnt_100ms = cnt_100ms + 1;
end
//1234->9999
always @ (posedge sys_clk or negedge sys_rst_n)begin
    if(!sys_rst_n)//复位给初始值1234
        data <= 1234;
    else if(cnt_100ms == (5_000_000 - 1))begin//100ms定时到,计数加一
        if(data == 9999)//清零
            data <= 0;
        else
            data = data + 1;
    end
end

endmodule


顶层模块设计

​ 顶层模块调用两个模块,将两个模块结合到一起,实现模块化设计。

请添加图片描述

`timescale 1ns / 1ps
//输入输出引脚定义
module Nixie_top(
    input sys_clk,
    input sys_rst_n,
    output [2:0] dis_sel,
    output [6:0] dis_seg,
    output dis_dp
    );
    
    wire [15:0] data;//数据位
    //例化数码管模块
    Nixie u_Nixie(
        .sys_clk (sys_clk),
        .sys_rst_n (sys_rst_n),
        .num    (data),
        .dis_sel (dis_sel),
        .dis_seg (dis_seg),
        .dis_dp  (dis_dp)
    );
	//例化计数器模块
    Get_data u_Get_data(
        .sys_clk (sys_clk),
        .sys_rst_n (sys_rst_n),
        .data    (data)
    );
     
    
endmodule

仿真文件编写

​ 程序文件编写完成后,编写访问文件。

`timescale 1ns / 1ps


module tb_Nixie(
    );
    //在模块外实例化引脚
  	reg sys_clk;//输入用reg
	reg sys_rst_n;
    wire [15:0] num;//输出用wire
	wire [2:0] dis_sel;
	wire [6:0] dis_seg;
	wire dis_dp;
	//初始化激励信号
    initial begin
    sys_clk = 1'b1;
    sys_rst_n <= 1'b0;
    #201 sys_rst_n <= 1'b1;
    end

always #10 sys_clk <= ~sys_clk;//模拟时钟
//例化接口
Nixie u_Nixie(
    .sys_clk (sys_clk),
    .sys_rst_n (sys_rst_n),
    .num (num),
    .dis_sel (dis_sel),
    .dis_seg (dis_seg),
    .dis_dp (dis_dp)
);

Get_data u_Get_data(
    .sys_clk (sys_clk),
    .sys_rst_n (sys_rst_n),
    .data    (num)
);

endmodule

仿真波形,由仿真波形可看出位码和段码都正确

请添加图片描述

仿真波形,由仿真波形可看出位码和段码都正确

引脚配置

请添加图片描述

在配置引脚的时候,犯了个小错误导致数码管不能正常显示。注意引脚配置,扩展板和主板要共地。

参考博客:https://blog.csdn.net/wuzhikaidetb/article/details/121586283

  • 17
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
下面是使用Vivado 2018.3软件和Verilog HDL语言实现Basys3四位数码管动态显示的一个简单例子。 首先,在Vivado中创建一个新项目,添加Basys3开发板作为目标板卡,并设置好约束文件。 然后,我们需要创建一个Verilog模块,用于控制四位数码管的动态显示。以下是一个示例代码: ```verilog module digit_display( input clk, // 时钟信号 input [3:0] data_in, // 输入数据,4位二进制数值 output reg [6:0] anodes, // 数码管阳极输出 output reg [6:0] segments // 数码管阴极输出 ); reg [25:0] counter; // 计数器,用于控制数码管动态显示 reg [3:0] digit; // 当前显示的数码管编号 // 数码管显示控制 always @(posedge clk) begin counter <= counter + 1; if(counter == 250000) begin // 50Hz 的刷新频率 counter <= 0; digit <= digit + 1; if(digit == 4) begin digit <= 0; end end end // 数码管数据输出 always @(posedge clk) begin case(digit) 0: begin anodes <= 7'b1111110; segments <= { data_in[0] ? 7'b0000001 : 7'b1111110, data_in[1] ? 7'b0000001 : 7'b1111110, data_in[2] ? 7'b0000001 : 7'b1111110, data_in[3] ? 7'b0000001 : 7'b1111110 }; end 1: begin anodes <= 7'b1100111; segments <= { data_in[0] ? 7'b0000001 : 7'b1111110, data_in[1] ? 7'b0000001 : 7'b1111110, data_in[2] ? 7'b0000001 : 7'b1111110, data_in[3] ? 7'b0000001 : 7'b1111110 }; end 2: begin anodes <= 7'b1001111; segments <= { data_in[0] ? 7'b0000001 : 7'b1111110, data_in[1] ? 7'b0000001 : 7'b1111110, data_in[2] ? 7'b0000001 : 7'b1111110, data_in[3] ? 7'b0000001 : 7'b1111110 }; end 3: begin anodes <= 7'b1110011; segments <= { data_in[0] ? 7'b0000001 : 7'b1111110, data_in[1] ? 7'b0000001 : 7'b1111110, data_in[2] ? 7'b0000001 : 7'b1111110, data_in[3] ? 7'b0000001 : 7'b1111110 }; end endcase end endmodule ``` 在这个模块中,我们使用计数器和一个 `digit` 变量来控制四位数码管的动态显示。每个数码管的数据由输入的 4 位二进制数值决定,通过 `case` 语句来选择要显示的数码管。在每个时钟上升沿时,根据 `digit` 的值输出相应的阳极和阴极信号。 最后,将这个Verilog模块添加到Vivado项目中,并生成比特流文件,烧录到Basys3开发板上即可实现四位数码管的动态显示。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值