完整代码下载:
正确程序段.docx
(31.06 KB, 下载次数: 14)
在FPGA 中,基于下面的程序,理解如下:在这个程序里检测按键是否按下的方法是脉冲边沿检法。第一次检测到后,启动20ms计数器,时间到后再检测。这里的检测方法跟脉冲边沿检测法有异曲同工之处,FPGA过20ms检测按键是否按下,存储检测到的值,并且按位取反与前一个20ms检测的值相与,得到一个值,如果为1,则判断按键按下,否则则无按下。 FPGA按键的理解示意图 其中key_an寄存器的功能是检测第一次的“按下”,是cnt的启动标志位。通过也能滤除干扰信号。led_ctrl是确实有按键按下的信号,维持一个时钟周期。
`timescale 1ns/1ns module sw_xiaodou( clk, rst_n, sw1_n, sw2_n, sw3_n, sw4_n, //output led_d1, led_d2, led_d3, led_d4 ); input clk; //主时钟信号50MHz input rst_n; //复位信号低有效。可将其绑为开关开关拨下有效。 input sw1_n,sw2_n,sw3_n,Sw4_n; //三个独立按键低表示按下 output led_d1,led_d2,led_d3,led_d4; //发光二极管分别由按键控制
// ----------------------------------------------------------------
reg[3:0] key_rst;
always @(posedge clk or negedge rst_n)
if (!rst_n) key_rst <= 4'b1111;
else key_rst <= {sw4_n,sw3_n,sw2_n,sw1_n};
reg[3:0] key_rst_r; //每个时钟周期的上升沿将low_sw信号锁存到low_sw_r中
always @ ( posedge clk or negedge rst_n )
if (!rst_n) key_rst_r <= 4'b1111;
else key_rst_r <= key_rst;
//当寄存器key_rst由1变为0时,key_an的值变为高,维持一个时钟周期
wire[3:0] key_an = key_rst_r & ( ~key_rst); //检测到按下的第一次(cnt的启动信号)
reg [19:0] cnt; //计数寄存器 always @ (posedge clk or negedge rst_n)/*always块 clk时钟的上升沿 和rst_n复位信号的下降沿触发执行*/ if (!rst_n) /*异步复位rst_n为低电平即rst_n为高电平时。*/ cnt <= 20'd0;/*cnt付初值为0*/ else if(key_an) cnt <=20'd0; else cnt <= cnt + 1'b1;/*cnt计数器自加1*/
reg [3:0] low_sw; always @(posedge clk or negedge rst_n)/*同上一个always*/ if (!rst_n) low_sw <= 4'b1111;/*赋初值为1111*/ else if (cnt == 20'hfffff) /*满20ms将按键值锁存到寄存器low_sw 中20‘hfffff=’d1048575 t=1/48000000*1048575=0.021s*/ low_sw <= {sw4_n,sw3_n,sw2_n,sw1_n};/*将按键sw3_n.sw2_n,sw1_n,用位拼 接符{ }拼接为一个三位的数传给low_sw*/
// ---------------------------------------------------------------------------
reg [3:0] low_sw_r; /*每个时钟周期的上升沿将low_sw信号锁存到low_sw_r中*/ always @ ( posedge clk or negedge rst_n ) if (!rst_n) low_sw_r <= 4'b1111;/*初值为1111*/ else low_sw_r <= low_sw;
/*当寄存器low_sw由1变为0时led_ctrl的值变为高维持一个时钟周期 */ wire [3:0] led_ctrl = low_sw_r[3:0] & ( ~low_sw[3:0]);/*找出变化的键存到led_ctrl中*/
reg d1; reg d2; reg d3; reg d4; always @ (posedge clk or negedge rst_n) if (!rst_n) begin d1 <= 1'b0; d2 <= 1'b0; d3 <= 1'b0; d4 <= 1'b0; end else begin //某个按键值变化时LED将做亮灭翻转 if ( led_ctrl[0] ) d1 <= ~d1; if ( led_ctrl[1] ) d2 <= ~d2; if ( led_ctrl[2] ) d3 <= ~d3; if ( led_ctrl[3] ) d4<= ~d4; end
assign led_d4 = d1 ? 1'b1 : 1'b0; //LED翻转输出 assign led_d3 = d2 ? 1'b1 : 1'b0; assign led_d2 = d3 ? 1'b1 : 1'b0; assign led_d1 = d4 ? 1'b1 : 1'b0; endmodule
|