当前位置:   article > 正文

FPGA-06FPGA动态数码管显示_4'd0

4'd0

让数码管各个位显示不同的数字,这就需要以动态驱动的方式驱动数码管。

(1)实验任务

使用FPGA开发板上的6位数码管以动态方式从0开始计数,每100ms计数值增加一,当计数值从0增加到999999后重新从0开始计数。

(2)硬件设计

https://blog.csdn.net/m0_37690102/article/details/100131062

(3)程序设计

由实验任务和动态驱动的原理我们可以知道,若要让6个数码管轮流显示对应的数字,首先需要一个数码管动态显示模块,能够依次点亮6个数码管,并将对应的数据输出至数码管,也就是需要分别控制段选和位选信号;同时还需要一个计数模块,能够将0—999999依次输出至数码管动态显示模块。根据实验任务,我们可以大致规划出系统的控制流程:首先我们需要一个数码管动态显示模块在数码管上显示数据,其次需要一个计数控制模块实现从0到999999的变化,并将产生的数值通过数码管动态显示模块在数码管上显示出来。由此画出系统的功能框图如下所示:

计数模块:

  1. //============================================
  2. //计数模块输出的数值data连接至数码管显示模块的输入
  3. //端口data,数码管显示模块将输入的数据data输出至
  4. //数码管上显示。
  5. //============================================
  6. module count(
  7. input sys_clk,
  8. input sys_rst_n,
  9. output reg[19:0] data, // 6个数码管要显示的数值
  10. output reg[5:0] point,// 小数点的位置,高电平点亮对应数码管位上的小数点
  11. output reg en, // 数码管使能信号
  12. output reg sign // 符号位,高电平时显示负号,低电平不显示负号
  13. );
  14. parameter MAX_NUM = 23'd5000_000;
  15. reg [22:0] cnt;
  16. reg flag;
  17. always @(posedge sys_clk or negedge sys_rst_n)begin
  18. if(!sys_rst_n)begin
  19. cnt <= 23'b0;
  20. flag <= 1'b0;
  21. end
  22. else if(cnt < MAX_NUM - 1'b1)begin
  23. cnt <= cnt + 1'b1;
  24. flag <= 1'b0;
  25. end
  26. else begin
  27. cnt <= 23'b0;
  28. flag <= 1'b1;
  29. end
  30. end
  31. //数码管需要显示的数据,从0累加到999999\
  32. always @(posedge sys_clk or negedge sys_rst_n)begin
  33. if(!sys_rst_n)begin
  34. data <= 20'd999999;
  35. point <= 6'b000_000;
  36. en <= 1'b0;
  37. sign <= 1'b0;
  38. end
  39. else begin
  40. point <= 6'b000_000;
  41. en <= 1'b1;//enable
  42. sign <= 1'b0;//不显示负号
  43. if(flag) begin
  44. if(data > 20'b0)
  45. data <= data - 1'b1;
  46. else
  47. data <= 20'd999999;
  48. end
  49. end
  50. end
  51. endmodule

动态数码管显示

  1. module seg_led(
  2. input sys_clk , // 时钟信号
  3. input sys_rst_n , // 复位信号
  4. input [19:0] data , // 6位数码管要显示的数值
  5. input [5:0] point , // 小数点具体显示的位置,从高到低,高电平有效
  6. input en , // 数码管使能信号
  7. input sign , // 符号位(高电平显示“-”号)
  8. output reg [5:0] seg_sel, // 数码管位选,最左侧数码管为最高位
  9. output reg [7:0] seg_led // 数码管段选
  10. );
  11. //parameter define
  12. localparam CLK_DIVIDE = 4'd10 ; // 时钟分频系数
  13. localparam MAX_NUM = 13'd5000 ; // 对数码管驱动时钟(5MHz)计数1ms所需的计数值
  14. //reg define
  15. reg [ 3:0] clk_cnt ; // 时钟分频计数器
  16. reg dri_clk ; // 数码管的驱动时钟,5MHz
  17. reg [23:0] num ; // 24位bcd码寄存器
  18. reg [12:0] cnt0 ; // 数码管驱动时钟计数器
  19. reg flag ; // 标志信号(标志着cnt0计数达1ms)
  20. reg [2:0] cnt_sel ; // 数码管位选计数器
  21. reg [3:0] num_disp ; // 当前数码管显示的数据
  22. reg dot_disp ; // 当前数码管显示的小数点
  23. //wire define
  24. wire [3:0] data0 ; // 个位数
  25. wire [3:0] data1 ; // 十位数
  26. wire [3:0] data2 ; // 百位数
  27. wire [3:0] data3 ; // 千位数
  28. wire [3:0] data4 ; // 万位数
  29. wire [3:0] data5 ; // 十万位数
  30. //*****************************************************
  31. //** main code
  32. //*****************************************************
  33. //提取显示数值所对应的十进制数的各个位
  34. assign data0 = data % 4'd10; // 个位数
  35. assign data1 = data / 4'd10 % 4'd10 ; // 十位数
  36. assign data2 = data / 7'd100 % 4'd10 ; // 百位数
  37. assign data3 = data / 10'd1000 % 4'd10 ; // 千位数
  38. assign data4 = data / 14'd10000 % 4'd10; // 万位数
  39. assign data5 = data / 17'd100000; // 十万位数
  40. //对系统时钟10分频,得到的频率为5MHz的数码管驱动时钟dri_clk
  41. always @(posedge sys_clk or negedge sys_rst_n) begin
  42. if(!sys_rst_n) begin
  43. clk_cnt <= 4'd0;
  44. dri_clk <= 1'b1;
  45. end
  46. else if(clk_cnt == CLK_DIVIDE/2 - 1'd1) begin
  47. clk_cnt <= 4'd0;
  48. dri_clk <= ~dri_clk;
  49. end
  50. else begin
  51. clk_cnt <= clk_cnt + 1'b1;
  52. dri_clk <= dri_clk;
  53. end
  54. end
  55. //====================================================================
  56. //将20位2进制数转换为8421bcd码(即使用4位二进制数表示1位十进制数)
  57. always @ (posedge dri_clk or negedge sys_rst_n) begin
  58. if (!sys_rst_n)
  59. num <= 24'b0;
  60. else begin
  61. if (data5 || point[5]) begin //如果显示数据为6位十进制数,
  62. num[23:20] <= data5; //则依次给6位数码管赋值
  63. num[19:16] <= data4;
  64. num[15:12] <= data3;
  65. num[11:8] <= data2;
  66. num[ 7:4] <= data1;
  67. num[ 3:0] <= data0;
  68. end
  69. else begin
  70. if (data4 || point[4]) begin //如果显示数据为5位十进制数,则给低5位数码管赋值
  71. num[19:0] <= {data4,data3,data2,data1,data0};
  72. if(sign)
  73. num[23:20] <= 4'd11; //如果需要显示负号,则最高位(第6位)为符号位
  74. else
  75. num[23:20] <= 4'd10; //不需要显示负号时,则第6位不显示任何字符
  76. end
  77. else begin //如果显示数据为4位十进制数,则给低4位数码管赋值
  78. if (data3 || point[3]) begin
  79. num[15: 0] <= {data3,data2,data1,data0};
  80. num[23:20] <= 4'd10; //第6位不显示任何字符
  81. if(sign) //如果需要显示负号,则最高位(第5位)为符号位
  82. num[19:16] <= 4'd11;
  83. else //不需要显示负号时,则第5位不显示任何字符
  84. num[19:16] <= 4'd10;
  85. end
  86. else begin //如果显示数据为3位十进制数,则给低3位数码管赋值
  87. if (data2 || point[2]) begin
  88. num[11: 0] <= {data2,data1,data0};
  89. //第6、5位不显示任何字符
  90. num[23:16] <= {2{4'd10}};
  91. if(sign) //如果需要显示负号,则最高位(第4位)为符号位
  92. num[15:12] <= 4'd11;
  93. else //不需要显示负号时,则第4位不显示任何字符
  94. num[15:12] <= 4'd10;
  95. end
  96. else begin //如果显示数据为2位十进制数,则给低2位数码管赋值
  97. if (data1 || point[1]) begin
  98. num[ 7: 0] <= {data1,data0};
  99. //654位不显示任何字符
  100. num[23:12] <= {3{4'd10}};
  101. if(sign) //如果需要显示负号,则最高位(第3位)为符号位
  102. num[11:8] <= 4'd11;
  103. else //不需要显示负号时,则第3位不显示任何字符
  104. num[11:8] <= 4'd10;
  105. end
  106. else begin //如果显示数据为1位十进制数,则给最低位数码管赋值
  107. num[3:0] <= data0;
  108. //第6、5位不显示任何字符
  109. num[23:8] <= {4{4'd10}};
  110. if(sign) //如果需要显示负号,则最高位(第2位)为符号位
  111. num[7:4] <= 4'd11;
  112. else //不需要显示负号时,则第2位不显示任何字符
  113. num[7:4] <= 4'd10;
  114. end
  115. end
  116. end
  117. end
  118. end
  119. end
  120. end
  121. //每当计数器对数码管驱动时钟计数时间达1ms,输出一个时钟周期的脉冲信号
  122. always @ (posedge dri_clk or negedge sys_rst_n) begin
  123. if (sys_rst_n == 1'b0) begin
  124. cnt0 <= 13'b0;
  125. flag <= 1'b0;
  126. end
  127. else if (cnt0 < MAX_NUM - 1'b1) begin
  128. cnt0 <= cnt0 + 1'b1;
  129. flag <= 1'b0;
  130. end
  131. else begin
  132. cnt0 <= 13'b0;
  133. flag <= 1'b1;
  134. end
  135. end
  136. //cnt_sel从0计数到5,用于选择当前处于显示状态的数码管
  137. always @ (posedge dri_clk or negedge sys_rst_n) begin
  138. if (sys_rst_n == 1'b0)
  139. cnt_sel <= 3'b0;
  140. else if(flag) begin
  141. if(cnt_sel < 3'd5)
  142. cnt_sel <= cnt_sel + 1'b1;
  143. else
  144. cnt_sel <= 3'b0;
  145. end
  146. else
  147. cnt_sel <= cnt_sel;
  148. end
  149. //控制数码管位选信号,使6位数码管轮流显示
  150. always @ (posedge dri_clk or negedge sys_rst_n) begin
  151. if(!sys_rst_n) begin
  152. seg_sel <= 6'b111111; //位选信号低电平有效
  153. num_disp <= 4'b0;
  154. dot_disp <= 1'b1; //共阳极数码管,低电平导通
  155. end
  156. else begin
  157. if(en) begin
  158. case (cnt_sel)
  159. 3'd0 :begin
  160. seg_sel <= 6'b111110; //显示数码管最低位
  161. num_disp <= num[3:0] ; //显示的数据
  162. dot_disp <= ~point[0]; //显示的小数点
  163. end
  164. 3'd1 :begin
  165. seg_sel <= 6'b111101; //显示数码管第1
  166. num_disp <= num[7:4] ;
  167. dot_disp <= ~point[1];
  168. end
  169. 3'd2 :begin
  170. seg_sel <= 6'b111011; //显示数码管第2
  171. num_disp <= num[11:8];
  172. dot_disp <= ~point[2];
  173. end
  174. 3'd3 :begin
  175. seg_sel <= 6'b110111; //显示数码管第3
  176. num_disp <= num[15:12];
  177. dot_disp <= ~point[3];
  178. end
  179. 3'd4 :begin
  180. seg_sel <= 6'b101111; //显示数码管第4
  181. num_disp <= num[19:16];
  182. dot_disp <= ~point[4];
  183. end
  184. 3'd5 :begin
  185. seg_sel <= 6'b011111; //显示数码管最高位
  186. num_disp <= num[23:20];
  187. dot_disp <= ~point[5];
  188. end
  189. default :begin
  190. seg_sel <= 6'b111111;
  191. num_disp <= 4'b0;
  192. dot_disp <= 1'b1;
  193. end
  194. endcase
  195. end
  196. else begin
  197. seg_sel <= 6'b111111; //使能信号为0时,所有数码管均不显示
  198. num_disp <= 4'b0;
  199. dot_disp <= 1'b1;
  200. end
  201. end
  202. end
  203. //控制数码管段选信号,显示字符
  204. always @ (posedge dri_clk or negedge sys_rst_n) begin
  205. if (!sys_rst_n)
  206. seg_led <= 8'hc0;
  207. else begin
  208. case (num_disp)
  209. 4'd0 : seg_led <= {dot_disp,7'b1000000}; //显示数字 0
  210. 4'd1 : seg_led <= {dot_disp,7'b1111001}; //显示数字 1
  211. 4'd2 : seg_led <= {dot_disp,7'b0100100}; //显示数字 2
  212. 4'd3 : seg_led <= {dot_disp,7'b0110000}; //显示数字 3
  213. 4'd4 : seg_led <= {dot_disp,7'b0011001}; //显示数字 4
  214. 4'd5 : seg_led <= {dot_disp,7'b0010010}; //显示数字 5
  215. 4'd6 : seg_led <= {dot_disp,7'b0000010}; //显示数字 6
  216. 4'd7 : seg_led <= {dot_disp,7'b1111000}; //显示数字 7
  217. 4'd8 : seg_led <= {dot_disp,7'b0000000}; //显示数字 8
  218. 4'd9 : seg_led <= {dot_disp,7'b0010000}; //显示数字 9
  219. 4'd10: seg_led <= 8'b11111111; //不显示任何字符
  220. 4'd11: seg_led <= 8'b10111111; //显示负号(-)
  221. default:
  222. seg_led <= {dot_disp,7'b1000000};
  223. endcase
  224. end
  225. end
  226. endmodule

顶层原理图

(4)下载验证

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

闽ICP备14008679号