基于FPGA的简易按键控制蜂鸣器发声

注意:本项目基于Altera开发版开发

项目要求:

如下图模块所示,输入时钟为板载的50Mhz时钟信号,key1~key4为板卡输入的按键信号,程序实现当任意1个按键按下后,蜂鸣器顺序演奏7个音符,每个音符持续时间为0.5秒,7音符演奏完成后停止演奏,如果继续按下任意按键,再次开始演奏,演奏完成就停止演奏。要求按键消抖模块与蜂鸣器控制的模块均使用锁相环输出的100Mhz时钟工作,所以设计锁相环IP核来满足这个要求

接下来是拿到项目要求后进行思路分析:

理清楚思路后开始创建工程进行编写代码:

对于pll锁相环部分简单设置成输入为50MHZ(板卡频率时钟)输出为100MHZ即可:

按键消抖模块:

按键消抖模块思路前面已经写过,这里不在叙述,主要是留意计数器的计数值和位宽即可


module key_xd(
    input  wire                       clk                        ,
    input  wire                       rst_n                      ,
    input  wire                       key_in                     ,
    output reg                        flag_key
  );
  //---------------------------------------------------------------------------------------
  // 基于100Mhz的计数器20ms
  //---------------------------------------------------------------------------------------
  parameter                         MAX_20ms                  = 'd1_999_999;
  reg                [  20: 0]      ms20_cnt                   ;
  always @(posedge clk or negedge rst_n)
  begin
    if(!rst_n)
      ms20_cnt <= 'd0   ;
    else if(key_in)
      ms20_cnt <= 0;
    else if(ms20_cnt >= MAX_20ms )
      ms20_cnt <= MAX_20ms  ;
    else
      ms20_cnt <= ms20_cnt + 1'b1;
  end

  //---------------------------------------------------------------------------------------
  // 在按键输入时,生成一个flag
  //---------------------------------------------------------------------------------------
  always @(posedge clk or negedge rst_n)
  begin
    if(!rst_n)
      flag_key <= 0;
    else if( !key_in && ms20_cnt == MAX_20ms -1 )
      flag_key <= 1;
    else
      flag_key <= 0;
  end

endmodule
蜂鸣器控制发声模块:

个人建议先把蜂鸣器发声模块理清思路后再加入按键进行控制发声。我们会发现,把按键加在计数7个音符的代码处是最合适的,因为按键控制的就是音符发声顺序,DO--RE--..--XI,所以我们只需要当按键信号有效时,将音符计数器清零,让蜂鸣器发声,当音符响过后,保持没有声音即可(这个方法有很多,比如给按键到来时加一个使能信号,使能信号有效时,计数器才工作,才让蜂鸣器发声),这里我采用代码更加简洁的办法。

在7个音符计数器的基本上再加一个音符:空音符,当按键按下时,音符计数器清零,并且会自加,达到最大值时,让其保持最大值(空音符)即可。这样就实现了蜂鸣器不发声的情况。当然此时为了避免板卡上电后蜂鸣器会直接发声,所以我们要把音符计数器的初值设为最大值即可。代码如下:


