其他分享
首页 > 其他分享> > 74HC595驱动(并转串,fpga与时钟匹配,fpga与外部芯片的连接注意事项)

74HC595驱动(并转串,fpga与时钟匹配,fpga与外部芯片的连接注意事项)

作者:互联网

上一次设计的动态扫描数码管显示电路模型如上,这是一个32位并行数据[31:0]disp_num选通输出并行数据[7:0]select和[7:0]段选的电路。因此需要输出16个信号

而在开发板上的电路与这个的接口不同,如下:

这个开发板设计的fpga只有有三个输出,接到2片级联的74HC595芯片上,并行输出段选和位选数据。

这三个输出分别为:DIO(串行数据),SCLK(与74HC595匹配的时钟信号),RCLK(锁存器使能信号)

因此,想要在这片开发板上控制数码管显示,就得修改代码。

在上一次代码的基础上,把输出的16位并行数据转化为串行数据从DIO端口输出。(并行数据转串行数据:逐个输出即可)。

由于74HC595时钟信号频率与fpga芯片的时钟信号频率不相等,fpga芯片的时钟频率为50MHz,而74HC595时钟频率在不同的驱动电压下不同,在3.3VS可以达到6~30MHz,为了方便,我们可以根据fpga50MHz的时钟产生一个12.5MHz的信号作为74HC595的SCLK信号输入 。

为了数据传输的稳定,在传输串行数据时,我们可以在SCLK的低电平时刻从fpga中输出一个数据,在SCLK上升沿到来时输入到74HC595,这样子防止亚稳态的产生。

 

 

 

每16个数据传输完成后,再让锁存器使能信号有效,这样子一次性把16个数据从两片移位寄存器中传到锁存器中,输出给数码管。

对于74HC595芯片,其设计就是一个移位寄存器(实现串行数据转换为并行数据),如图所示:

16个输出Q并行输出。

module drive_digital_tube(
    clk,
    reset,
    data,
    s_en,
    DIO,
    sclk,
    rclk,
    s_done
    );
    input clk;//50MHz
    input reset;
    input [15:0]data;
    input  s_en;
    output reg DIO;
    output reg sclk;
    output reg rclk;
    output reg s_done;
    
    reg [1:0]div_cnt;// 分频计数器,频率为25MHz
    always@( posedge clk or negedge reset)
    begin
        if (!reset)
            div_cnt <= 2'd0 ;
        else if(div_cnt == 1)
            div_cnt <= 2'd0 ;
        else
            div_cnt <= div_cnt + 1'd1 ; 
    end
    
    wire pulse25M; //频率为25MHz的取样脉冲
    assign pulse25M = ( div_cnt == 2'd1 ) ? 1 : 0 ;
    
    reg [5:0]cnt;//计数33个状态
    always@(posedge clk or negedge reset)
    begin
        if(!reset)
            cnt <= 6'd0 ;
        else if (s_en)
        begin
            if (pulse25M)
                begin
                    if(cnt == 6'd33)
                        cnt <= 6'd0 ; 
                    else 
                        cnt <= cnt + 1 ;
                end
        end
        else
            cnt <= 6'd0 ;
    end
    
    always@(posedge clk or negedge reset)
    begin
        if(!reset)
        begin
            DIO <= 0 ;
            sclk <= 0 ;
            rclk <= 0 ;
            s_done = 0 ;
        end
        else if(s_en)           
        begin
                if (pulse25M)
                case(cnt)//sclk为12.5MHz信号,rclk为输出使能(所有数据取完后),在sclk的低电平时取值,可以稳定,在sclk上升沿到来时可稳定输出
                    0:begin DIO <= 0 ;sclk <= 0 ;rclk <= 0 ;s_done = 0 ;end
                    1: sclk <= 1 ;
                    2:begin DIO <=data[15] ;sclk <= 0 ; end
                    3:sclk <= 1 ;
                    4:begin DIO <=data[14] ;sclk <= 0 ; end
                    5:sclk <= 1 ;
                    6:begin DIO <=data[13] ;sclk <= 0 ; end
                    7:sclk <= 1 ;
                    8:begin DIO <=data[12] ;sclk <= 0 ; end
                    9:sclk <= 1 ;
                    10:begin DIO <=data[11] ;sclk <= 0 ; end
                    11:sclk <= 1 ;
                    12:begin DIO <=data[10] ;sclk <= 0 ; end
                    13:sclk <= 1 ;
                    14:begin DIO <=data[9] ;sclk <= 0 ; end
                    15:sclk <= 1 ;
                    16:begin DIO <=data[8] ;sclk <= 0 ; end
                    17:sclk <= 1 ;
                    18:begin DIO <=data[7] ;sclk <= 0 ; end
                    19:sclk <= 1 ;
                    20:begin DIO <=data[6] ;sclk <= 0 ; end
                    21:sclk <= 1 ;
                    22:begin DIO <=data[5] ;sclk <= 0 ; end
                    23:sclk <= 1 ;
                    24:begin DIO <=data[4] ;sclk <= 0 ; end
                    25:sclk <= 1 ;
                    26:begin DIO <=data[3] ;sclk <= 0 ; end
                    27:sclk <= 1 ;
                    28:begin DIO <=data[2] ;sclk <= 0 ; end
                    29:sclk <= 1 ;
                    30:begin DIO <=data[1] ;sclk <= 0 ; end
                    31:sclk <= 1 ;
                    32:begin DIO <=data[0] ;sclk <= 0 ; rclk <= 1 ;end
                    33:begin sclk <= 1 ; rclk <= 0 ;s_done = 1 ;end
                    default ;           
                endcase
        end
        else
        begin
            DIO <= 0 ;
            sclk <= 0 ;
            rclk <= 0 ;
            s_done = 0 ;
        end
    end    
    
end
module
`timescale 1ns / 1ns
module drive_digital_tube_tb(
    );
    
    reg clk ;
    reg reset;
    reg s_en;
    reg [15:0]data;
    wire DIO;
    wire sclk;
    wire rclk;
    wire s_done ;
    
    drive_digital_tube drive_digital_tube_sim(
    clk,
    reset,
    data,
    s_en,
    DIO,
    sclk,
    rclk,
    s_done
    );
    
    initial clk = 1;
    always #10 clk = ! clk ;
    initial
    begin
        reset = 0 ;
        data = 0 ;
        s_en = 0 ;
        #201;
        reset = 1 ;
        s_en = 1 ;
        data = 16'ha55a;
        @(negedge s_done);
        s_en = 0;
        #200;
        s_en = 1;
        data = 16'h7597;
         @(negedge s_done);
        s_en = 0;
        #200;
        s_en = 1;
        data = 16'h6425;
         @(negedge s_done);
        
        $stop ;
    end
    
endmodule

 

 注意:

①有的内部变量由于没有真正用上,在仿真时波形为X,会使结果错误。检查alyays里面有没有 posedge reset,没有的话可能会出现这种情况。

②对于输入的数据,最好拿一个寄存器把当下的值存下来(添加一个控制信号),再慢慢输出,不然可能会造成输入数据不稳定,传输结果错误。

③fpga与外部芯片连接的场景:大部分情况下需要fpga产生一个时钟信号来驱动外部芯片,因此,对于fpga既要提高数据又要提高时钟的情况,我们可以在自己提供的时钟的低电平时刻输出数据,这样子可以保证外部芯片输入数据的稳定,在时钟上升沿到来时已经稳定,不会产生亚稳态。

标签:reset,输出,74HC595,en,fpga,转串,reg,时钟
来源: https://www.cnblogs.com/fbur/p/16388257.html