FPGA_数码管显示(74HC595芯片)

本文介绍了如何通过FPGA的管脚优化,利用74HC595串行移位寄存器将16位数码管的输出信号并转串,仅需3个管脚,详细解释了Verilog代码实现和时序逻辑设计,以及如何与数码管驱动结合使用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

根据上一篇博客描述,数码管驱动在实际应用此输出占用的管脚过多,所以为了节省FPGA的管脚,需要将输出信号并转串后(FPGA只需要输出3个管脚),再利用串转并芯片(比如74HC595)连接数码管去显示需要输出的字符。如下功能示意图:

从上图可以看到FPGA管脚从16个节省到3个。

74HC595芯片是一个8位串行移位寄存器,下图是一个4位的串行移位寄存器。

每个时钟周期Q端口的值都会发生变化

LATCH时钟不出现上升沿,OUTPUT端口数据就不发生变化

那么8位串行移位寄存器如下:

上图可以用Verilog实现,那么就可以制作成对应的芯片(74HC595)如下(芯片手册内容):

如果需要16位的移位寄存器呢:

只需要将前一芯片的输出QH-连接到下一芯片的D1就实现了16位移位寄存器

下图是电路图:

那么我们的任务就是:如何将上一篇博客的SEL输出和SEG输出两个8位共16位的值通过DIO,RCLK,SCLK传到2片级联的74HC595。

实现一个驱动逻辑,通过这3根信号线能正确的给74HC595位数据。

即需要在FPGA中实现一下逻辑功能,如下图:

并串转换逻辑。

下图是芯片输入输出时序图:

时序逻辑

代码编写:

先看一下期望实现波形图:

代码如下:

module HC595_driver(
    Clk,
    Reset_n,
    SEG,
    SEL,
    DIO,
    SRCLK,
    RCLK
    );
    input Clk;
    input Reset_n;
    input [7:0]SEG;
    input [7:0]SEL;
    output reg DIO;
    output reg SRCLK;
    output reg RCLK;
    parameter CLOCK_FREQ = 50_000_000;
    parameter SRCLK_FREQ = 12_500_000;
    parameter MCNT = CLOCK_FREQ/(SRCLK_FREQ * 2) -1;
   //SRCLK 2V时5MHZ 5V是25MHZ   那么3.3V时就大致取12.5MHZ  40ns
   //主频假设最高1GHZ 最低1hz   [29:0]div_count  编译器会根据实际使用确定实际尾位宽
   reg [29:0]div_count;
   reg [4:0]cnt;
   always@(posedge Clk or negedge Reset_n)
   if(!Reset_n)
        div_count <= 0;
   else if (div_count == MCNT)
        div_count <= 0;
   else
        div_count <= div_count +1'd1;
    
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)
        cnt <= 0;
    else if (div_count == MCNT)
        cnt <= cnt + 1'd1;
    
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)begin
        DIO = 1'd0; SRCLK <= 1'd0; RCLK <= 1'd0;
    end
    else begin
        case(cnt)
            0:begin DIO = SEG[7]; SRCLK <= 1'd0; RCLK <= 1'd1;end
            1:begin SRCLK <= 1'd1; RCLK <= 1'd0; end
            2:begin DIO = SEG[6]; SRCLK <= 1'd0; end
            3:begin SRCLK <= 1'd1; end
            4:begin DIO = SEG[5]; SRCLK <= 1'd0; end
            5:begin SRCLK <= 1'd1; end
            6:begin DIO = SEG[4]; SRCLK <= 1'd0; end
            7:begin SRCLK <= 1'd1; end
            8:begin DIO = SEG[3]; SRCLK <= 1'd0; end
            9:begin SRCLK <= 1'd1; end
            10:begin DIO = SEG[2]; SRCLK <= 1'd0; end
            11:begin SRCLK <= 1'd1; end
            12:begin DIO = SEG[1]; SRCLK <= 1'd0; end
            13:begin SRCLK <= 1'd1; end
            14:begin DIO = SEG[0]; SRCLK <= 1'd0; end
            15:begin SRCLK <= 1'd1; end
            16:begin DIO = SEL[7]; SRCLK <= 1'd0; end
            17:begin SRCLK <= 1'd1; end
            18:begin DIO = SEL[6]; SRCLK <= 1'd0; end
            19:begin SRCLK <= 1'd1; end
            20:begin DIO = SEL[5]; SRCLK <= 1'd0; end
            21:begin SRCLK <= 1'd1; end
            22:begin DIO = SEL[4]; SRCLK <= 1'd0; end
            23:begin SRCLK <= 1'd1; end
            24:begin DIO = SEL[3]; SRCLK <= 1'd0; end
            25:begin SRCLK <= 1'd1; end
            26:begin DIO = SEL[2]; SRCLK <= 1'd0; end
            27:begin SRCLK <= 1'd1; end
            28:begin DIO = SEL[1]; SRCLK <= 1'd0; end
            29:begin SRCLK <= 1'd1; end
            30:begin DIO = SEL[0]; SRCLK <= 1'd0; end
            31:begin SRCLK <= 1'd1; end
        endcase
    end
    
endmodule

编写testbench测试代码:

`timescale 1ns / 1ps
module HC595_driver_tb();
    reg Clk;
    reg Reset_n;
    reg [7:0]SEG;
    reg [7:0]SEL;
    wire DIO;
    wire SRCLK;
    wire RCLK;  
    HC595_driver HC595_driver1(
        .Clk(Clk),
        .Reset_n(Reset_n),
        .SEG(SEG),
        .SEL(SEL),
        .DIO(DIO),
        .SRCLK(SRCLK),
        .RCLK(RCLK)
        );
    initial Clk = 1;
    always #10 Clk = ~Clk;
    
    initial begin
        Reset_n = 0;
        SEL = 8'b0000_0001;
        SEG = 8'b0101_0101;
        #201
        Reset_n = 1;
        #5000;
        SEL = 8'b0000_0010;
        SEG = 8'b1010_1010;
        #5000;
        SEL = 8'b1010_0101;
        SEG = 8'b0000_1101;
        #5000;
        $stop;
    end
endmodule

 波形图如下:

至此我们完成了74HC595芯片输入逻辑驱动设计

接下来我们将上一篇博客数码管驱动 与上面所写的74HC595芯片驱动连接起来;

因为数码管显示输入为32位数据,一般开发板无法提供这么多的引脚,所以使用2个拨码开关,设置4组数据作为测试;详情看代码:

module digitial_tube_hc595(
    Clk,
    Reset_n,
    SW,
    DIO,
    SRCLK,
    RCLK
    );
    input Clk;
    input Reset_n;
    input [1:0]SW;
    output  DIO;
    output  SRCLK;
    output  RCLK;
    wire [7:0]SEL;
    wire [7:0]SEG;
    reg[31:0]Disp_Data;
    
    digitial_tube_0 digitial_tube_0(
        .Clk(Clk),
        .Reset_n(Reset_n),
        .Disp_Data(Disp_Data),
        .SEL(SEL),
        .SEG(SEG)
        );
    
    HC595_driver HC595_driver1(
        .Clk(Clk),
        .Reset_n(Reset_n),
        .SEG(SEG),
        .SEL(SEL),
        .DIO(DIO),
        .SRCLK(SRCLK),
        .RCLK(RCLK)
        );
    always@(*)
        case(SW)
            0:Disp_Data <= 32'h01234567;
            1:Disp_Data <= 32'h89abcdef;
            2:Disp_Data <= 32'h02468ace;
            3:Disp_Data <= 32'h13579bdf;
        endcase
endmodule

至此,整个数码管驱动逻辑到此结束!

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值