当前位置:   article > 正文

使用74HC595驱动数码管动态显示实验

74hc595驱动数码管

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

串行移位寄存器原理详解

在这里插入图片描述
我们实现的是FPGA图片对应的部分。相当于写的是一个驱动,

电路逻辑示意图,不是详细的电路图。
74HC595,8位串行移位寄存器。

LATCH有上升沿的信号时,上面的REG0到3会将DFF0到3的信号存储起来,并输出到OUTPUT0到3对应的D0-D3的信号口上。

在这里插入图片描述
逻辑信号示意图。
表示了4位的移位寄存器。
需要4个时钟周期,移位4次。输出4位并行数据。

同理8位的移位寄存器。
需要8个时钟周期,移位8次。输出8位并行数据。
在这里插入图片描述
74HC595芯片的内容
在这里插入图片描述
QH’当成了移位的端口输出。
移位时钟SRCLK,锁定时钟RCLK。

在这里插入图片描述
两个并联的情况。
移位时钟SRCLK,锁定时钟RCLK。这样并联之后就可以实现16位的并行输出

只需要将这16位的信号分别接给8位8段数码管的ser(选择)接口和seg接口,就能任意控制某个数码管的某一段。
两个47HC595芯片可以实现,3个信号线传输16位信号的功能。

在这里插入图片描述数码管74HC595的电路。和上面的原理是一致的。
上面是一个级联,因为QH接到了SER那里。
第一个U11QA-QH接到了数码管的HEX_SEL0-7也就是位选信号端,后边U12QA-QH接到了数码管的HEX_A-DP也就是段选信号端。

输入的信号其实就是DIO 对应的SER,RCLK,SCLK对应的SRCLK。
最终的工作不是去实现74HC595本来的功能,而是去驱动数码管管。

一、需实现的模块

在这里插入图片描述
模块功能:
将两个8位的SEL[7:0],SEG[7:0],通过DIO(SER),SCLK,RCLK。输出给两片级联的74HC595芯片。
将两个8位的第一级接SEL和第二级接SEG恰好稳定,出现输出在两片47HC595芯片的QA-QH上。
在这里插入图片描述
对应的信号传输时序图。
在这里插入图片描述
对应的功能表
在这里插入图片描述
在写代码的时候对应的时序逻辑顺序十分重要。

二、模块实现

在verilog中的信号名称不能以数字作为开头。
在这里插入图片描述
DIO不能在SRCLK的高电平变化,有一段时间的延迟,如上面的时间延迟表。
RCLK的上升沿一定不会出现在SRCLK的上升沿的。

思路:用线性序列机的方式实现
最小时钟单位取SRCLK的一半。

移位的时候,先移动高位再移动低位。
上一轮的结束本身就意味着下一轮的开始,

线性序列机

就是根据时序图来写代码,根据不同的时间来进行具体的操作。其中不同的时间主要是依靠计数器来进行计时。
不同的时间对应不同的操作。

1.对应模块

代码如下(示例):

`timescale 1ns / 1ps

module HC595(
    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;   //期望的SRCLK的频率
    parameter MCNT = CLOCK_FREQ/(SRCLK_FREQ * 2) - 1;
    
    reg [29:0]div_cnt;
    
        
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)
        div_cnt <= 0;
    else if(div_cnt == MCNT)
        div_cnt <= 0;
    else
        div_cnt <= div_cnt +1'd1; 
        
    reg [4:0]cnt;
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)
        cnt <= 0;
    else if(div_cnt == 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

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85

2.读入数据

代码如下(示例):

`timescale 1ns / 1ps

module HC595_tb;
    reg Clk;
    reg Reset_n;
    reg SEG;
    reg SEL;
    wire DIO;
    wire SRCLK;
    wire RCLK;

    HC595 HC595_driver(
        .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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

在测试激励程序中最好能让你的输出两轮以上,这样子方便观察计数器的问题。只跑一轮是有可能出问题的。


3.仿真结果

在这里插入图片描述

在这里插入图片描述
这里往前推传的是低位数据而不是高位的数据,SEL对的方式是按照上升沿往前推。

在这里插入图片描述
从这里往前对的是SEG的值。SEL的第一位同时也是SEG的最后一位。

提问,74HC595是在上升沿寄存DIO的值,为什么DIO的值是在下降沿才去变化。
答:信号在上升沿被采样,那么就让他在下降沿去变化。这样的话,变化的时刻就比采样的时刻整整差了半个时钟周期,就能保证当芯片采样数据的时候,数据就早已经变化并且稳定了。

4.驱动显示

(1)文件添加

在这里插入图片描述
在对应的文件夹找到之前的hex8.v数码管模块的文件,并且手动拷贝到HC595的文件夹下。
在这里插入图片描述
点击添加或者创建设计文件
在这里插入图片描述
选择对应文件添加并finish。

`timescale 1ns / 1ps

module hex8_hc595_test(
    Clk,
    Reset_n,
    SW,
    DIO,
    SRCLK, 
    RCLK
    );
    input Clk;
    input [1:0]SW;
    input Reset_n;
    output DIO;
    output SRCLK;
    output RCLK;
    
    wire [7:0]SEG,SEL;
    
    reg [31:0]Disp_Data;
    //例化内容
    HC595 HC595_driver(
        .Clk(Clk),
        .Reset_n(Reset_n),
        .SEG(SEG),
        .SEL(SEL),
        .DIO(DIO),
        .SRCLK(SRCLK),
        .RCLK(RCLK)
    );
    
    hex8 hex8(
        .Clk(Clk),
        .Reset_n(Reset_n),
        .Disp_Data(Disp_Data),
        .SEL(SEL),
        .SEG(SEG)
    );
    
    
   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

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56

(1)实物效果

在这里插入图片描述
实现效果,对应的拨码开关控制对应的输出。

总结

通过Vivado软件对驱动74HC595芯片进行数码管动态显示做了仿真验证。

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号