赞
踩
`timescale 1ns / 1ps
// Module Function:按键消抖
module debounce_button (clk,rst,key,key_pulse,en, data_i, data_o,dout);
parameter N = 1; //要消除的按键的数量
input clk;
input rst;
input [N-1:0] key; //输入的按键
output [N-1:0] key_pulse; //按键动作产生的脉冲
input en;
input [7:0] data_i;
output data_o,dout;
reg [N-1:0] key_rst_pre; //定义一个寄存器型变量存储上一个触发时的按键值
reg [N-1:0] key_rst; //定义一个寄存器变量储存储当前时刻触发的按键值
wire [N-1:0] key_edge; //检测到按键由高到低变化是产生一个高脉冲
//利用非阻塞赋值特点,将两个时钟触发时按键状态存储在两个寄存器变量中
always @(posedge clk or negedge rst)
begin
if (rst) begin
key_rst <= {N{1'b1}}; //初始化时给key_rst赋值全为1,{}中表示N个1
key_rst_pre <= {N{1'b1}};
end
else begin
key_rst <= key; //第一个时钟上升沿触发之后key的值赋给key_rst,同时key_rst的值赋给key_rst_pre
key_rst_pre <= key_rst; //非阻塞赋值。相当于经过两个时钟触发,key_rst存储的是当前时刻key的值,key_rst_pre存储的是前一个时钟的key的值
end
end
assign key_edge = key_rst_pre & (~key_rst);//脉冲边沿检测。当key检测到下降沿时,key_edge产生一个时钟周期的高电平
reg [17:0] cnt; //产生延时所用的计数器,系统时钟12MHz,要延时20ms左右时间,至少需要18位计数器
//产生20ms延时,当检测到key_edge有效是计数器清零开始计数
always @(posedge clk or negedge rst)
begin
if(rst)
cnt <= 18'h0;
else if(key_edge)
cnt <= 18'h0;
else
cnt <= cnt + 1'h1;
end
reg [N-1:0] key_sec_pre; //延时后检测电平寄存器变量
reg [N-1:0] key_sec;
//延时后检测key,如果按键状态变低产生一个时钟的高脉冲。如果按键状态是高的话说明按键无效
always @(posedge clk or negedge rst)
begin
if (rst)
key_sec <= {N{1'b1}};
else if (cnt==18'h3ffff)
key_sec <= key;
end
always @(posedge clk or negedge rst)
begin
if (rst)
key_sec_pre <= {N{1'b1}};
else
key_sec_pre <= key_sec;
end
assign key_pulse = key_sec_pre & (~key_sec); //在产生一个时钟的高脉冲后,传入parallel_serial的clk中,计数,往后读取并行的输入数据
parallel_serial u1(
.clk(key_pulse), .reset(rst), .en(en), .data_i(data_i), .data_o(data_o),.dout(dout)/*,.clk_real()*/
);
endmodule
`timescale 1ns / 1ps
module parallel_serial(
clk, reset, en, data_i, data_o,dout/*,clk_real*/
);
input clk, reset,en;
input [7:0] data_i;
output data_o,dout;
//input clk_real;
reg [7:0] data_buf;
localparam N = 3; //使用低16位对50Mhz的时钟进行分频(50MHZ/2^16)
reg [N-1:0] regN; //高两位作为控制信号,低16位为计数器,对时钟进行分频
/*reg flag;
always @ (posedge clk_real)
begin
flag <=clk;
end
*/
always@(posedge clk, posedge reset)
begin
if(reset) //FPGA板上配有 5 个按键,当按键按下时,表示 FPGA 的相应输入脚为高电平。所以平时的状态为低电平,即按键是未按下的 “弹起” 状态。
regN <= 0;
else
regN <= regN + 1;
end
always@(posedge clk or negedge reset)
if(reset)
data_buf <= 8'b0;
else if(en)
/*当en=0时,regN只能计数,不能执行以下传输代码,即不能改变data_buf的值了,不能再往seq_det_moore中传入下一个data_o了,
但是seq_det_moore还是会随着clk的进行,而继续检索1101序列,此时data_o的值是之前传入的值,不变。
只有在en=1后的下一次posedge clk时,才可以继续传输值*/
begin
case(regN[N-1:N-3])
3'b0: data_buf <= data_i[7:0];
3'b1: data_buf <= {data_i[6:0],data_i[7]};
3'd2: data_buf <= {data_i[5:0],data_i[7:6]};
3'd3: data_buf <= {data_i[4:0],data_i[7:5]};
3'd4: data_buf <= {data_i[3:0],data_i[7:4]};
3'd5: data_buf <= {data_i[2:0],data_i[7:3]};
3'd6: data_buf <= {data_i[1:0],data_i[7:2]};
3'd7: data_buf <= {data_i[0],data_i[7:1]};
default: data_buf <= data_i[7:0];
endcase
end
assign data_o = data_buf[7];
seq_det_moore u1(
.clk(clk),
.reset(reset),
.din(data_o),//每按一次模拟 clk 的按键便传入一个开关的值
.dout(dout)
);
endmodule
`timescale 1ns / 1ps
module seq_det_moore(
input clk,
input reset,
input din,
output reg dout
);
//状态声明
localparam [2:0]
s0 = 3'b000,
s1 = 3'b001,
s2 = 3'b010,
s3 = 3'b011,
s4 = 3'b100;
reg [2:0] current_state,next_state;
always @(posedge clk, posedge reset)
begin
if(reset) //FPGA板上配有 5 个按键,当按键按下时,表示 FPGA 的相应输入脚为高电平。所以平时的状态为低电平,即按键是未按下的 "弹起" 状态。
current_state <= s0;
else
current_state <= next_state;
end
always @ *
begin
case(current_state)
s0:
if(din == 1'b1) next_state = s1;
else next_state = s0;
s1:
if(din == 1'b1) next_state = s2;
else next_state = s0;
s2:
if(din == 1'b0) next_state = s3;
else next_state = s2;
s3:
if(din == 1'b1) next_state = s4;
else next_state = s0;
s4:
if(din == 1'b1) next_state = s1;
else next_state = s0;
default: next_state = s0;
endcase
end
always @*
begin
if(next_state == s4) dout = 1;
else dout = 0;
end
endmodule
`timescale 1ns / 1ps
module parallel_serial_tb;
reg clk,reset,en;
wire data_o;
wire dout;
reg [7:0] data_i;
// Note: CLK must be defined as a reg when using this method
parameter PERIOD = 10;
always begin
#(PERIOD/2) clk = ~clk;
end
initial begin
clk = 0;
reset = 1'b1;
@(posedge clk) reset = 1'b0;
en=1'b1;
data_i = 8'b11011101;
end
parallel_serial u1(
.clk(clk), .reset(reset), .en(en), .data_i(data_i), .data_o(data_o) , .dout(dout)
);
endmodule
set_property IOSTANDARD LVCMOS33 [get_ports {data_i[7]}]
set_property IOSTANDARD LVCMOS33 [get_ports {data_i[6]}]
set_property IOSTANDARD LVCMOS33 [get_ports {data_i[5]}]
set_property IOSTANDARD LVCMOS33 [get_ports {data_i[4]}]
set_property IOSTANDARD LVCMOS33 [get_ports {data_i[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {data_i[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {data_i[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {data_i[0]}]
set_property PACKAGE_PIN W13 [get_ports {data_i[7]}]
set_property PACKAGE_PIN W14 [get_ports {data_i[6]}]
set_property PACKAGE_PIN V15 [get_ports {data_i[5]}]
set_property PACKAGE_PIN W15 [get_ports {data_i[4]}]
set_property PACKAGE_PIN W17 [get_ports {data_i[3]}]
set_property PACKAGE_PIN W16 [get_ports {data_i[2]}]
set_property PACKAGE_PIN V16 [get_ports {data_i[1]}]
set_property PACKAGE_PIN V17 [get_ports {data_i[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports clk]
set_property IOSTANDARD LVCMOS33 [get_ports data_o]
set_property IOSTANDARD LVCMOS33 [get_ports dout]
set_property IOSTANDARD LVCMOS33 [get_ports en]
set_property PACKAGE_PIN R2 [get_ports en]
set_property PACKAGE_PIN E19 [get_ports data_o]
set_property PACKAGE_PIN U16 [get_ports dout]
set_property IOSTANDARD LVCMOS33 [get_ports {key[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {key_pulse[0]}]
set_property PACKAGE_PIN W5 [get_ports clk]
set_property IOSTANDARD LVCMOS33 [get_ports rst]
set_property PACKAGE_PIN U18 [get_ports rst]
set_property PACKAGE_PIN T17 [get_ports {key[0]}]
set_property PACKAGE_PIN L1 [get_ports {key_pulse[0]}]
我用的板子是XILINX的BASYS 3
上板子的实验输入按键。(注意最左边的是en按键,要赋为1才能进行检测)
(=.=点击这里查看上板实验操作演示的视频哦=.=)
https://www.wpsshop.cn/w/Cpp五条/article/detail/676637
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。