当前位置:   article > 正文

FPGA开发——按键控制LED的实现

FPGA开发——按键控制LED的实现

一、概述

在上一篇文章中我们学习了按键的相关消抖及其使用,在这篇文章当中我们就针对通过按键实现LED的控制。

1、按键原理图

2、基本框架

通过我们前面编写的按键消抖的文件和LED文件将按键和LED两个模块进行交互,从而达到按键控制LED的目的。

 二、代码编写

1、首先是按键相关设计文件的编写,新建key.v,如下:

  1. //状态机实现
  2. module key (
  3. input clk ,
  4. input rst_n ,
  5. input key_in , //输入原始的按键信号
  6. output reg key_out //输出处理之后的按键信号
  7. );
  8. //参数定义
  9. localparam IDLE = 4'b0001,//空闲
  10. JITTLE0 = 4'b0010,//滤除第一次抖动
  11. DOWN = 4'b0100,//稳定
  12. JITTLE1 = 4'b1000;//滤除第二次抖动
  13. parameter TIME_20MS = 1_000_000;//需要计数的值,20ms
  14. //内部信号
  15. reg [3:0] state_c;//现态
  16. reg [3:0] state_n;//次态
  17. reg [19:0] cnt_20ms;//计数20ms
  18. wire add_cnt_20ms;
  19. wire end_cnt_20ms;
  20. wire nedge ;//下降沿信号
  21. wire pedge ;//上升沿信号
  22. reg key_in_r1 ;// 同步打拍
  23. //状态转移 同步时序逻辑描述状态转移
  24. always @(posedge clk or negedge rst_n) begin
  25. if(!rst_n)
  26. state_c <= IDLE;
  27. else
  28. state_c <= state_n;
  29. end
  30. //状态转移条件 组合逻辑
  31. always @(*) begin
  32. case (state_c)//一定是case 现态
  33. IDLE:begin
  34. if(nedge)
  35. state_n = JITTLE0;
  36. else
  37. state_n = state_c;
  38. end
  39. JITTLE0:begin
  40. if(end_cnt_20ms)
  41. state_n = DOWN;
  42. else
  43. state_n = state_c;
  44. end
  45. DOWN:begin
  46. if(pedge)
  47. state_n = JITTLE1;
  48. else
  49. state_n = state_c;
  50. end
  51. JITTLE1 :begin
  52. if(end_cnt_20ms)
  53. state_n = IDLE;
  54. else
  55. state_n = state_c;
  56. end
  57. default: state_n = IDLE;
  58. endcase
  59. end
  60. //20ms计数器
  61. always @(posedge clk or negedge rst_n) begin
  62. if(!rst_n)
  63. cnt_20ms <= 0;
  64. else if(add_cnt_20ms)begin
  65. if(end_cnt_20ms)
  66. cnt_20ms <= 0;
  67. else
  68. cnt_20ms <= cnt_20ms + 1;
  69. end
  70. end
  71. assign add_cnt_20ms = (state_c == JITTLE0) || (state_c == JITTLE1);
  72. assign end_cnt_20ms = add_cnt_20ms && cnt_20ms == TIME_20MS - 1;
  73. //下降沿 上升沿
  74. //同步 打拍
  75. always @(posedge clk or negedge rst_n)begin
  76. if(!rst_n)begin
  77. key_in_r1 <= 2'b11;
  78. end
  79. else begin
  80. key_in_r1 <= key_in; //同步按键输入信号
  81. end
  82. end
  83. //r1当前状态
  84. assign nedge = ~key_in_r1 && key_in;
  85. assign pedge = key_in_r1 && ~key_in;
  86. //key_out
  87. always @(posedge clk or negedge rst_n) begin
  88. if(!rst_n)
  89. key_out <= 0;
  90. else if(end_cnt_20ms &&(state_c== JITTLE1))
  91. key_out <= ~key_in_r1;//有效脉冲 20ns
  92. else
  93. key_out <= 0;
  94. end
  95. endmodule

2、LED相关设计文件编写

新建led_ctrl.v文件

  1. module led_ctrl(
  2. input clk ,
  3. input rst_n ,
  4. input key_flag ,//输入原始的按键信号
  5. output reg led //输出处理之后的按键信号
  6. );
  7. always @(posedge clk or negedge rst_n )begin
  8. if(!rst_n)
  9. led<=1'b0;
  10. else if(key_flag)
  11. led<=~led;
  12. end
  13. endmodule

3、顶层文件编写

在顶层文件中,使用一个中间变量key_out将按键中的输出赋值给LED模块中的按键标志位输入key_flag。

  1. module top(
  2. input clk,
  3. input rst_n,
  4. input key_in,
  5. output led
  6. );
  7. wire key_out;
  8. key key_inst(
  9. /*input */ .clk (clk ),
  10. /*input */ .rst_n (rst_n ),
  11. /*input */ .key_in (key_in), //输入原始的按键信号
  12. /*output reg */ .key_out (key_out) //输出处理之后的按键信号
  13. );
  14. led_ctrl led_inst(
  15. /*input */ .clk (clk ),
  16. /*input */ .rst_n (rst_n ),
  17. /*input */ .led (led), //输入原始的按键信号
  18. /*output reg */ .key_flag (key_out) //输出处理之后的按键信号
  19. );
  20. endmodule

4、测试文件编写

  1. `timescale 1ns/1ns
  2. module top_tb ;
  3. reg clk ;
  4. reg rst_n ;
  5. reg key_in ;
  6. wire led ;
  7. defparam top_inst.key_inst.TIME_20MS = 1000;
  8. top top_inst(
  9. .clk (clk ),
  10. .rst_n (rst_n ),
  11. .key_in (key_in ), //输入原始的按键信号
  12. .led (led ) //输出处理之后的按键信号
  13. );
  14. //激励信号产生
  15. parameter CLK_CLY = 20;
  16. //时钟
  17. initial clk=1;
  18. always #(CLK_CLY/2)clk=~clk;
  19. //复位
  20. initial begin
  21. rst_n= 1'b0;
  22. #(CLK_CLY*3);
  23. #5;//复位结束避开时钟上升沿
  24. rst_n= 1'b1;
  25. end
  26. //激励
  27. integer i;
  28. initial repeat(5)begin
  29. key_in = 1;//模拟按键未按下
  30. i ={$random}%6;//给i赋值0-5
  31. #(CLK_CLY*500);//等待复位时间结束
  32. #3;
  33. repeat (3)begin
  34. key_in = 0;//前按键抖动开始
  35. #(CLK_CLY*1);
  36. //一个5-10ms的抖动时间
  37. repeat ((i+5)*50)begin
  38. key_in = $random;
  39. #(CLK_CLY*1);
  40. end
  41. key_in = 0;//按键稳定
  42. #(CLK_CLY*100*50);
  43. //后抖动开始
  44. key_in = 1;
  45. #(CLK_CLY*1);
  46. repeat ((i+5)*50)begin
  47. key_in = $random;
  48. #(CLK_CLY*1);
  49. end
  50. key_in = 1;//按键稳定
  51. #(CLK_CLY*10*500);
  52. end
  53. //模拟意外抖动
  54. repeat (3)begin
  55. repeat ((i+5)*50)begin
  56. key_in = $random;
  57. #(CLK_CLY*1);
  58. end
  59. key_in = 1;//按键稳定
  60. #(CLK_CLY*500);
  61. end
  62. $stop;
  63. end
  64. endmodule

三、仿真波形图

通过波形图我们可以看见当按键按下一次,LED状态切换一次,实现了按键控制LED的功能实现。 

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号