基于FPGA的简易电子琴设计
这是一个简易的电子琴,由小脚丫fpga核心板驱动,实现了蜂鸣器喇叭播放音乐,任意两个琴键的和弦。
标签
FPGA
小脚丫
暑假一起练
电子琴
2022暑假在家练
岁月静好 山河无恙
更新2022-09-08
2316

一,硬件介绍;

1.工作原理;

FuQEzkTUQ-YsobUDo13HRiGvv8y5FlcC3mZfp8_VRf2Iwqe4eZ9e4S6B

图1.电子琴硬件框图

      (1)电子琴的硬件框图中,核心部分是小脚丫的step开发板,本次活动搭载的是STEP-MXO2-C专用板,是专为FPGA大赛推出的,可以使用网页版FPGA开发系统Web IDE来编程,无需下载、安装FPGA的编程软件,当然熟悉Lattice Diamond编程工具的同学仍然可以使用Diamond对其进行编程。

      (2)输入端共15个按键,其中13个被定义为琴键,剩下两个按键用来扩展音程;

      (3)输出端可以选择喇叭发声,也可以是蜂鸣器发声,通过中间拨动开关来选择。蜂鸣器与喇叭的驱动方式和音色响度略有不同。

2.硬件原理图

      硬禾的原理图格式一直是可以的,比起学校里那些堆砌一通的原理图好太多了。这种清爽的布局,清晰的连线,易于阅读也好查错。在对一个事物还没建立大局观的时候,顺藤摸瓜胜过碎片化的反复检索。

Fiaobzz2j8LQcoCtA16KyawWslIk

图2.硬件原理图

3.蜂鸣器和喇叭的区别和驱动方法

      蜂鸣器发声主要靠电压驱动压电陶瓷发声:给压电陶瓷材料施加交变电压时,材料发生规律性膨胀收缩,从而带动金属振膜震动发出声音。压电陶瓷一般工作在谐振频率附近,频带较窄。因为阻抗较大,电流较小,所以蜂鸣器功率较小。本应用FPGA给出一路PWM波来控制三极管开关,从而驱动蜂鸣器发声。通过调节占空比来控制音量大小。

      喇叭的发声是利用永磁体和线圈磁场相互作用发声:变化的电信号流经线圈产生变化的磁场与永磁体产生相作用力,致使磁体吸引排斥线圈产生震动,从而带动纸盆发出声音。喇叭的阻抗较低,功率可以做的很高。本应用采用PWM模拟DAC来生成需要的模拟信号,经过放大电路放大后驱动喇叭发声,通过调节模拟信号的幅值来控制声音大小。

4.蜂鸣器和喇叭的声音区别

      由于蜂鸣器的谐振频率较高,频带较窄,所以发出的声音较尖锐,一般做报警用。喇叭的频带较宽,频率响应优于蜂鸣器,在人耳听力范围内可以表现出更多的细节,适合播放音乐。

5.模拟放大电路的仿真及分析:

      小脚丫的IO口只有两种状态,要么是高电平,要么低电平。要想获得模拟信号,就需要用到小脚丫的“独臂神通”PWM模拟DAC了,即通过调节PWM的占空比,来获得与之等效的模拟电压信号。此处PWM的频率要与后端R16,R17,C3所组成的滤波电路频率相匹配,频率过高驱不动,频率低了又会引起失真。

      Fpobp4UB_AThYOID0oaNPZl4ZQQq

图3.功放芯片框图

      图3是功放驱动芯片的框图可以看到内部输入端是一个放大器件,它可以将输入信号按照一定倍数放大,这个放大倍数为FqPzwPSb6SP6eG2D9F7_2MvHg_JB,一级放大后的信号接到喇叭的一端、再经过反向后接到喇叭另一端来驱动喇叭。

Foy8CA0CVgZchas_nTjKEcm9TtRp

 

图4.放大电路仿真    

      图4是根据放大电路内部框架搭建的仿真图,图中绿色是输入信号,黄、蓝色曲线是放大器输出端信号。

二,功能介绍

      经过这段时间的学习,实现了存储一段琴谱自动播放,按不同琴键切换不同音调。上下按键扩展音程,以及同时按下两个琴键生成和弦等功能。

三,实现过程

      1.正弦波的生成:本应用使用了查表法来实现。即事先将目标基频的一段波表存在小脚丫中,每过一段时间读取一个值来执行累加操作,溢出后将相应IO口置高。

波表部分:

module sin_table(address,sin);
output [8:0] sin;         //实际波形表为9位分辨率(1/4周期)
input  [5:0] address;     //64个点来生成1/4个周期的波形,完整的一个周期为256个点
 
reg    [8:0] sin;
 
always @(address)
	begin
                  case(address)	

                      6'h0:  sin=9'h0;
                      6'h1:  sin=9'h24;
                      6'h2:  sin=9'h4A;
                      6'h3:  sin=9'h6F;
                      6'h4:  sin=9'h93;
                      6'h5:  sin=9'hB6;
                      6'h6:  sin=9'hD8;
                      6'h7:  sin=9'hF8;
                      6'h8:  sin=9'h116;
                      6'h9:  sin=9'h134;
。
。
。
。
。
。
。


                   endcase
              end
endmodule

pwm生成部分:

module pwm(

input   clk,
input   rst,
input   [12:0]  duty,
output pwm_out
);

