当前位置:   article > 正文

FPGA项目(5)--FPGA控制数码管动态显示的原理_为什么fpga开发板的七段数码管到9就灭了

为什么fpga开发板的七段数码管到9就灭了

        数码管是现在电子产品上常用的显示器件,它有驱动简单、显示清晰、价格低廉等优势。数码管的实物图:

         数码管的内部结构图如下所示:

         从图中可以看出,它由八个段组成,即A B C D E F G DP(小数点),只要将这八个段按规律组合点亮,就能显示出一定的数字。例如,对于数字1,只需要将B C两段点亮,其他全部熄灭,那么就可以在数码管上显示出数字1.数码管还有一个公共端,用于接电源或地。

        数码管又分为两种,一种是共阴极数码管,一种是共阳极数码管。对于共阴极数码管而言,它的各个段是高电平点亮,公共端接地。对于共阳极数码管,它的各个段是低电平点亮,公共端接电源。现在给出两种数码管的0-9这十个数字的段码表:

        共阴极(兼有共阳极):

        

        共阳极:

         

         至此,对于如何在数码管上显示出数字,我们就有了思路。本次我用的是共阳极数码管,不需要显示小数点,所以对我而言,我只需要控制数码管的七个段即可。用FPGA控制数码管静态显示是很容易的,直接给七个段分配七个管脚,然后再输出对应的电平,就能静态显示出数字。如果要显示数字1,只要输出电平 1111001即可。难点在于如何动态显示。下面讲解FPGA驱动四位数码管动态显示的思路:

        本次使用的四位数码管按如下方式排列:

         每个数码管都有一个位选端,通过位选端的控制,就可以一次只点亮一个数码管,然后快速切换到另一个数码管,只要频率够快,就能达到动态显示的效果。本次我使用的4位数码管的位选端是低电平有效,那么当位选信号为1110时,标号为4的数码管被点亮,可以显示相应的数字。要使得标号为3的数码管也被点亮显示数字时,只需要将位选信号赋值为1101即可。只要以足够快的频率,依次给位选信号赋值为1110 ,1101 , 1011 , 0111,就可以同时点亮四个数码管。

        下面给出FPGA驱动数码管动态显示的代码,并对代码进行具体的分析、解释。

  1. module seg(
  2. input sys_clk,sys_rest,
  3. input [15:0] data,
  4. output reg [3:0] sel,
  5. output reg [6:0] seg_led
  6. );
  7. parameter CLK_NUM=4'd10;
  8. parameter MSNUM=14'd5000;
  9. reg [3:0] CNT_NUM;
  10. reg CLK;
  11. reg [12:0] MSCNT;
  12. reg MS_flag;
  13. reg [3:0] num_display;
  14. reg [15:0] num;
  15. reg [2:0] sel_num; //选择哪一位数码管被点亮
  16. //wire define
  17. wire [3:0] data0 ; // 个位数
  18. wire [3:0] data1 ; // 十位数
  19. wire [3:0] data2 ; // 百位数
  20. wire [3:0] data3 ; // 千位数
  21. //提取显示数值所对应的十进制数的各个位
  22. assign data0 = data[3:0]; // 个位数
  23. assign data1 = data[7:4]; // 十位数
  24. assign data2 = data[11:8]; // 百位数
  25. assign data3 = data[15:12]; // 千位数
  26. always @(posedge sys_clk or negedge sys_rest) begin
  27. if(!sys_rest)
  28. begin
  29. CNT_NUM<=4'd0;
  30. CLK<=1'd1;
  31. end
  32. else if(CNT_NUM<=CLK_NUM/2-1'b1)
  33. begin
  34. CLK<=~CLK;
  35. CNT_NUM<=4'd0;
  36. end
  37. else
  38. begin
  39. CNT_NUM<=CNT_NUM+1;
  40. CLK<=CLK;
  41. end
  42. end
  43. always @(posedge CLK or negedge sys_rest) begin
  44. if(!sys_rest)
  45. num<=16'd0;
  46. else
  47. begin
  48. num[15:12] <= data3; //则依次给4位数码管赋值
  49. num[11:8] <= data2;
  50. num[ 7:4] <= data1;
  51. num[ 3:0] <= data0;
  52. end
  53. end
  54. always @(posedge CLK or negedge sys_rest) begin //产生1ms脉冲
  55. if(!sys_rest)
  56. begin
  57. MSCNT<=13'd0;
  58. MS_flag<=1'b0;
  59. end
  60. else if(MSCNT==MSNUM-1)
  61. begin
  62. MSCNT<=13'd0;
  63. MS_flag<=1'b1;
  64. end
  65. else
  66. begin
  67. MSCNT<=MSCNT+1;
  68. MS_flag<=1'b0;
  69. end
  70. end
  71. always @(posedge CLK or negedge sys_rest) begin
  72. if(!sys_rest)
  73. sel_num<=0;
  74. else if(MS_flag)
  75. begin
  76. if(sel_num<3'd3)
  77. sel_num<=sel_num+1;
  78. else
  79. sel_num<=0;
  80. end
  81. else
  82. sel_num<=sel_num;
  83. end
  84. always @(posedge CLK or negedge sys_rest) begin
  85. if(!sys_rest)
  86. sel<=4'b1111;
  87. else
  88. begin
  89. case(sel_num)
  90. 3'd0: begin
  91. sel<= 4'b1110; //显示数码管最低位
  92. num_display<=num[3:0];
  93. end
  94. 3'd1: begin
  95. sel<= 4'b1101; //显示数码管第1
  96. num_display<=num[7:4];
  97. end
  98. 3'd2: begin
  99. sel<= 4'b1011; //显示数码管第2
  100. num_display<=num[11:8];
  101. end
  102. 3'd3: begin
  103. sel<= 4'b0111; //显示数码管第3
  104. num_display<=num[15:12];
  105. end
  106. default sel<= 4'b1111;
  107. endcase
  108. end
  109. end
  110. always @(posedge CLK or negedge sys_rest) begin
  111. if(!sys_rest)
  112. seg_led<=7'b100000;
  113. else
  114. begin
  115. case(num_display)
  116. 4'h0 : seg_led <= 7'b1000000;
  117. 4'h1 : seg_led <= 7'b1111001;
  118. 4'h2 : seg_led <= 7'b0100100;
  119. 4'h3 : seg_led <= 7'b0110000;
  120. 4'h4 : seg_led <= 7'b0011001;
  121. 4'h5 : seg_led <= 7'b0010010;
  122. 4'h6 : seg_led <= 7'b0000010;
  123. 4'h7 : seg_led <= 7'b1111000;
  124. 4'h8 : seg_led <= 7'b0000000;
  125. 4'h9 : seg_led <= 7'b0010000;
  126. 4'd10: seg_led <= 7'b1111111; //不显示任何字符
  127. default : seg_led <= 7'b1000000;
  128. endcase
  129. end
  130. end
  131. endmodule

        首先显示的数据是以BCD码的格式传入的,例如我要显示数据1234,那么就要传入0001_0010_0011_0100给该模块,所以输入数据data的位宽为16。然后定义4个内部变量,data0到data3,用于保存个位 ,十位, 百位 ,千位上的数字,方便后面的显示。随后又分频,产生了5M的时钟CLK和1K的时钟MS_flag。位选信号的变化就是在MS_flag信号的驱动下变换的,也就是说,数码管以1KHZ的频率切换显示,人眼是分辨不出来的,所以看起来就是同时显示了四个数字。最后,根据位选信号,将对应位(个位/十位/百位/千位)的数字传给num_display,再由num_display变量控制数码管段选信号的输出。这样就实现了动态的显示!

        备注:数码管的段选信号就是数码管A B C D E F G等七个段的控制信号,数码管位选信号就是公共端的控制信号。

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

闽ICP备14008679号