经典模式流水灯实验的个人总结和思考

举报
李锐博恩 发表于 2021/07/15 08:55:25 2021/07/15
【摘要】 问题叙述: 当拨码开关SW3处于OFF时, LED停止不动,只有一个LED处于点亮,并且点亮的LED不会变化;而SW3处于ON状态时,流水灯处于流动状态。导航按键S2被按下后,LED流动方向是从上到下(D9到D2方向);导航按键S3被按下后,LED流动方向是从下到上(D2到D9)。 这里面用到了拨码开关,按键,以及led灯,那么我把这三种外设的电路图给出来,并简...

问题叙述:

当拨码开关SW3处于OFF时, LED停止不动,只有一个LED处于点亮,并且点亮的LED不会变化;而SW3处于ON状态时,流水灯处于流动状态。导航按键S2被按下后,LED流动方向是从上到下(D9D2方向);导航按键S3被按下后,LED流动方向是从下到上(D2D9)。

这里面用到了拨码开关,按键,以及led灯,那么我把这三种外设的电路图给出来,并简单解释:

拨码开关:

拨码开关处于“ON”状态时,SW0输出低电平;当拨码开关处于“OFF”状态时,SW0输出高电平

led灯:

可见,低电平led灯亮;

按键:

独立按键一般有2组管脚,这2组管脚在按键未被按下时是断开的,在按键被按下时则是导通的

基于此原理,我们一般会把按键的一个管脚接地,另一个管脚上拉到VCC,并且也连接到GPIO。这样,在按键未被按下时,GPIO的连接状态为上拉到VCC,则键值为1;按键被按下时,GPIO虽然还是上拉到VCC,但同时被导通的另一个管脚拉到地了,所以它的键值实际上是0


其他没什么好说的,就是按键这个问题,既然用到了按键,就要对按键的消抖问题进行处理,本实验也不例外,在用Verilog HDL语言设计硬件电路时,必须考虑按键抖动的问题:

关于按键抖动的消除,上篇博文如果明白了的话,稍加改动,就可以直接拿过来用了。

贴出博文地址:《按键消抖与LED控制》实验的个人思考与总结

