当前位置:   article > 正文

小梅哥Xilinx FPGA学习笔记14——基于74HC595动态扫描数码管显示_小梅哥fpga

小梅哥fpga

目录

一、 移位寄存器

二、 74HC595

2.1 概述

2.2 功能方框图

2.3 功能表

2.4 时序要求

2.5 74HC595驱动框图

三 、代码实现

3.1 数码管驱动代码(hex8文件)

3.2 74HC595驱动代码

3.3 74HC595仿真测试代码

3.4 74HC595仿真测试图

四、整体例化测试代码实现


一、 移位寄存器

四个D触发器,连接同一个Clk,每个时钟上升沿,数据向右移一位,如果想实现四个数据全移位结束后一起输出的话,则需要将输出Q连接4个D触发器输出,这四个D触发器的时钟LATCH时钟信号与之前的四个D触发器的时钟Clk上升沿不是同时出现,所以就可以实现串转并输出。

同理,如果想实现8位数据的传输,则需要8+8=16个D触发器进行实现串并转换

二、 74HC595

2.1 概述

74HC595 是用于 CMOS 应用的 HC 系列逻辑器件中的一部分。74HC595 器件包含对8位 D 类存储寄存器进行馈送的 8位串行输入/并行输出移位寄存器。
移位寄存器时钟(SRCLK)和存储寄存器时钟(RCLK) 均为正边沿触发。如果将两个时钟连接在一起,则移位寄存器始终比存储寄存器早一个时钟脉冲。

2.2 功能方框图

 ZYNQ702数码管只有三个管脚,其上集成移位寄存器——74HC595芯片(8个D触发器、8个输出锁存器实现8位数据串转并)。FPGA输出16位数据(16进制),2个HC595级联,16个时钟周期后实现串转并

      SRCLK:移位时钟信号SRCLK;DOI:输入信号DOI;RCLK:锁存时钟信号RCLK

      SRCLK高电平,信号进入D触发器Q端,RCLK高电平,信号进入相应锁存器Q端,此时Q0~Q7才有输出.

级联:DIO数据进入第一级芯片,8个时钟周期后,进入下一级芯片

2.3 功能表

从功能表中可以看出当移位时钟信号SRCLK上升沿到来时有效,即将数据存入D触发器中;对于锁存时钟信号RCLK来说,当其上升沿到来时,移位寄存器的值存入到存储寄存器之中。

2.4 时序要求

从下图中可以看出74HC595的时序要求为:1.当供电电压为2V时,其SRCLK时钟频率最大值为5MHZ,当供电电压为4.5V时,其SRCLK时钟频率最大值为25MHZ,本实验开发板供电电压为3.3V文中并没有提到3。3V,所以有两种办法:第一种是选取最低的5MHZ肯定是没有问题的;第二种方法是用中间值12.5MHZ进行实现。综合起来看第二种方法更好一点。2.RCLK高脉冲时间至少要为SRCLK高脉冲时间的一半。3. 2V时SRCLK上升沿到来之前的125ns,DIO数据线数值不可以变化。4. 2V时SRCLK上升沿比RCLK上升沿先到来至少94ns

2.5 74HC595驱动框图

首先输入16位的数值,其中8位SEL信号,8位SEG信号,然后输出三条线作为驱动74HC595的输入线。

三 、代码实现

实现逻辑仿真框图如下:图中可见最小时间单元为40ns。

3.1 数码管驱动代码(hex8文件)

