天天看点

【FPGA实验】数码管静态显示

开拓者FPGA开发板上有六个共阳极八段数码管,本实验将完成数码管静态显示。

功能描述

控制六位数码管以0.5秒的频率同时显示0-F 16个数字。

分频模块

开发板本身的时钟频率为50kHz,对应时钟周期为20ns,而本实验需要0.5s让数字变化一次,因此需要对时钟进行分频,使其0.5s输出一个脉冲信号flag。

module time_count(
    input           clk     ,   // 时钟信号
    input           rst_n   ,   // 复位信号

    output   reg    flag        // 一个时钟周期的脉冲信号
);

//parameter define
parameter  MAX_NUM = 25000_000; // 计数器最大计数值

//reg define
reg [24:0] cnt;                 // 时钟分频计数器

//*****************************************************
//**                    main code
//*****************************************************

//计数器对时钟计数,每计时到0.5s,输出一个时钟周期的脉冲信号
always @ (posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        flag <= 1'b0;
        cnt  <= 24'b0;
    end
    else if(cnt < MAX_NUM - 1'b1) begin
        cnt  <= cnt +1'b1;
        flag <= 1'b0;
    end
    else begin
        cnt  <= 24'b0;
        flag <= 1'b1;      

数码管静态显示模块

首先需清楚两个概念:

位选信号(sel)——控制哪个数码管显示

段选信号(seg_led)–控制数码管显示内容

数码管显示具体数值可参考真值表:

【FPGA实验】数码管静态显示

共阳极二极管,常理来说应当0才是点亮,而这里是相反的。

原因可以看下面的原理图,输入信号并不是给到二极管的负级,而是给到了三级管的基极,三极管在这里起到开关的作用,因此相反。

【FPGA实验】数码管静态显示

模块代码:

module seg_led_static (
    input               clk     ,   // 时钟信号
    input               rst_n   ,   // 复位信号(低有效)

    input               add_flag,   // 数码管变化的通知信号
    output  reg  [5:0]  sel     ,   // 数码管位选
    output  reg  [7:0]  seg_led     // 数码管段选
);

//reg define
reg [3:0] num;                      // 数码管显示的十六进制数

//*****************************************************
//**                    main code
//*****************************************************

//控制数码管位选信号(低电平有效),选中所有的数码管
always @ (posedge clk or negedge rst_n) begin
    if (!rst_n)
        sel <= 6'b111111;
    else
        sel <= 6'b000000;
end

//每次通知信号到达时,数码管显示的十六进制数值加1
always @ (posedge clk or negedge rst_n) begin
    if (!rst_n)
        num <= 4'h0;
    else if(add_flag) begin
        if (num < 4'hf)
            num <= num + 1'b1;
        else
            num <= 4'h0;
    end
    else
        num <= num;
end

//根据数码管显示的数值,控制段选信号
always @ (posedge clk or negedge rst_n) begin
    if (!rst_n)
        seg_led <= 8'b0;
    else begin
        case (num)
            4'h0 :    seg_led <= 8'b1100_0000;
            4'h1 :    seg_led <= 8'b1111_1001;
            4'h2 :    seg_led <= 8'b1010_0100;
            4'h3 :    seg_led <= 8'b1011_0000;
            4'h4 :    seg_led <= 8'b1001_1001;
            4'h5 :    seg_led <= 8'b1001_0010;
            4'h6 :    seg_led <= 8'b1000_0010;
            4'h7 :    seg_led <= 8'b1111_1000;
            4'h8 :    seg_led <= 8'b1000_0000;
            4'h9 :    seg_led <= 8'b1001_0000;
            4'ha :    seg_led <= 8'b1000_1000;
            4'hb :    seg_led <= 8'b1000_0011;
            4'hc :    seg_led <= 8'b1100_0110;
            4'hd :    seg_led <= 8'b1010_0001;
            4'he :    seg_led <= 8'b1000_0110;
            4'hf :    seg_led <= 8'b1000_1110;
            default : seg_led <= 8'b1100_0000;      

顶层模块

module seg_led_static_top (
    input               sys_clk  ,       // 系统时钟
    input               sys_rst_n,       // 系统复位信号(低有效)

    output    [5:0]     sel      ,       // 数码管位选
    output    [7:0]     seg_led          // 数码管段选

);

//parameter define
parameter  TIME_SHOW = 25'd25000_000;    // 数码管变化的时间间隔0.5s

//wire define
wire       add_flag;                     // 数码管变化的通知信号

//*****************************************************
//**                    main code
//*****************************************************

//每隔0.5s产生一个时钟周期的脉冲信号
time_count #(
    .MAX_NUM    (TIME_SHOW)
) u_time_count(
    .clk        (sys_clk  ),
    .rst_n      (sys_rst_n),
    
    .flag       (add_flag )
);

//每当脉冲信号到达时,使数码管显示的数值加1
seg_led_static u_seg_led_static (
    .clk        (sys_clk  ), 
    .rst_n      (sys_rst_n),

    .add_flag   (add_flag ), 
    .sel        (sel      ),
    .seg_led    (seg_led  )
);      

管脚分配