module beep_music(
    input  wire                       clk                        ,
    input  wire                       rst_n                      ,
    input  wire        [   3: 0]      flag_key                   ,
    output reg                        beep_out                    
  );

  //---------------------------------------------------------------------------------------
  // 基于100Mhz计数500ms
  //---------------------------------------------------------------------------------------
    parameter                         MAX_500ms                 = 49_999_999;
    reg                [  25: 0]      ms500_cnt                  ;
  always @(posedge clk or negedge rst_n)
  begin
    if(!rst_n)
      ms500_cnt <= 'd0   ;
    else if(ms500_cnt >= MAX_500ms )
      ms500_cnt <= 0  ;
    else
      ms500_cnt <= ms500_cnt + 1'b1;
  end

  //---------------------------------------------------------------------------------------
  //    7个音符频率
  //---------------------------------------------------------------------------------------
    parameter                         DO                        = 100_000_000/262;
    parameter                         RE                        = 100_000_000/294;
    parameter                         MI                        = 100_000_000/330;
    parameter                         FA                        = 100_000_000/349;
    parameter                         SO                        = 100_000_000/392;
    parameter                         LA                        = 100_000_000/440;
    parameter                         XI                        = 100_000_000/494;

  //---------------------------------------------------------------------------------------
  // 计数7个数(题目要求只响一次就停止)那就计数9个--第一个和最后一个为空,计数到最大值后保持--等待下次再次触发
  //---------------------------------------------------------------------------------------
    reg                [   3: 0]      g_cnt                      ;
  always @(posedge clk or negedge rst_n)
  begin
    if(!rst_n)
      g_cnt <= 'd8   ;
    else if(flag_key)
        g_cnt <= 0;
    else if(g_cnt >= 'd8 && ms500_cnt >= MAX_500ms)
      g_cnt <= 'd8  ;
    else  if(ms500_cnt >= MAX_500ms)
      g_cnt <= g_cnt + 1'b1;   
  end

  //---------------------------------------------------------------------------------------
  // 用case语句进行赋值
  //---------------------------------------------------------------------------------------
    reg                [  18: 0]      frq                        ;
  always @(posedge clk or negedge rst_n)
  begin
    if(!rst_n)
      frq <= 0;
    else
      
    case (g_cnt)
      0 :
        frq <= 0;
      1 :
        frq <= DO;
      2 :
        frq <= RE;
      3 :
        frq <= MI;
      4 :
        frq <= FA;
      5 :
        frq <= SO;
      6 :
        frq <= LA;
      7 :
        frq <= XI;
      8 :
        frq <= 0;
      default:
        frq <= 0;
    endcase
  end

  //---------------------------------------------------------------------------------------
  // 占空比50%
  //---------------------------------------------------------------------------------------
    wire               [  18: 0]      duty                       ;
    assign                            duty                      = frq >>1;

  //---------------------------------------------------------------------------------------
  // 进行频率计数
  //---------------------------------------------------------------------------------------
    reg                [  18: 0]      frq_cnt                    ;
  always @(posedge clk or negedge rst_n)
  begin
    if(!rst_n)
      frq_cnt <= 'd0   ;
    else if(frq_cnt >= frq || ms500_cnt >= MAX_500ms  )
      frq_cnt <= 0  ;
    else
      frq_cnt <= frq_cnt + 1'b1;
  end

  //---------------------------------------------------------------------------------------
  //   让蜂鸣器发声
  //---------------------------------------------------------------------------------------
  always @(posedge clk or negedge rst_n)
  begin
    if(!rst_n)
      beep_out <= 0;
    else if(frq_cnt >= duty )
      beep_out <= 1;
    else
      beep_out <= 0;
  end


endmodule

 

#### 接下来就是顶层模块的编写:

顶层模块由一个pll锁相环,4个按键消抖和一个蜂鸣器发声。只需要将其用先连接起开即可


module top(
    input  wire                       clk_50M                    ,

    input  wire                       key_in1                    ,
    input  wire                       key_in2                    ,
    input  wire                       key_in3                    ,
    input  wire                       key_in4                    ,

    output                            beep                        
  );
    wire                              clk                        ;
    wire               [   3: 0]      flag_key                   ;
    wire                              locked                     ;


  pll_key_beep    pll_key_beep_inst (
    .inclk0                           (clk_50M                   ),
    .c0                               (clk                       ),
    .locked                           (locked                     ) 
                  );

  key_xd u_key_xd_1(
    .clk                              (clk                       ),
    .rst_n                            (locked                    ),
    .key_in                           (key_in1                   ),
    .flag_key                         (flag_key[0]               ) 
         );

  key_xd u_key_xd_2(
    .clk                              (clk                       ),
    .rst_n                            (locked                    ),
    .key_in                           (key_in2                   ),
    .flag_key                         (flag_key[1]               ) 
         );

  key_xd u_key_xd_3(
    .clk                              (clk                       ),
    .rst_n                            (locked                    ),
    .key_in                           (key_in3                   ),
    .flag_key                         (flag_key[2]               ) 
         );

  key_xd u_key_xd_4(
    .clk                              (clk                       ),
    .rst_n                            (locked                    ),
    .key_in                           (key_in4                   ),
    .flag_key                         (flag_key[3]               ) 
         );



  beep_music u_beep_music(
    .clk                              (clk                       ),
    .rst_n                            (locked                    ),
    .flag_key                         (flag_key                  ),
    .beep_out                         (beep                      ) 
             );

endmodule

其中clk_50M是板卡50MHZ,clk在代码内是100MHZ。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值