**这是本文档旧的修订版!**

简易电子琴设计


实验任务

  • 任务:基于 STEP-MAX10M08核心板 和 STEP BaseBoard V3.0底板 完成简易电子琴设计并观察调试结果
  • 要求:按动矩阵键盘,驱动底板无源蜂鸣器发出产生不同音调,弹奏一首《小星星》。
  • 解析:通过FPGA编程驱动矩阵键盘电路,获取矩阵键盘键入的信息,然后通过编码将键盘输出的信息译码成对应的音节数据,最后通过PWM发生模块驱动底板上的无源蜂鸣器发出声音。

实验目的

在基础数字电路实验部分我们已经掌握了FPGA设计PWM信号发生器的原理及方法,上节实验中又学习了矩阵键盘的驱动原理及方法,本实验主要学习无源蜂鸣器的驱动原理,同时熟悉PWM发生模块及矩阵键盘驱动模块的实例化应用。

  • 熟悉PWM信号发生驱动模块和矩阵键盘驱动模块的应用
  • 了解无源蜂鸣器的驱动原理及方法
  • 完成简易电子琴设计实现

设计框图

根据前面的实验解析我们可以得知,该设计总体可以拆分成两个功能模块实现,

  • ArrayKeyBoard:通过驱动矩阵键盘工作获取键盘的操作信息数据。 * Beeper:根据键盘按键信息驱动无源蜂鸣器发出不同的音节。 顶层模块ElectricPiano通过实例化两个子模块并将对应的信号连接,最终实现简易电子琴的总体设计。我们知道无源蜂鸣器是通过交流信号驱动的,FPGA可以通过输出不同频率的PWM脉冲信号控制蜂鸣器产生不同的音节输出,所以上面Beeper模块又可以拆分成两个功能模块实现其功能
  • tone:通过编码方式将键盘的操作信息译码成对应的PWM周期信息。
  • PWM:根据PWM周期信息产生对应的PWM脉冲信号。

Top-Down层次设计模块结构设计

实验原理

蜂鸣器介绍

蜂鸣器的分类: 按其结构主要分为压电式蜂鸣器和电磁式蜂鸣器两种类型:

  • 电磁式蜂鸣器由振荡器、电磁线圈、磁铁、振动膜片及外壳等组成。接通电源后,振荡器产生的音频信号电流通过电磁线圈,使电磁线圈产生磁场,振动膜片在电磁线圈和磁铁的相互作用下,周期性地振动发声。
  • 压电式蜂鸣器主要由多谐振荡器、压电蜂鸣片、阻抗匹配器及共鸣箱、外壳等组成。多谐振荡器由晶体管或集成电路构成,当接通电源后(1.5~15V直流工作电压),多谐振荡器起振,输出1.5~2.5kHZ的音频信号,阻抗匹配器推动压电蜂鸣片发声。

按是否带有信号源分为有源蜂鸣器和无源蜂鸣器两种类型:

  • 有源蜂鸣器只需要在其供电端加上额定直流电压,其内部的震荡器就可以产生固定频率的信号,驱动蜂鸣器发出声音。
  • 无源蜂鸣器可以理解成与喇叭一样,需要在其供电端上加上高低不断变化的电信号才可以驱动发出声音。

我们STEP BaseBoard V3.0底板上集成的蜂鸣器为无源电磁式蜂鸣器,接下来和大家一起学习无源蜂鸣器的驱动

蜂鸣器驱动电路

无源蜂鸣器没有集成振荡器,需要外部提供震荡激励,当震荡频率不同时发出不同的音调,对于数字系统来说,方波信号产生方便可靠,成为外部震荡激励的首选,方波信号输入谐振装置转换为声音信号输出,电磁式蜂鸣器需要的驱动电流较高,一般单片机和FPGA管脚驱动能力有限不能直接驱动,常用三极管增加驱动能力,另外电磁式蜂鸣器内部含有感应线圈,在电路通断瞬间会产生感应电势,为保证电路长期稳定的工作,最好增加续流二极管设计,STEP BaseBoard V3.0底板蜂鸣器驱动电路如下:

蜂鸣器驱动电路

注:不需要蜂鸣器工作时,控制器BEEP端口输出低电平,管脚配置下拉(pull dowm)模式

蜂鸣器使用NPN三极管(S8050)驱动,三极管当开关用,当基极电压拉高时,蜂鸣器通电,当基极电压拉低时,蜂鸣器断电,FPGA控制GPIO口给三极管的基极输出不同频率的脉冲信号,蜂鸣器就可以发出不同的音节。

蜂鸣器驱动设计

前面我们了解到电磁式无源蜂鸣器需要外部提供震荡激励才可以发出声音,且震荡频率不同产生的音调也不同,不同音节与蜂鸣器震荡频率的对应关系如下表:

音调频率对照表

音节名 频率(Hz) 音节名 频率(Hz) 音节名 频率(Hz)
低音1 261.6 中音1 523.3 高音1 1045.5
低音2 293.7 中音2 587.3 高音2 1174.7
低音3 329.6 中音3 659.3 高音3 1318.5
中音4 349.2 中音4 698.5 高音4 1396.9
低音5 392 中音5 784 高音5 1568
低音6 440 中音6 880 高音6 1760
低音7 493.9 中音7 987.8 高音7 1975.5

FPGA要驱动蜂鸣器就需要给蜂鸣器模块输出《音调频率对照表》中不同频率的脉冲信号就可以了,我们在基础数字电路实验中学习过PWM产生原理,设计过一个PWM信号发生器模块,模块根据两个输入信号(cycle、duty)控制产生周期可控、占空比可控的脉冲信号(pwm_out),可以用来驱动无源蜂鸣器电路。