上一章节写过的代码

  1. module hex8(
  2. input Clk,
  3. input Reset_n,
  4. input [31:0]Disp_Data,
  5. output reg [7:0]SEL,
  6. output reg [7:0]SEG
  7. );
  8. reg [29:0]cnt_1ms;
  9. reg Flag_1ms; //1毫秒切换一个数码管
  10. reg [2:0]cnt_sel;//位选信号
  11. parameter MCNT = 50000-1;
  12. //定时一毫秒
  13. always@(posedge Clk or negedge Reset_n)
  14. if(!Reset_n)
  15. cnt_1ms <= 0;
  16. else if(cnt_1ms == MCNT)
  17. cnt_1ms <= 0;
  18. else
  19. cnt_1ms <= cnt_1ms + 1;
  20. //产生一个一毫秒到来的高脉冲信号
  21. always@(posedge Clk or negedge Reset_n)
  22. if(!Reset_n)
  23. Flag_1ms <= 0;
  24. else if(cnt_1ms == MCNT)
  25. Flag_1ms <= 1;
  26. else
  27. Flag_1ms <= 0;
  28. //cnt_sel自加逻辑实现(每1毫秒自加一次切换一个数码管)
  29. always@(posedge Clk or negedge Reset_n)
  30. if(!Reset_n)
  31. cnt_sel <= 0;
  32. else if(Flag_1ms)
  33. cnt_sel <= cnt_sel + 1;
  34. else
  35. cnt_sel <= cnt_sel;
  36. //数码管的位选择逻辑
  37. always@(posedge Clk)begin
  38. case(cnt_sel)
  39. 0: SEL <= 8'b0000_0001;
  40. 1: SEL <= 8'b0000_0010;
  41. 2: SEL <= 8'b0000_0100;
  42. 3: SEL <= 8'b0000_1000;
  43. 4: SEL <= 8'b0001_0000;
  44. 5: SEL <= 8'b0010_0000;
  45. 6: SEL <= 8'b0100_0000;
  46. 7: SEL <= 8'b1000_0000;
  47. default:SEL <= 8'b0000_0000;
  48. endcase
  49. end
  50. reg [3:0]data_temp;//显示16种数值8 + 4 + 2 + 1 = 15,
  51. //查找表中列出SEG段选信号的各种情况。
  52. always@(posedge Clk)begin
  53. case(data_temp)
  54. 0: SEG <= 8'b1100_0000; //0
  55. 1: SEG <= 8'b1111_1001; //1
  56. 2: SEG <= 8'b1010_0100; //2
  57. 3: SEG <= 8'b1011_0000; //3
  58. 4: SEG <= 8'b1001_1001; //4
  59. 5: SEG <= 8'b1001_0010; //5
  60. 6: SEG <= 8'b1000_0010; //6
  61. 7: SEG <= 8'b1111_1000; //7
  62. 8: SEG <= 8'b1000_0000; //8
  63. 9: SEG <= 8'b1001_0000; //9
  64. 10: SEG <= 8'b1000_1000;//A
  65. 11: SEG <= 8'b1000_0011;//B
  66. 12: SEG <= 8'b1100_0110;//C
  67. 13: SEG <= 8'b1010_0001;//D
  68. 14: SEG <= 8'b1000_0110;//E
  69. 15: SEG <= 8'b1000_1110;//F
  70. default:SEL <= 8'b1111_1111;//全灭
  71. endcase
  72. end
  73. //8路选择器实现逻辑
  74. always@(*)
  75. case(cnt_sel)
  76. 0:data_temp <= Disp_Data[3:0];
  77. 1:data_temp <= Disp_Data[7:4];
  78. 2:data_temp <= Disp_Data[11:8];
  79. 3:data_temp <= Disp_Data[15:12];
  80. 4:data_temp <= Disp_Data[19:16];
  81. 5:data_temp <= Disp_Data[23:20];
  82. 6:data_temp <= Disp_Data[27:24];
  83. 7:data_temp <= Disp_Data[31:28];
  84. default:data_temp = 4'b0000;
  85. endcase
  86. endmodule

3.2 74HC595驱动代码

