基于FPGA的按键提示音设计
1. 设计要求
按键按下,蜂鸣器要“叮”一声。
2. 设计分析
该设计方案采用野火征途MiNi FPGA开发板(intel-Cyclone IV -EP4CE10F17C8)实现,利用开发板的按键做输入设备,无源蜂鸣器做输出设备。硬件连接图如下图所示:
开发板晶振为50MHz,提供系统时钟信号,复位按键按下为低电平,弹起为高电平。无源蜂鸣器采用10KHz的方便驱动,每次发出声音的时间为0.1s。
(1)顶层模块设计
端口及其含义:
- clk_50M:系统时钟,50MHz;
- rst_n: 系统复位信号,低电平有效;
- key_in: 按键输入信号
- beep: 蜂鸣器驱动信号。
(2)架构设计
根据系统功能描述,该系统可由按键消抖模块、边沿检测模块和蜂鸣器驱动模块组成,按键消抖模块负责对按键进行消抖操作,当边沿检测模块检测到按键按下时,会产出一个周期高电平的脉冲信号key_flag,利用该脉冲产出一个长度为0.1s方波信号,驱动蜂鸣器发声。
3. 设计实现
(1)按键消抖模块的设计与实现
1 module key_filter( 2 input wire clk, 3 input wire rst_n, 4 input wire key_n, 5 6 output reg key_out 7 ); 8 9 localparam IDLE = 4'b0001; 10 localparam FILTER0 = 4'b0010; 11 localparam DOWN = 4'b0100; 12 localparam FILTER1 = 4'b1000; 13 14 parameter T_10MS = 19'd500_000; 15 16 reg key_n_r; 17 reg key_n_rr; 18 reg [3:0] c_state; 19 reg [3:0] n_state; 20 reg [18:0] cnt; 21 22 always@(posedge clk)begin 23 key_n_r <= key_n; 24 key_n_rr <= key_n_r; 25 end 26 27 always@(posedge clk or negedge rst_n)begin 28 if(rst_n == 1'b0) 29 c_state <= IDLE; 30 else 31 c_state <= n_state; 32 end 33 34 always@(*)begin 35 case(c_state) 36 IDLE : begin 37 if(key_n_rr == 1'b0) 38 n_state = FILTER0; 39 else 40 n_state = IDLE; 41 end 42 43 FILTER0 : begin 44 if(key_n_rr == 1'b1) 45 n_state = IDLE; 46 else 47 if(cnt < T_10MS - 1'b1) 48 n_state = FILTER0; 49 else 50 n_state = DOWN; 51 end 52 53 DOWN : begin 54 if(key_n_rr == 1'b0) 55 n_state = DOWN; 56 else 57 n_state = FILTER1; 58 end 59 60 FILTER1 : begin 61 if(key_n_rr == 1'b0) 62 n_state = DOWN; 63 else 64 if(cnt < T_10MS - 1'b1) 65 n_state = FILTER1; 66 else 67 n_state = IDLE; 68 end 69 default : n_state = IDLE; 70 endcase 71 end 72 73 always@(posedge clk or negedge rst_n)begin 74 if(rst_n == 1'b0) 75 cnt <= 19'd0; 76 else begin 77 case(c_state) 78 IDLE : cnt <= 19'd0; 79 80 FILTER0 : begin 81 if(key_n_rr == 1'b1) 82 cnt <= 19'd0; 83 else 84 if(cnt < T_10MS - 1'b1) 85 cnt <= cnt + 1'b1; 86 else 87 cnt <= 19'd0; 88 end 89 90 DOWN : cnt <= 19'd0; 91 92 FILTER1 : begin 93 if(key_n_rr == 1'b0) 94 cnt <= 19'd0; 95 else 96 if(cnt < T_10MS - 1'b1) 97 cnt <= cnt + 1'b1; 98 else 99 cnt <= 19'd0; 100 end 101 default : cnt <= 19'd0; 102 endcase 103 end 104 end 105 106 always@(posedge clk or negedge rst_n)begin 107 if(rst_n == 1'b0) 108 key_out <= 1'b1; 109 else 110 if(c_state == DOWN || c_state == FILTER1) 111 key_out <= 1'b0; 112 else 113 key_out <= 1'b1; 114 end 115 116 endmodule
(2)边沿检测模块的设计与实现
1 module edge_check( 2 input wire clk_50M, 3 input wire rst_n, 4 input wire key_out, 5 6 output wire key_flag 7 ); 8 9 reg key_out_reg; 10 11 always@(posedge clk_50M or negedge rst_n)begin 12 if(rst_n == 1'b0) 13 key_out_reg <= 1'b0; 14 else 15 key_out_reg <= key_out; 16 end 17 18 assign key_flag = key_out_reg && (~key_out); 19 20 endmodule
(3)蜂鸣器驱动模块的设计与实现
1 module beep_drive( 2 input wire clk_50M, 3 input wire rst_n, 4 input wire key_flag, 5 6 output wire beep 7 ); 8 9 parameter FREQ = 10_000; 10 parameter HALF = 50_000_000/(2*FREQ); 11 parameter T_100MS = 5_000_000; 12 13 reg [25:0] cnt; 14 reg wave_10k; 15 reg [25:0] count; 16 wire valid; 17 18 always@(posedge clk_50M or negedge rst_n)begin 19 if(rst_n == 1'b0) 20 cnt <= 26'd0; 21 else 22 if(cnt < HALF - 1'b1) 23 cnt <= cnt + 1'b1; 24 else 25 cnt <= 26'd0; 26 end 27 28 always@(posedge clk_50M or negedge rst_n)begin 29 if(rst_n == 1'b0) 30 wave_10k <= 1'b0; 31 else 32 if(cnt == HALF -1'b1) 33 wave_10k <= ~wave_10k; 34 else 35 wave_10k <= wave_10k; 36 end 37 38 always@(posedge clk_50M or negedge rst_n)begin 39 if(rst_n == 1'b0) 40 count <= T_100MS; 41 else 42 if(key_flag == 1'b1) 43 count <= 26'd0; 44 else if(count < T_100MS) 45 count <= count + 1'b1; 46 else 47 count <= count; 48 end 49 50 assign valid = (count < T_100MS) ? 1'b1 : 1'b0; 51 52 assign beep = wave_10k && valid; 53 54 endmodule
1 `timescale 1ns/1ps 2 3 module beep_drive_tb(); 4 reg clk_50M; 5 reg rst_n; 6 reg key_flag; 7 8 wire beep; 9 10 defparam beep_drive_inst.T_100MS = 500; 11 defparam beep_drive_inst.FREQ = 1000_000; 12 13 beep_drive beep_drive_inst( 14 .clk_50M (clk_50M), 15 .rst_n (rst_n), 16 .key_flag (key_flag), 17 18 .beep (beep) 19 ); 20 21 initial clk_50M = 1'b0; 22 always #10 clk_50M = ~clk_50M; 23 24 initial begin 25 rst_n = 1'b0; key_flag = 1'b0; 26 #201; 27 rst_n = 1'b1; 28 repeat(5)begin 29 @(posedge clk_50M); #2; 30 key_flag = 1'b1; 31 @(posedge clk_50M); #2; 32 key_flag = 1'b0; 33 #(20*1000); 34 end 35 #500;$stop; 36 end 37 38 endmodule
参考文献: