在基础数字电路实验部分我们已经掌握了FPGA设计PWM信号发生器的原理及方法,上节实验中又学习了矩阵键盘的驱动原理及方法,本实验主要学习无源蜂鸣器的驱动原理,同时熟悉PWM发生模块及矩阵键盘驱动模块的实例化应用。
根据前面的实验解析我们可以得知,该设计总体可以拆分成两个功能模块实现,
蜂鸣器的分类: 按其结构主要分为压电式蜂鸣器和电磁式蜂鸣器两种类型:
按是否带有信号源分为有源蜂鸣器和无源蜂鸣器两种类型:
我们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 );
驱动蜂鸣器的脉冲信号对占空比没有太高的要求,我们默认产生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输入连线就实现了按键信息产生对应音节的输出了,想一想逻辑有问题吗?
应该没错了,到这里我们就完成了蜂鸣器音节驱动部分。
前次实验中我们学习了矩阵键盘的驱动原理及方法,这里就不再重复,不一样的是之前我们用的矩阵键盘模块的脉冲输出(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 ) );
综合后的设计框图如下:
将简易电子琴设计配置文件烧写到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
按照曲谱弹奏琴电子琴没有什么难度,如果我们设计一个状态机,在状态跳转时能够产生上述的音节信息,再配合我们今天讲的蜂鸣器音节驱动设计,就可以实现一个音乐盒了,有兴趣的同学不妨尝试一下。