一开始,我也没想到把上篇博文中的按键抖动代码拿过来改动,准备过一遍实验,参考特权同学的代码,可是发现,代码我看不懂,这样的话,马克思大概是说过这么一句话,忘了,大概意思是需求是催生生产力。特权同学的代码看了好久,就是不明白为什么?我得自己找办法呀,于是突然想到了为什么非要用你的代码呢?我改一下上篇博文的按键消抖的代码,再添加一些控制led等的东西不就好了。于是产生了如下的Verilog HDL设计代码:


  
  1. `timescale 1ns / 1ps
  2. //
  3. // Company:
  4. // Engineer:
  5. //
  6. // Create Date: 19:47:47 08/16/2018
  7. // Design Name:
  8. // Module Name: led_flow
  9. // Project Name:
  10. // Target Devices:
  11. // Tool versions:
  12. // Description:
  13. //
  14. // Dependencies:
  15. //
  16. // Revision:
  17. // Revision 0.01 - File Created
  18. // Additional Comments:
  19. //
  20. //
  21. module led_flow(
  22. clk,rst_n,
  23. switch,
  24. sw1_n,sw2_n,
  25. led
  26. );
  27. input clk; //主时钟信号,50MHz
  28. input rst_n; //复位信号,低有效
  29. input switch; //switch表示拨码开关,低电平表示on,高电平表示off
  30. input sw1_n,sw2_n; //2个独立按键,低表示按下
  31. output[7:0] led; //8个发光二极管
  32. reg [7:0] led;
  33. //---------------------------------------------------------------------------
  34. reg[1:0] key_rst;
  35. always @(posedge clk or negedge rst_n)
  36. if (!rst_n) key_rst <= 2'b11;
  37. else key_rst <= {sw2_n,sw1_n};
  38. reg[1:0] key_rst_r; //每个时钟周期的上升沿将low_sw信号锁存到low_sw_r中
  39. always @ ( posedge clk or negedge rst_n )
  40. if (!rst_n) key_rst_r <= 2'b11;
  41. else key_rst_r <= key_rst;
  42. //当寄存器key_rst由1变为0时,key_an的值变为高,维持一个时钟周期
  43. wire[2:0] key_an = key_rst_r & (~key_rst);
  44. /*
  45. key_rst 1 1 1 0 0 1
  46. ~key_rst 0 0 0 1 1 0
  47. key_rst_r 1 1 1 0 0 1
  48. key_an 0 0 1 0 0
  49. */
  50. //---------------------------------------------------------------------------
  51. reg[19:0] cnt; //计数寄存器
  52. always @ (posedge clk or negedge rst_n)
  53. if (!rst_n) cnt <= 20'd0; //异步复位
  54. else if(key_an) cnt <=20'd0;
  55. else cnt <= cnt + 1'b1;
  56. reg[1:0] low_sw;
  57. always @(posedge clk or negedge rst_n)
  58. if (!rst_n) low_sw <= 2'b11;
  59. else if (cnt == 20'hfffff) //满20ms,将按键值锁存到寄存器low_sw中 cnt == 20'hfffff
  60. low_sw <= {sw2_n,sw1_n};
  61. //---------------------------------------------------------------------------
  62. reg [1:0] low_sw_r; //每个时钟周期的上升沿将low_sw信号锁存到low_sw_r中
  63. always @ ( posedge clk or negedge rst_n )
  64. if (!rst_n) low_sw_r <= 2'b11;
  65. else low_sw_r <= low_sw;
  66. /*
  67. low_sw 11 11 11 10 10 10
  68. ~low_sw 00 00 00 01 01 01
  69. low_sw_r 11 11 11 10 10 10
  70. led_ctrl 00 00 00 01 00 00
  71. */
  72. //当寄存器low_sw由1变为0时,led_ctrl的值变为高,维持一个时钟周期
  73. wire[1:0] led_ctrl = low_sw_r[1:0] & ( ~low_sw[1:0]);
  74. reg dir;
  75. always @ (posedge clk or negedge rst_n)
  76. if (!rst_n) begin
  77. dir <= 1'b0; //复位信号有效时,led灯方向控制寄存器置0,也就是默认为向左流动
  78. end
  79. else begin
  80. if(led_ctrl[0] == 1'b1) dir <= 1'b1; //控制led灯向右流动
  81. if(led_ctrl[1] == 1'b1) dir <= 1'b0; //控制led灯向左流动
  82. end
  83. reg [23:0] delay; //led灯延迟计数器
  84. always @(posedge clk or negedge rst_n)
  85. begin
  86. if(!rst_n)
  87. delay <= 24'b0;
  88. else
  89. delay <= delay + 24'b1;
  90. end
  91. always @(posedge clk or negedge rst_n)
  92. begin
  93. if(!rst_n)
  94. led <= 8'b0111_1111; //复位信号有效时,led灯处于静止状态,且只有一个灯led7亮
  95. else if(delay == 24'hffffff) //否则,延迟到达24'hffffff,进行如下操作
  96. begin
  97. if(switch == 1'b1) //如果拨码开关处于off状态时,则led灯处于静止状态,且只有一个等led7亮
  98. led <= 8'b0111_1111;
  99. else //否则,也就是拨码开关处于on状态时,则led做出如下动作:
  100. begin
  101. case(dir) //dir是控制方向的状态,如果dir <= 1'b1,则从左向右流动,如果dir <= 'b0,则从右向左流动
  102. 1'b1: led <= {led[0],led[7:1]};
  103. 1'b0: led <= {led[6:0],led[7]};
  104. default: ;
  105. endcase
  106. end
  107. end
  108. end
  109. endmodule

我注释也写的很清楚,我就不多解释了,如果你真的想了解,那就认真研读代码,肯定能懂;不过前提是度过了按键消抖的那篇博文。

实验结果十分完美,和我设想的一样。

如何用ISE进行整个流程,我以前也用一个简单的实例说过:全过程实现一个最简单的FPGA项目之PWM蜂鸣器控制

那纯理论上也说过:XIlinx FPGA开发基本流程(一)(总介绍)

 

 

文章来源: reborn.blog.csdn.net,作者:李锐博恩,版权归原作者所有,如需转载,请联系作者。

原文链接:reborn.blog.csdn.net/article/details/81748879

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。