当前位置:   article > 正文

基于FPGA的IO复用扫描模块_fpga 模块复用

fpga 模块复用

一、静态数码管显示(共阳极)

RTL代码:

  1. module seg_led_static(
  2. input sys_clk,
  3. input sys_rst,
  4. output [5:0] sel,
  5. output reg [7:0]seg_led
  6. );
  7. reg [24:0] cnt; //25M分频计数器 -> 0.5s
  8. reg [3:0] num; // 显示控制
  9. reg flag; // 增减标志位 1
  10. assign sel = 6'd0;
  11. // 计时模块
  12. always @(posedge sys_clk or negedge sys_rst) begin
  13. if (!sys_rst)
  14. cnt <= 25'd0;
  15. else if (cnt == 25'd5)
  16. cnt <= 25'd0;
  17. else
  18. cnt <= cnt + 1'd1;
  19. end
  20. // 显示控制模块
  21. always @(posedge sys_clk or negedge sys_rst) begin
  22. if (!sys_rst) begin
  23. num <= 4'd0;
  24. flag <= 1'd1;
  25. end
  26. else begin
  27. if (flag == 1'd1) begin
  28. if (num >= 4'hf)
  29. flag <= 1'd0;
  30. else begin
  31. if (cnt == 25'd5)
  32. num <= num + 1'h1;
  33. else
  34. num <= num;
  35. end
  36. end
  37. else begin
  38. if (num <= 4'h0)
  39. flag <= 1'd1;
  40. else begin
  41. if (cnt == 25'd5)
  42. num <= num - 1'h1;
  43. else
  44. num <= num;
  45. end
  46. end
  47. end
  48. end
  49. // 显示模块
  50. always @(posedge sys_clk or negedge sys_rst) begin
  51. if (!sys_rst)
  52. seg_led <= 8'b11111111;
  53. else
  54. case (num)
  55. 4'h0: seg_led <= 8'b1100_0000;
  56. 4'h1: seg_led <= 8'b1111_1001;
  57. 4'h2: seg_led <= 8'b1010_0100;
  58. 4'h3: seg_led <= 8'b1011_0000;
  59. 4'h4: seg_led <= 8'b1001_1001;
  60. 4'h5: seg_led <= 8'b1001_0010;
  61. 4'h6: seg_led <= 8'b1000_0010;
  62. 4'h7: seg_led <= 8'b1111_1000;
  63. 4'h8: seg_led <= 8'b1000_0000;
  64. 4'h9: seg_led <= 8'b1001_0000;
  65. 4'hA: seg_led <= 8'b1000_1000;
  66. 4'hB: seg_led <= 8'b1000_0011;
  67. 4'hC: seg_led <= 8'b1100_0110;
  68. 4'hD: seg_led <= 8'b1010_0001;
  69. 4'hE: seg_led <= 8'b1000_0110;
  70. 4'hF: seg_led <= 8'b1000_1110;
  71. endcase
  72. end
  73. endmodule

Testbench

  1. `timescale 1ns/1ns
  2. module seg_led_static_tb();
  3. reg sys_clk;
  4. reg sys_rst;
  5. wire [5:0] sel;
  6. wire [7:0] seg_led;
  7. always #10 sys_clk = ~ sys_clk;
  8. initial begin
  9. sys_clk <= 1'd0;
  10. sys_rst <= 1'd0;
  11. # 40 sys_rst <= 1'd1;
  12. end
  13. seg_led_static u1(
  14. sys_clk,
  15. sys_rst,
  16. sel,
  17. seg_led
  18. );
  19. endmodule

过程中有这么一个顾虑的问题:

        当flag = 1,num = 4'hf 时,当前时钟下flag<=0,num锁存。在下个时钟上升沿到来时,flag取得0值,num取得锁存值4'hf,cnt取得新计数值,如果cnt达到上限值时,num<=num-1,即在接下来一个时钟上升沿时,num = 4'he. 不存在因为flag变化时导致num持续保持的问题。

基于modelsim的时序分析:

二、动态数码管显示(共阳极)

设计思路

 RTL代码

1、Top module

  1. module seg_led_danymic_top(
  2. input sys_clk,
  3. input sys_rst,
  4. output [5:0] sel,
  5. output [7:0] seg_led
  6. );
  7. wire bcd_clk;
  8. wire sel_flag;
  9. wire [23:0] data;
  10. wire [3:0] data0;
  11. wire [3:0] data1;
  12. wire [3:0] data2;
  13. wire [3:0] data3;
  14. wire [3:0] data4;
  15. wire [3:0] data5;
  16. wire en0;
  17. wire en1;
  18. wire en2;
  19. wire en3;
  20. wire en4;
  21. wire en5;
  22. assign data = {data5,data4,data3,data2,data1,data0};
  23. assign en0 = 1'd1;
  24. assign en1 = (data0 == 4'd9) ? 1'd1 : 1'd0;
  25. assign en2 = ({data1, data0} == 8'h99) ? 1'd1 : 1'd0;
  26. assign en3 = ({data2, data1, data0} == 12'h999) ? 1'd1 : 1'd0;
  27. assign en4 = ({data3, data2, data1, data0} == 16'h9999) ? 1'd1 : 1'd0;
  28. assign en5 = ({data4,data3,data2,data1,data0}==20'h99999) ? 1'd1 : 1'd0;
  29. // 时钟模块
  30. count cnt1(sys_clk, sys_rst, bcd_clk, sel_flag);
  31. // 扫描显示模块
  32. scan_display scan1(
  33. .sys_clk(sys_clk),
  34. .sys_rst(sys_rst),
  35. .sel_flag(sel_flag),
  36. .data(data),
  37. .sel(sel),
  38. .seg_led(seg_led)
  39. );
  40. // 例化6个BCD计数器作为各个数码段的显示值
  41. bcd_cnt u1(bcd_clk, sys_rst, en0, data0);
  42. bcd_cnt u2(bcd_clk, sys_rst, en1, data1);
  43. bcd_cnt u3(bcd_clk, sys_rst, en2, data2);
  44. bcd_cnt u4(bcd_clk, sys_rst, en3, data3);
  45. bcd_cnt u5(bcd_clk, sys_rst, en4, data4);
  46. bcd_cnt u6(bcd_clk, sys_rst, en5, data5);
  47. endmodule

2、计时模块

  1. module count(
  2. input sys_clk,
  3. input sys_rst,
  4. output reg bcd_clk,
  5. output reg sel_flag
  6. );
  7. reg [22:0] cnt_seg;
  8. reg [18:0] cnt_sel;
  9. reg sel_clk;
  10. // 5M分频计数器 -> 10Hz(0.1s)用于bcd计数器的时钟信号
  11. always @(posedge sys_clk or negedge sys_rst) begin
  12. if (!sys_rst) begin
  13. cnt_seg <= 23'd0;
  14. bcd_clk <= 1'd0;
  15. end
  16. else if (cnt_seg == 23'd2_499_999) begin
  17. cnt_seg <= 23'd0;
  18. bcd_clk <= ~ bcd_clk;
  19. end
  20. else begin
  21. cnt_seg <= cnt_seg + 1'd1;
  22. bcd_clk <= bcd_clk;
  23. end
  24. end
  25. // 计时模块 6ms -> 用于位选
  26. always @(posedge sys_clk or negedge sys_rst) begin
  27. if (!sys_rst) begin
  28. cnt_sel <= 19'd0;
  29. sel_flag <= 1'd0;
  30. end
  31. else if (cnt_sel == 19'd29_999) begin
  32. cnt_sel <= 19'd0;
  33. sel_flag <= 1'd1;
  34. end
  35. else begin
  36. cnt_sel <= cnt_sel + 1'd1;
  37. sel_flag <= 1'd0;
  38. end
  39. end
  40. endmodule

3、BCD计数器模块

  1. module bcd_cnt(
  2. input clk,
  3. input rst,
  4. input en,
  5. output reg [3:0] data
  6. );
  7. always @(posedge clk or negedge rst) begin
  8. if (!rst)
  9. data <= 4'd0;
  10. else if (en == 1'd1) begin
  11. if (data == 4'd9)
  12. data <= 4'd0;
  13. else
  14. data <= data + 1'd1;
  15. end
  16. else
  17. data <= data;
  18. end
  19. endmodule

4、扫描显示模块

  1. module scan_display(
  2. input sys_clk,
  3. input sys_rst,
  4. input sel_flag,
  5. input [23:0]data,
  6. output reg [5:0] sel,
  7. output reg [7:0] seg_led
  8. );
  9. reg [2:0] cnt_sel_flag;
  10. reg [3:0] seg_reg; // 用于存放每位数码管的待翻译的数据
  11. // 位选状态控制计数器
  12. always @(posedge sys_clk or negedge sys_rst) begin
  13. if (!sys_rst)
  14. cnt_sel_flag <= 3'd0;
  15. else if (sel_flag == 1'd1) begin
  16. if (cnt_sel_flag == 3'd5)
  17. cnt_sel_flag <= 3'd0;
  18. else
  19. cnt_sel_flag <= cnt_sel_flag + 1'd1;
  20. end
  21. else
  22. cnt_sel_flag <= cnt_sel_flag;
  23. end
  24. // 位选控制器
  25. always @(posedge sys_clk or negedge sys_rst) begin
  26. if (!sys_rst)
  27. sel <= 6'b111111;
  28. else begin
  29. case (cnt_sel_flag)
  30. 3'd0: begin
  31. sel <= 6'b111110;
  32. seg_reg <= data[3:0];
  33. end
  34. 3'd1: begin
  35. sel <= 6'b111101;
  36. seg_reg <= data[7:4];
  37. end
  38. 3'd2: begin
  39. sel <= 6'b111011;
  40. seg_reg <= data[11:8];
  41. end
  42. 3'd3: begin
  43. sel <= 6'b110111;
  44. seg_reg <= data[15:12];
  45. end
  46. 3'd4: begin
  47. sel <= 6'b101111;
  48. seg_reg <= data[19:16];
  49. end
  50. 3'd5: begin
  51. sel <= 6'b011111;
  52. seg_reg <= data[23:20];
  53. end
  54. endcase
  55. end
  56. end
  57. // 段显控制器
  58. always @(posedge sys_clk or negedge sys_rst) begin
  59. if (!sys_rst)
  60. seg_led <= 8'b11111111;
  61. else begin
  62. case (seg_reg)
  63. 4'h0: seg_led <= 8'b1100_0000;
  64. 4'h1: seg_led <= 8'b1111_1001;
  65. 4'h2: seg_led <= 8'b1010_0100;
  66. 4'h3: seg_led <= 8'b1011_0000;
  67. 4'h4: seg_led <= 8'b1001_1001;
  68. 4'h5: seg_led <= 8'b1001_0010;
  69. 4'h6: seg_led <= 8'b1000_0010;
  70. 4'h7: seg_led <= 8'b1111_1000;
  71. 4'h8: seg_led <= 8'b1000_0000;
  72. 4'h9: seg_led <= 8'b1001_0000;
  73. endcase
  74. end
  75. end
  76. endmodule

Testbench:

  1. `timescale 1ns/1ns
  2. module seg_led_dynamic_tb();
  3. reg sys_clk;
  4. reg sys_rst;
  5. wire [5:0] sel;
  6. wire [7:0] seg_led;
  7. always #10 sys_clk = ~ sys_clk;
  8. initial begin
  9. sys_clk <= 1'd0;
  10. sys_rst <= 1'd0;
  11. # 40 sys_rst <= 1'd1;
  12. end
  13. seg_led_danymic_top a1(
  14. sys_clk,
  15. sys_rst,
  16. sel,
  17. seg_led
  18. );
  19. endmodule

基于Modelsim的时序分析:

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

闽ICP备14008679号