reg [9:0] PWM_accumulatore;
always @(posedge clk or negedge rst) 
    begin
    if(!rst)
        PWM_accumulatore <= 0;
    else
        PWM_accumulatore <= PWM_accumulatore[8:0] + duty[8:0];
    end
assign pwm_out = ~PWM_accumulatore[9];

endmodule

      (2)生成不同频率的波:通过调节累加器步进值来调节读取播表的快慢成都,从而获得不同正弦波频率。

module synthesizer(
    input clk, 
    input rst,
    input [12:0] key, 
    input [1:0]updown, 
    output [12:0] wavecnt
    );

wire pwm_bit_synthesizer;

wire [9:0] wavec4, waved4b, waved4, wavee4b, wavee4, wavef4, waveg4b, waveg4, wavea4b, wavea4, waveb4b, waveb4, wavec5;

wave #(366) c4(.clk(clk), .rst(rst), .enable(key[0]), .interval(updown), .waveout(wavec4));
wave #(388) d4b(.clk(clk),.rst(rst), .enable(key[1]), .interval(updown),.waveout(waved4b));
wave #(411) d4(.clk(clk), .rst(rst), .enable(key[2]), .interval(updown),.waveout(waved4));
wave #(435) e4b(.clk(clk),.rst(rst), .enable(key[3]), .interval(updown),.waveout(wavee4b));
wave #(461) e4(.clk(clk), .rst(rst), .enable(key[4]), .interval(updown),.waveout(wavee4));
wave #(488) f4(.clk(clk), .rst(rst), .enable(key[5]), .interval(updown),.waveout(wavef4));
wave #(517) g4b(.clk(clk),.rst(rst), .enable(key[6]), .interval(updown),.waveout(waveg4b));
wave #(548) g4(.clk(clk), .rst(rst), .enable(key[7]), .interval(updown),.waveout(waveg4));
wave #(581) a4b(.clk(clk),.rst(rst), .enable(key[8]), .interval(updown),.waveout(wavea4b));
wave #(615) a4(.clk(clk), .rst(rst), .enable(key[9]), .interval(updown),.waveout(wavea4));
wave #(652) b4b(.clk(clk),.rst(rst), .enable(key[10]),.interval(updown), .waveout(waveb4b));
wave #(690) b4(.clk(clk), .rst(rst), .enable(key[11]),.interval(updown), .waveout(waveb4));
wave #(732) c5(.clk(clk), .rst(rst), .enable(key[12]),.interval(updown), .waveout(wavec5));

assign wavecnt = (wavec4+waved4b+waved4+wavee4b+wavee4+wavef4+waveg4b+waveg4+wavea4b+wavea4+waveb4b+waveb4+wavec5)/4;


endmodule

      (3)谐波分量:为了实现谐波分量要求,我事先使用excel生成了一段带有3倍,5倍谐波分量的波表如下图:

Fuo2A1GcDKp2D9AY_69c9YEBpi6d

图5.谐波分量波表

      (4)两个琴键的和弦,此处使用了简单的相加操作来生成和弦。但同时引出另一个问题,两个波相加后的值超出寄存器上限,这样就会出现失真的问题。解决方法是将相加的波值进行了除4处理。

assign wavecnt = (wavec4+waved4b+waved4+wavee4b+wavee4+wavef4+waveg4b+waveg4+wavea4b+wavea4+waveb4b+waveb4+wavec5)/4;

      (5)自动播放一段音乐:这里再次使用了万能的查表法,即先将琴谱存储起来。然后再定义一个节拍模块,每四分之一秒读取一次琴谱,循环一圈播放一遍音乐。

 always@(posedge clk or negedge rst)      //自动播放音乐节拍计数
        begin
        if(!rst)
            tempo[23:0]<= 0;
        else
            tempo[23:0]<=tempo[23:0]+24'b1;
                if(tempo>=1500000)
                begin
                tempo[23:0]<= 0;
                tempo_flag=~tempo_flag;        //计数到节拍标志翻转
                end
        end

    always@(posedge tempo_flag or negedge rst)       //自动播放音节累加
        begin
        if(!rst)
            music_count[7:0]<= 0;
            
        else if(music_flag==1)
           begin
                music_count[7:0]<=music_count[7:0]+8'b1;
                if(music_count>=96)
                begin
                music_count[7:0]<= 0;
                end
            end
            else
            music_count[7:0]<= 0;
        end

    musicable musicable_u0(
    .micount(music_count),
    .musickey(music)
    );

    autokey autokey_u0(                       //将单个音节映射到13个按键
    .key_value (music), 
    .key_bit(music_keybit) 
    );
    

四,不足与改进

      1.按键开始和结束的时候,能听到声音突变,代码还有待优化。现在想来可以这么处理:按键按下时做缓启动设计,即振幅由小慢慢变到最大,弹起时增加振幅慢慢减小的过程;

      2.蜂鸣器的声音大小还不能调节,暂时还没摸索出蜂鸣器声音的调节方法;

      3.自动播放功能只能播放单音节,还不能播放和弦,后续继续探索。

五,心得体会

      1.了解了fpga的设计流程;

      2.认识到功放电路的驱动原理;

附件下载
stepfpga_Synthesizer.zip
implement(37).jed
团队介绍
长草的小破号
评论
0 / 100
查看更多
目录
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2024 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号