zoukankan      html  css  js  c++  java
  • 基于FPGA的音乐蜂鸣器设计

          蜂鸣器是一种一体化结构的电子讯响器,采用直流电压供电,广泛应用于计算机、打印机、复印机、报警器、电子玩具、汽车电子设备、电话机、定时器等电子产品中作发声器件。

     

    图1 :蜂鸣器实物图

    蜂鸣器主要分为压电式蜂鸣器和电磁式蜂鸣器两种类型。

        压电式蜂鸣器 压电式蜂鸣器主要由多谐振荡器、压电蜂鸣片、阻抗匹配器及共鸣箱、外壳等组成。有的压电式蜂鸣器外壳上还装有发光二极管。多谐振荡器由晶体管或集成电路构成。当接通电源后(1.5~15V直流工作电压),多谐振荡器起振,输出1.5~2.5kHZ的音频信号,阻抗匹配器推动压电蜂鸣片发声。

        电磁式蜂鸣器电磁式蜂鸣器由振荡器、电磁线圈、磁铁、振动膜片及外壳等组成。接通电源后,振荡器产生的音频信号电流通过电磁线圈,使电磁线圈产生磁场。振动膜片在电磁线圈和磁铁的相互作用下,周期性地振动发声。

        按照内部有无震荡源可以分为有源蜂鸣器和无源蜂鸣器。有源蜂鸣器内部带震荡源,所以只要一通电就会发出声音;而无源内部不带震荡源,所以如果用直流信号无法令其鸣叫。必须用一定频率的方波去驱动它。

        首先设计分频器,设计一个1KHz的方波,驱动蜂鸣器,观测蜂鸣器是否会有声音产生。

        本小节研究如何利用蜂鸣器演唱一首曲子《世上只有妈妈好》。

        下图为《世上只有妈妈好》的简谱。

     

    图2:世上只有妈妈好的简谱

        简谱是一种比较简单易学的音乐记谱法。据说简谱是由法国思想家卢梭于1742年发明的。而最早把简谱引进我国的是我国近代音乐教育家沈心工。简谱应该说是一种比较简单易学的音乐记谱法。它的最大好处是仅用7个阿拉伯数字----1234567,就能将万千变化的音乐曲子记录并表示出来.

        在简谱中,用以表示音的高低及相互关系的基本符号为七个阿拉伯数字,即1、2、3、4、5、6、7,唱作do、re、mi、fa、sol、la、si,称为唱名。

    音符:1234567

    唱名:do re mi fa sol la si

    汉字:哆来米发梭拉西

    显然,单用以上七个音是无法表现众多的音乐形象的。在实际作品中,还有一些更高或更低的音,如在基本音符上方加记一个"·",表示该音升高一个八度,称为高音;加记两个" :",则表示该音升高两个八度,称为倍高音。在基本音符下方加记一个"·",表示该音降低一个八度,称为低音;加记两个" :",则表示该音降低两个八度,称为倍低音。

    在一般歌曲中,无论是在基本音符上方或下方加记两个以上的"·"的音符都是很少见的。

        在简谱中,1、2、3、4、5、6、7这七个基本音符,不仅表示音的高低,而且还是表示时值长短的基本单位,称为四分音符,其他音符均是在四分音符的基础上,用加记短横线"-"和附点"·"表示。

        在基本音符右侧加记一条短横线,表示增长一个四分音符的时值。这类加记在音符右侧、使音符时值增长的短横线,称为增时线。增时线越多,音符的时值越长。

        在基本音符下方加记一条短横线,表示缩短原音符时值的一半。这类加记在音符下方、使音符时值缩短的短横线,称为减时线。减时线越多,音符的时值越短。

        在简谱中,加记在单纯音符的右侧的、使音符时值增长的小圆点"·",称为附点。加记附点的音符称为附点音符。附点本身并无一定的长短,其长短由前面的单纯音符来决定。附点的意义在于增长原音符时值的一半,常用于四分音符和小于四分音符的各种音符之后。

        在《世上只有妈妈好》的简谱中,每两个竖线之间为2秒钟的时长。每两个竖线之间有4个音符时长,但是其中有较多半个音符的长,本设计采用1/4秒为基本单位。

    蜂鸣器给予不同的频率是可以发出近似1、2、3、4、5、6、7这七个基本音符。

     

    图3 :各个音符所对应的频率

    此模块命名为music_beep,clk为50MHz的时钟,rst_n为低电平有效的复位,beep为蜂鸣器的驱动信号。

    图4 :music_beep的模型

    在设计时,首先将简谱中的音符存起来;利用计数器产生1/4秒为周期的脉冲,在此脉冲驱动下,将事先存好的音符一个个输出;根据音符的值,计算出分频比;根据分频比,产生对应频率的波形。将此波形输出即可。

     

    图5 :架构图

       

    在进行多模块设计时,可以对每个模块只设计端口,将架构完成后。再分别设计每个模块。

        《世上只有妈妈好》的简谱中共有8个四拍,每个四拍我们用8个音符来表示,合计共64个音符。在speed_ctrl中,输出的cnt为6位,正好可以表示64个状态。

        在speed_ctrl中,每1/8秒让cnt增加1即可。

    module speed_ctrl (

      input   wire            clk,

      input   wire            rst_n,

     

      output  reg   [5:0]     cnt

    );

      parameter T_250ms   =   12_500_000;

     

      reg           [25:0]    count;

      wire                    flag_250ms;

     

      always @ (posedge clk, negedge rst_n) begin

        if (rst_n == 1'b0)

          count <= 26'd0;

        else

          if (count < T_250ms - 1'b1)

            count <= count + 1'b1;

          else

            count <= 26'd0;

      end

      assign flag_250ms = (count == T_250ms - 1'b1) ? 1'b1 : 1'b0;

       

      always @ (posedge clk, negedge rst_n) begin

        if (rst_n == 1'b0)

          cnt <= 6'd0;

        else

          if (flag_250ms == 1'b1)

            cnt <= cnt + 1'b1;

          else

            cnt <= cnt;

      end

    endmodule

    图6:speed_ctrl的设计代码

        在music_mem中存储音符,存储方式为低音用1到7表示,中音用8到14表示,高音用15到21表示,music为5bit位宽。

    module music_mem (

      input   wire            clk,

      input   wire            rst_n,

     

      input   wire    [5:0]   cnt,

     

      output  reg     [4:0]   music

    );

    // 1  2  3  4  5  6  7

    // 8  9  10 11 12 13 14

    // 15 16 17 18 19 20 21

     

      always @ (posedge clk, negedge rst_n) begin

        if (rst_n == 1'b0)

          music <= 5'd0;

        else

          case (cnt)

            6'd0    :   music <= 5'd13;

            6'd1    :   music <= 5'd13;

            6'd2    :   music <= 5'd13;

            6'd3    :   music <= 5'd12;

            6'd4    :   music <= 5'd10;

            6'd5    :   music <= 5'd10;

            6'd6    :   music <= 5'd12;

            6'd7    :   music <= 5'd12;

           

            6'd8    :   music <= 5'd15;

            6'd9    :   music <= 5'd15;

            6'd10   :   music <= 5'd13;

            6'd11   :   music <= 5'd12;

            6'd12   :   music <= 5'd13;

            6'd13   :   music <= 5'd13;

            6'd14   :   music <= 5'd13;

            6'd15   :   music <= 5'd13;

           

            6'd16   :   music <= 5'd10;

            6'd17   :   music <= 5'd10;

            6'd18   :   music <= 5'd12;

            6'd19   :   music <= 5'd13;

            6'd20   :   music <= 5'd12;

            6'd21   :   music <= 5'd12;

            6'd22   :   music <= 5'd10;

            6'd23   :   music <= 5'd10;

           

            6'd24   :   music <= 5'd8;

            6'd25   :   music <= 5'd6;

            6'd26   :   music <= 5'd12;

            6'd27   :   music <= 5'd10;

            6'd28   :   music <= 5'd9;

            6'd29   :   music <= 5'd9;

            6'd30   :   music <= 5'd9;

            6'd31   :   music <= 5'd9;

           

            6'd32   :   music <= 5'd9;

            6'd33   :   music <= 5'd9;

            6'd34   :   music <= 5'd9;

            6'd35   :   music <= 5'd10;

            6'd36   :   music <= 5'd12;

            6'd37   :   music <= 5'd12;

            6'd38   :   music <= 5'd13;

            6'd39   :   music <= 5'd13;

            

            6'd40   :   music <= 5'd10;

            6'd41   :   music <= 5'd10;

            6'd42   :   music <= 5'd10;

            6'd43   :   music <= 5'd9;

            6'd44   :   music <= 5'd8;

            6'd45   :   music <= 5'd8;

            6'd46   :   music <= 5'd8;

            6'd47   :   music <= 5'd8;

           

            6'd48   :   music <= 5'd12;

            6'd49   :   music <= 5'd12;

            6'd50   :   music <= 5'd12;

            6'd51   :   music <= 5'd10;

            6'd52   :   music <= 5'd9;

            6'd53   :   music <= 5'd8;

            6'd54   :   music <= 5'd6;

            6'd55   :   music <= 5'd8;

           

            6'd56   :   music <= 5'd5;

            6'd57   :   music <= 5'd5;

            6'd58   :   music <= 5'd5;

            6'd59   :   music <= 5'd5;

            6'd60   :   music <= 5'd5;

            6'd61   :   music <= 5'd5;

            6'd62   :   music <= 5'd5;

            6'd63   :   music <= 5'd5;

            default  :   music <= 5'd0;

          endcase

      end

    endmodule

    图7 :music_mem的设计代码

        根据频率和音符的关系,将音符对应的频率值取出来,根据频率值算出分频比。驱动时钟为50MHz,所以分频比为50M除以频率。

    module cal_divnum (

     

      input   wire              clk,

      input   wire              rst_n,

     

      input   wire    [4:0]     music,

     

      output  reg     [31:0]    divnum

    );

     

      reg             [31:0]    freq;

     

      always @ * begin

        case (music)

          5'd1    : freq =    32'd262;

          5'd2    : freq =    32'd294;

          5'd3    : freq =    32'd330;

          5'd4    : freq =    32'd349;

          5'd5    : freq =    32'd392;

          5'd6    : freq =    32'd440;

          5'd7    : freq =    32'd494;

         

          5'd8    : freq =    32'd523;

          5'd9    : freq =    32'd587;

          5'd10   : freq =    32'd659;

          5'd11   : freq =    32'd699;

          5'd12   : freq =    32'd784;

          5'd13   : freq =    32'd880;

          5'd14   : freq =    32'd988;

         

          5'd15   : freq =    32'd1050;

          5'd16   : freq =    32'd1175;

          5'd17   : freq =    32'd1319;

          5'd18   : freq =    32'd1397;

          5'd19   : freq =    32'd1568;

          5'd20   : freq =    32'd1760;

          5'd21   : freq =    32'd1976;

          default : freq =    32'd1;

        endcase

      end

     

      always @ (posedge clk, negedge rst_n) begin

        if (rst_n == 1'b0)

          divnum <= 32'd50_000_000;

        else

          divnum <= 50_000_000/freq;

      end

    endmodule

    图8 :cal_divmum的设计代码

    知道分频数后,利用任意分频的方式,产生对的波形即可。

    module wave_gen (

      input   wire            clk,

      input   wire            rst_n,

     

      input   wire  [31:0]    divnum,

     

      output  reg             beep

    );

     

      reg           [31:0]    cnt;

     

      always @ (posedge clk, negedge rst_n) begin

        if (rst_n == 1'b0)

          cnt <= 32'd0;

        else

          if (cnt < divnum - 1'b1)

            cnt <= cnt + 1'b1;

          else

            cnt <= 32'd0;

      end

     

      always @ (posedge clk, negedge rst_n) begin

        if (rst_n == 1'b0)

          beep <= 1'b0;

        else

          if (cnt < divnum[31:1])

            beep <= 1'b0;

          else

            beep <= 1'b1;

      end

    endmodule

    图9 :wave_gen的设计代码

        设计好上述四个模块后,将它们之前设计架构的连接方式,连接起来。

    module music_beep (

      input   wire              clk,

      input   wire              rst_n,

     

      output  wire              beep

    );

      wire          [5:0]       cnt;

      wire          [4:0]       music;

      wire          [31:0]      divnum;

     

      speed_ctrl speed_ctrl_inst(

          .clk                  (clk),

          .rst_n                (rst_n),

         

          .cnt                  (cnt)

        );

       

      music_mem music_mem_inst(

          .clk                  (clk),

          .rst_n                (rst_n),

         

          .cnt                  (cnt),

         

          .music                (music)

        );

       

      cal_divnum cal_divnum_inst(

     

          .clk                  (clk),

          .rst_n                (rst_n),

         

          .music                (music),

         

          .divnum               (divnum)

        );

      wave_gen wave_gen_inst(

          .clk                  (clk),

          .rst_n                (rst_n),

         

          .divnum               (divnum),

         

          .beep                 (beep)

        );

       

    endmodule

    图10 :music_beep的设计代码

        RTL视图如下,和所设计架构相同。

    图11 :RTL视图

    在testbench中,将speed_ctrl_inst模块中的T_250ms改成10。

    defparam可以重新定义参数。

    `timescale 1ns/1ps

    module music_beep_tb;

     

      reg           clk;

      reg           rst_n;

     

      wire          beep;

     

      defparam music_beep_inst.speed_ctrl_inst.T_250ms = 10;

     

      music_beep music_beep_inst(

          .clk        (clk),

          .rst_n      (rst_n),

         

          .beep       (beep)

        );

      initial clk = 1'b0;

      always # 10 clk = ~clk;

     

      initial begin

        rst_n = 1'b0;

        # 200

        @ (posedge clk);

        # 2;

        rst_n = 1'b1;

       

        # 20000;

        $stop;

      end

    endmodule

    图12 :testbench代码

    由于输出的频率都较低,所以仿真时间都很长。

    将参数改小,也只是加快切换输出音符的频率。由于wave_gen模块和分频模块相同,故而不在验证。只看RTL视图中,分频数是不是正确即可。

     

    图13 :RTL视图

     

    在RTL视图中,也看到cnt每10个周期增长1,然后对应输出音符。音符得出频率,根据频率得出分频数。经过验证,数据都是正确的。

    分配管脚,全编译形成下载文件,下板后就可以听到《世上只有妈妈好》的歌曲了。

    通过更改speed_crtl中的控制音符前进的速度,可以控制播放的速度。如果将速度控制到1/2秒的话,那么听到的歌曲将会变慢。如果将速度控制到1/8秒的话,那么听到的歌曲将会变快。

    设计者:郝旭帅         QQ:746833924     QQ交流群: 173560979                                    

  • 相关阅读:
    Linux下安装nginx
    使用Nginx搭建集群
    怎样解决虚拟机中多台机器之间的相互通信问题??
    怎样安装vmtools
    常用的机器学习&数据挖掘知识(点)领域链接
    sparkan安装链接
    matlab中怎样将散点用光滑曲线连接起来??
    matlab中怎样画出散点图,将这些散点连接成线??
    matlab中怎样计算两个集合的差集?-setdiff函数
    MATLAB中在一个三维矩阵中如何提取出一个二维矩阵,使用permute
  • 原文地址:https://www.cnblogs.com/fendoudexiaohai/p/13093744.html
Copyright © 2011-2022 走看看