0.目录
- 
项目要求 
- 
实现功能 
- 
项目分析 
- 
硬件结构 
- 
蜂鸣器 
- 
扬声器 
- 
和弦 
- 
音乐盒 
- 资源占用
- 
实物演示 
- 
心得体会 
- 附件
1.项目要求
自己组装,并通过编程驱动模拟扬声器实现电子琴的功能。
2.实现功能
- 
基于套件和工具,自己组装电子琴。 
- 
编程基于FPGA实现: - 
存储一段音乐,并可以进行音乐播放。 
- 
可以自己通过板上的按键进行弹奏,支持两个按键同时按下(和弦)并且声音不能失真,板上的按键只有13个,可以通过有上方的“上“、”下”两个按键对音程进行扩展。 
- 
使用扬声器进行播放时,输出的音调信号除了对应于该音调的单频正弦波外,还必须包含至少一个谐波分量。 
- 
音乐的播放支持两种方式,这两种方式可以通过开关进行切换: - 
当开关切换到蜂鸣器端,可以通过蜂鸣器来进行音乐播放。 
- 
当开关切换到扬声器端,可以通过模拟扬声器来进行音乐播放,每个音符都必须包含基频 + 至少一个谐波分量。 
 
- 
 
- 
3.项目分析
该项目需要使用小脚丫FPGA与电子琴扩展板,电子琴拓展板与所有小脚丫核心板兼容,本次使用基于Lattice XO2-4000HC的小脚丫FPGA核心模块,通过Diamond进行开发(lattice_diamond_安装配置)。
本项目共需要有两种声音输出方式——蜂鸣器与扬声器。蜂鸣器通过PWM进行驱动,产生的声音效果较差。扬声器则通过PWM和一位DAC后加运放进行驱动,以达到更好的声音效果。
- 
2个RGB灯指示扬声器输出或蜂鸣器输出。 
- 
LED显示当前音程。 
- 
数码管显示按下琴键。 
- 
Key1为系统复位按键。 
- 
SW1为切换音乐盒模式。 
4.硬件结构
- 
核心器件:Lattice LCMXO2-4000HC-4MG132 
- 
板载资源: - 
两位7段数码管; 
- 
两个RGB三色LED; 
- 
8路用户LED; 
- 
4路拨码开关; 
- 
4路按键; 
 
- 
- 
36个用户可扩展I/O(其中包括一路SPI硬核接口和一路I2C硬核接口) 
- 
支持Lattice的开发工具Diamond 
- 
支持MICO32/8软核处理器 
- 
板上集成FPGA编程器 
- 
一路Micro USB接口 
- 
板卡尺寸52mm x 18mm 
5.蜂鸣器
蜂鸣器可以直接参考例程,按下不同按键时调整PWM的频率即可。按键按下时输出,抬起后声音停止。
//当蜂鸣器使能时,计数器按照计数终值(分频系数)计数
always@(posedge clk_in or negedge rst_n_in) begin
   if (!rst_n_in) begin
       time_cnt <= 1'b0;
       end else if (!tone_en) begin
       time_cnt <= 1'b0;
       end else if (time_cnt>= time_end) begin
       time_cnt <= 1'b0;
       end else begin
       time_cnt <= time_cnt + 1'b1;
   end
end
//根据计数器的周期,翻转蜂鸣器控制信号
always@(posedge clk_in or negedge rst_n_in) begin
   if (!rst_n_in) begin
       piano_out <= 1'b0;
       end else if (time_cnt == time_end) begin
       piano_out <= ~piano_out; //蜂鸣器控制输出翻转,两次翻转1Hz
       end else begin
       piano_out <= piano_out;
   end
end
6.扬声器
扬声器为达到更好的效果,先使用PLL倍频,输入晶振为12MHz,通过PLL倍频至120MHz。
通过调整PWM波的占空比,以实现不同电压,可以参考简易电子琴设计。
PWM的代码如下:
module PWM(input clk,
           input rst_n,
           input [9:0]duty,
           input pwm_en,
           output pwm_output);
    
    reg [10:0] pwm_acc;
    
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n)begin
            pwm_acc <= 0;
        end
        else begin
            pwm_acc <= pwm_acc[9:0]+duty;
        end
    end
    
    assign pwm_output = pwm_acc[10]&pwm_en;
    
endmodule正弦波表预先存储在ROM中,采用EXCEL制作,加入谐波分量(最高至五次谐波),各次比例如下:
| 谐波 | 比例 | 
| 基波谐波 | 0.63 | 
| 二次谐波 | 0.21 | 
| 三次谐波 | 0.06 | 
| 四次谐波 | 0.05 | 
| 五次谐波 | 0.05 | 
按该比例加和后进行归一化处理,再进行整形与十六进制转换,最终的得到256位10bit的正弦波形。
将该数据以mem格式存储后生成ROM,配置如下:
对于不同的音节正弦信号频率不同,修改ROM的时钟频率即可以不同速度输出正弦波,以达到输出不同频率正弦波的作用。
   ReadSinData ReadSinData1(
    .clk(clk),
    .rst_n(rst_n),
    .tone_en(tone_en),
    .tone(tone1),
    .sin_out(sin_out1)
    );
    
    PWM PWM(
    .clk(clk),
    .rst_n(rst_n),
    .duty(pwm_duty),
    .pwm_en(tone_en),
    .pwm_output(piano_out)
    );
7.和弦
和弦时例化3个读取ROM的模块,输入不同音节频率,将输出结果合成即可。
   ReadSinData ReadSinData1(
    .clk(clk),
    .rst_n(rst_n),
    .tone_en(tone_en),
    .tone(tone1),
    .sin_out(sin_out1)
    );
    
    ReadSinData ReadSinData2(
    .clk(clk),
    .rst_n(rst_n),
    .tone_en(chord_en),
    .tone(tone2),
    .sin_out(sin_out2)
    );
    
    ReadSinData ReadSinData3(
    .clk(clk),
    .rst_n(rst_n),
    .tone_en(chord_en),
    .tone(tone3),
    .sin_out(sin_out3)
    );
assign chord_out  = (sin_out1 + sin_out2 + sin_out3)/3;
8.音乐盒
预先存储一段乐谱在ROM中,控制音符以0.5s的速度播放,演示中播放的是小星星。
9.资源占用
10.实物演示
演示视频见b站链接。
11.心得体会
- 
Diamond与Quartus使用上界面相似,但IP核的使用体验比Quartus差。 
- 
和弦的种类较多,只设置了1 3 5的和弦,其他和弦种类未进行设置。 
12.附件
链接:https://pan.baidu.com/s/1kk9RoY3Ls0tt1VMOvek-hA?pwd=64ir 提取码:64ir