代码中可以看出使用的频率是12.5MHZ,所以SCLK的周期是80ns。

  1. `timescale 1ns / 1ps
  2. module HC595_Driver(
  3. input Clk,
  4. input Reset_n,
  5. input [7:0]SEL,
  6. input [7:0]SEG,
  7. output reg DIO,
  8. output reg SCLK,
  9. output reg RCLK
  10. );
  11. parameter MCNT = 2-1;
  12. reg [29:0]Cnt_40ns;
  13. reg [4:0]Bit_cnt;
  14. //40ns定时单位
  15. always@(posedge Clk or negedge Reset_n)
  16. if(!Reset_n)
  17. Cnt_40ns <= 0;
  18. else if(Cnt_40ns == MCNT)
  19. Cnt_40ns <= 0;
  20. else
  21. Cnt_40ns <= Cnt_40ns+1;
  22. //位控制逻辑
  23. always@(posedge Clk or negedge Reset_n)
  24. if(!Reset_n)
  25. Bit_cnt <= 0;
  26. else if(Cnt_40ns == MCNT)
  27. Bit_cnt <= Bit_cnt + 1;
  28. else
  29. Bit_cnt <= Bit_cnt;
  30. //不同时刻做不同的事情(线性序列机,找到最小时间单位40ns)
  31. always@(posedge Clk or negedge Reset_n)
  32. if(!Reset_n)begin
  33. DIO <= 1'd0;
  34. RCLK <= 1'd0;
  35. SCLK <= 1'd0;
  36. end
  37. else begin
  38. case(Bit_cnt)
  39. 0: begin DIO <= SEG[7]; SCLK <= 1'd0;RCLK <= 1'd1;end//高位先给
  40. 1: begin SCLK <= 1; RCLK <= 1'd0;end
  41. 2: begin DIO <= SEG[6]; SCLK <= 1'd0;end
  42. 3: begin SCLK <= 1; end
  43. 4: begin DIO <= SEG[5]; SCLK <= 1'd0;end
  44. 5: begin SCLK <= 1; end
  45. 6: begin DIO <= SEG[4]; SCLK <= 1'd0;end
  46. 7: begin SCLK <= 1; end
  47. 8: begin DIO <= SEG[3]; SCLK <= 1'd0;end
  48. 9: begin SCLK <= 1; end
  49. 10: begin DIO <= SEG[2]; SCLK <= 1'd0;end
  50. 11: begin SCLK <= 1; end
  51. 12: begin DIO <= SEG[1]; SCLK <= 1'd0;end
  52. 13: begin SCLK <= 1; end
  53. 14: begin DIO <= SEG[0]; SCLK <= 1'd0;end
  54. 15: begin SCLK <= 1; end
  55. 16: begin DIO <= SEL[7]; SCLK <= 1'd0;end
  56. 17: begin SCLK <= 1; end
  57. 18: begin DIO <= SEL[6]; SCLK <= 1'd0;end
  58. 19: begin SCLK <= 1; end
  59. 20: begin DIO <= SEL[5]; SCLK <= 1'd0;end
  60. 21: begin SCLK <= 1; end
  61. 22: begin DIO <= SEL[4]; SCLK <= 1'd0;end
  62. 23: begin SCLK <= 1; end
  63. 24: begin DIO <= SEL[3]; SCLK <= 1'd0;end
  64. 25: begin SCLK <= 1; end
  65. 26: begin DIO <= SEL[2]; SCLK <= 1'd0;end
  66. 27: begin SCLK <= 1; end
  67. 28: begin DIO <= SEL[1]; SCLK <= 1'd0;end
  68. 29: begin SCLK <= 1; end
  69. 30: begin DIO <= SEL[0]; SCLK <= 1'd0;end
  70. 31: begin SCLK <= 1; end
  71. endcase
  72. end
  73. endmodule

3.3 74HC595仿真测试代码

  1. `timescale 1ns / 1ps
  2. module HC595_Driver_tb();
  3. reg Clk;
  4. reg Reset_n;
  5. reg [7:0]SEL;
  6. reg [7:0]SEG;
  7. wire DIO;
  8. wire SCLK;
  9. wire RCLK;
  10. HC595_Driver HC595_Driver(
  11. .Clk(Clk),
  12. .Reset_n(Reset_n),
  13. .SEL(SEL),
  14. .SEG(SEG),
  15. .DIO(DIO),
  16. .SCLK(SCLK),
  17. .RCLK(RCLK)
  18. );
  19. initial Clk = 1;
  20. always #10 Clk = ~Clk;
  21. initial
  22. begin
  23. Reset_n = 0;
  24. SEL = 8'b0000_0001;
  25. SEG = 8'b0101_0101;
  26. #201;
  27. Reset_n = 1;
  28. #5000;
  29. SEL = 8'b0000_0010;
  30. SEG = 8'b1010_1010;
  31. #5000;
  32. SEL = 8'b1010_0101;
  33. SEG = 8'b0000_1101;
  34. #5000;
  35. $stop;
  36. end
  37. endmodule

3.4 74HC595仿真测试图

四、整体例化测试代码实现

  1. `timescale 1ns / 1ps
  2. module hex8_hc595_test(
  3. input Clk,
  4. input Reset_n,
  5. //input SW,
  6. output DIO,
  7. output SCLK,
  8. output RCLK
  9. );
  10. wire [7:0]SEL;//hex8模块与HC595_Driver模块连接到了一起。用导线wirej进行连接.
  11. wire [7:0]SEG;
  12. wire [31:0]Disp_Data;
  13. hex8 hex8(
  14. .Clk(Clk),
  15. .Reset_n(Reset_n),
  16. .Disp_Data(Disp_Data),
  17. .SEL(SEL),
  18. .SEG(SEG)
  19. );
  20. HC595_Driver HC595_Driver(
  21. .Clk(Clk),
  22. .Reset_n(Reset_n),
  23. .SEL(SEL),
  24. .SEG(SEG),
  25. .DIO(DIO),//底层模块的输出端口不能用reg型了
  26. .SCLK(SCLK),//底层模块的输出端口不能用reg型了
  27. .RCLK(RCLK)//底层模块的输出端口不能用reg型了
  28. );
  29. assign Disp_Data = 32'h01221843;
  30. // always@(*)
  31. // case(SW)
  32. // 0: Disp_Data <= 32'h01221843;
  33. // 1: Disp_Data <= 32'h12345678;
  34. // endcase
  35. endmodule

这就实现了数码管动态显示的功能了。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/菜鸟追梦旅行/article/detail/402679
推荐阅读
相关标签
  

闽ICP备14008679号