赞
踩
一、概述
在上一篇文章中我们学习了按键的相关消抖及其使用,在这篇文章当中我们就针对通过按键实现LED的控制。
1、按键原理图
2、基本框架
通过我们前面编写的按键消抖的文件和LED文件将按键和LED两个模块进行交互,从而达到按键控制LED的目的。
二、代码编写
1、首先是按键相关设计文件的编写,新建key.v,如下:
- //状态机实现
- module key (
- input clk ,
- input rst_n ,
- input key_in , //输入原始的按键信号
- output reg key_out //输出处理之后的按键信号
- );
- //参数定义
- localparam IDLE = 4'b0001,//空闲
- JITTLE0 = 4'b0010,//滤除第一次抖动
- DOWN = 4'b0100,//稳定
- JITTLE1 = 4'b1000;//滤除第二次抖动
-
- parameter TIME_20MS = 1_000_000;//需要计数的值,20ms
-
- //内部信号
- reg [3:0] state_c;//现态
- reg [3:0] state_n;//次态
-
- reg [19:0] cnt_20ms;//计数20ms
- wire add_cnt_20ms;
- wire end_cnt_20ms;
-
- wire nedge ;//下降沿信号
- wire pedge ;//上升沿信号
- reg key_in_r1 ;// 同步打拍
-
-
-
- //状态转移 同步时序逻辑描述状态转移
- always @(posedge clk or negedge rst_n) begin
- if(!rst_n)
- state_c <= IDLE;
- else
- state_c <= state_n;
- end
-
- //状态转移条件 组合逻辑
- always @(*) begin
- case (state_c)//一定是case 现态
- IDLE:begin
- if(nedge)
- state_n = JITTLE0;
- else
- state_n = state_c;
- end
- JITTLE0:begin
- if(end_cnt_20ms)
- state_n = DOWN;
- else
- state_n = state_c;
- end
- DOWN:begin
- if(pedge)
- state_n = JITTLE1;
- else
- state_n = state_c;
- end
- JITTLE1 :begin
- if(end_cnt_20ms)
- state_n = IDLE;
- else
- state_n = state_c;
- end
- default: state_n = IDLE;
- endcase
- end
-
- //20ms计数器
- always @(posedge clk or negedge rst_n) begin
- if(!rst_n)
- cnt_20ms <= 0;
- else if(add_cnt_20ms)begin
- if(end_cnt_20ms)
- cnt_20ms <= 0;
- else
- cnt_20ms <= cnt_20ms + 1;
- end
- end
-
- assign add_cnt_20ms = (state_c == JITTLE0) || (state_c == JITTLE1);
- assign end_cnt_20ms = add_cnt_20ms && cnt_20ms == TIME_20MS - 1;
-
- //下降沿 上升沿
- //同步 打拍
- always @(posedge clk or negedge rst_n)begin
- if(!rst_n)begin
- key_in_r1 <= 2'b11;
-
- end
- else begin
- key_in_r1 <= key_in; //同步按键输入信号
-
- end
- end
- //r1当前状态
- assign nedge = ~key_in_r1 && key_in;
- assign pedge = key_in_r1 && ~key_in;
-
- //key_out
- always @(posedge clk or negedge rst_n) begin
- if(!rst_n)
- key_out <= 0;
- else if(end_cnt_20ms &&(state_c== JITTLE1))
- key_out <= ~key_in_r1;//有效脉冲 20ns
- else
- key_out <= 0;
- end
-
- endmodule
2、LED相关设计文件编写
新建led_ctrl.v文件
- module led_ctrl(
- input clk ,
- input rst_n ,
- input key_flag ,//输入原始的按键信号
- output reg led //输出处理之后的按键信号
- );
- always @(posedge clk or negedge rst_n )begin
- if(!rst_n)
- led<=1'b0;
- else if(key_flag)
- led<=~led;
- end
- endmodule
3、顶层文件编写
在顶层文件中,使用一个中间变量key_out将按键中的输出赋值给LED模块中的按键标志位输入key_flag。
- module top(
- input clk,
- input rst_n,
- input key_in,
- output led
- );
- wire key_out;
- key key_inst(
- /*input */ .clk (clk ),
- /*input */ .rst_n (rst_n ),
- /*input */ .key_in (key_in), //输入原始的按键信号
- /*output reg */ .key_out (key_out) //输出处理之后的按键信号
- );
-
- led_ctrl led_inst(
- /*input */ .clk (clk ),
- /*input */ .rst_n (rst_n ),
- /*input */ .led (led), //输入原始的按键信号
- /*output reg */ .key_flag (key_out) //输出处理之后的按键信号
- );
- endmodule
4、测试文件编写
- `timescale 1ns/1ns
-
- module top_tb ;
-
- reg clk ;
- reg rst_n ;
- reg key_in ;
- wire led ;
-
- defparam top_inst.key_inst.TIME_20MS = 1000;
-
- top top_inst(
- .clk (clk ),
- .rst_n (rst_n ),
- .key_in (key_in ), //输入原始的按键信号
- .led (led ) //输出处理之后的按键信号
- );
- //激励信号产生
- parameter CLK_CLY = 20;
- //时钟
- initial clk=1;
- always #(CLK_CLY/2)clk=~clk;
-
- //复位
- initial begin
- rst_n= 1'b0;
- #(CLK_CLY*3);
- #5;//复位结束避开时钟上升沿
- rst_n= 1'b1;
- end
-
- //激励
- integer i;
- initial repeat(5)begin
- key_in = 1;//模拟按键未按下
- i ={$random}%6;//给i赋值0-5
- #(CLK_CLY*500);//等待复位时间结束
- #3;
- repeat (3)begin
- key_in = 0;//前按键抖动开始
- #(CLK_CLY*1);
- //一个5-10ms的抖动时间
- repeat ((i+5)*50)begin
- key_in = $random;
- #(CLK_CLY*1);
- end
- key_in = 0;//按键稳定
- #(CLK_CLY*100*50);
-
- //后抖动开始
- key_in = 1;
- #(CLK_CLY*1);
- repeat ((i+5)*50)begin
- key_in = $random;
- #(CLK_CLY*1);
- end
- key_in = 1;//按键稳定
- #(CLK_CLY*10*500);
- end
-
- //模拟意外抖动
- repeat (3)begin
- repeat ((i+5)*50)begin
- key_in = $random;
- #(CLK_CLY*1);
- end
- key_in = 1;//按键稳定
- #(CLK_CLY*500);
-
- end
- $stop;
- end
- endmodule
三、仿真波形图
通过波形图我们可以看见当按键按下一次,LED状态切换一次,实现了按键控制LED的功能实现。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。