基于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 

 

参考文献:

(1)陪您一起学习FPGA-郝旭帅团队_哔哩哔哩_bilibili

posted @ 2021-08-10 22:12  豌豆茶  阅读(331)  评论(0编辑  收藏  举报