PWM模块端口程序如下:

module PWM #
(
parameter	WIDTH = 32	//ensure that 2**WIDTH > cycle
)
(
input					clk,
input					rst_n,
input		[WIDTH-1:0]	cycle,	//cycle > duty
input		[WIDTH-1:0]	duty,	//duty < cycle
output	reg				pwm_out
);
  • cycle:基于系统时钟的计数器计数终值,与产生脉冲信号的周期有关
  • duty:脉冲信号产生机制中的比较器阈值,与产生脉冲信号的脉宽(占空比)有关

驱动蜂鸣器的脉冲信号对占空比没有太高的要求,我们默认产生50%占空比的脉冲信号,所以duty的输入取cycle的一半;cycle的值关乎蜂鸣器的音节,需要和《音调频率对照表》中对应,例如如果要蜂鸣器发出低音1的音节,脉冲信号频率控制为261.6Hz,系统时钟采用12MHz,计数器计数终值cycle就等于12M / 261.6 = 45872,即当我们给PWM模块中cycle信号的值为45872时,得到低音1的音节输出。这样我们将每个音节对应的cycle值计算出来,当按动不同按键时给PWM模块不同的cycle值就可以了,我们可以通过设计一个转码模块(tone)将按键信息转换成PWM需要的cycle信号,矩阵键盘共有16个按键,我们只能输出16个音节。

PWM周期转码程序实现如下:

always@(key_in) begin
	case(key_in)
		16'h0001: cycle = 16'd45872;	//L1,
		16'h0002: cycle = 16'd40858;	//L2,
		16'h0004: cycle = 16'd36408;	//L3,
		16'h0008: cycle = 16'd34364;	//L4,
		16'h0010: cycle = 16'd30612;	//L5,
		16'h0020: cycle = 16'd27273;	//L6,
		16'h0040: cycle = 16'd24296;	//L7,
		16'h0080: cycle = 16'd22931;	//M1,
		16'h0100: cycle = 16'd20432;	//M2,
		16'h0200: cycle = 16'd18201;	//M3,
		16'h0400: cycle = 16'd17180;	//M4,
		16'h0800: cycle = 16'd15306;	//M5,
		16'h1000: cycle = 16'd13636;	//M6,
		16'h2000: cycle = 16'd12148;	//M7,
		16'h4000: cycle = 16'd11478;	//H1,
		16'h8000: cycle = 16'd10215;	//H2,
		default:  cycle = 16'd0;		//cycle为0,PWM占空比为0,低电平
	endcase
end

现在我们在Beeper模块中实例化tone和PWM模块,将tone的输出与PWM的cycle输入连线就实现了按键信息产生对应音节的输出了,想一想逻辑有问题吗?

  • 当我们按下按键,会得到按键信息,根据按键信息转码得到一个cycle值,连线传输给PWM模块,产生对应频率脉冲,听到对应音节输出;
  • 当我们松开按键,同样有按键信息,对应到转码模块中得到cycle值为0,连线传输给PWM模块,产生低电平信号,蜂鸣器不发声。

应该没错了,到这里我们就完成了蜂鸣器音节驱动部分。

系统总体实现

前次实验中我们学习了矩阵键盘的驱动原理及方法,这里就不再重复,不一样的是之前我们用的矩阵键盘模块的脉冲输出(keypulse),本实验中简易电子琴在按键按下状态下一直发声,跟按键时间长短有关,这样我们就不能使用keypulse了,而应该使用keyout信号,另外keyout按键有效输出为低电平,而PWM周期转码模块(tone)是高有效编码,所以在顶层模块(ElectricPiano)中矩阵键盘(ArrayKeyBoard)与蜂鸣器音节驱动模块(Beeper)之间的key_out连线需要做按位取反操作。

总体设计程序实现如下:

//Array_KeyBoard 
Array_KeyBoard u1
(
.clk					(clk			),
.rst_n					(rst_n			),
.col					(col			),
.row					(row			),
.key_out				(key_out		),
.key_pulse				(key_pulse		)
);
 
//beeper module
Beeper u2
(
.clk					(clk			),
.rst_n					(rst_n			),
.key_out				(~key_out		),
.beeper					(beeper			)
);

综合后的设计框图如下:

rtl设计框图

实验步骤

  1. 双击打开Quartus Prime工具软件;
  2. 新建工程:File → New Project Wizard(工程命名,工程目录选择,设备型号选择,EDA工具选择);
  3. 新建文件:File → New → Verilog HDL File,键入设计代码并保存;
  4. 设计综合:双击Tasks窗口页面下的Analysis & Synthesis对代码进行综合;
  5. 管脚约束:Assignments → Assignment Editor,根据项目需求分配管脚;
  6. 设计编译:双击Tasks窗口页面下的Compile Design对设计进行整体编译并生成配置文件;
  7. 程序烧录:点击Tools → Programmer打开配置工具,Program进行下载;
  8. 观察设计运行结果。

实验现象

将简易电子琴设计配置文件烧写到FPGA实验平台,按动矩阵按键听蜂鸣器发出的声音,16个按键对应16个音节,按键K1~K7分别对应音节低音1~7,接下来一首好听的《小星星》送给大家,按照下面的曲谱循环弹奏: 1 1 5 5 6 6 5 , 4 4 3 3 2 2 1 , 5 5 4 4 3 3 2 , 5 5 4 4 3 3 2

按照曲谱弹奏琴电子琴没有什么难度,如果我们设计一个状态机,在状态跳转时能够产生上述的音节信息,再配合我们今天讲的蜂鸣器音节驱动设计,就可以实现一个音乐盒了,有兴趣的同学不妨尝试一下。