在FPGA 实验中, 我们也会使用蜂鸣器作为人机交互的接口, 蜂鸣器在硬件设计中经常会被使用。 最熟悉的就是我们平时使用的台式计算机。几乎每个计算机都保留了蜂鸣器的功能。 蜂鸣器的硬件设计通常比较简单, 硬件连接也比较容易, 在硬件电路设计中, 往往被用来作为调试和警告来使用。 比如计算机的蜂鸣器有很多不同的发声方式, 代表着不同的硬件状态。部分使用方式列举如下:
1长3短:键盘控制器错误。
1长9短:主板Flash RAM或EPROM错误,BIOS损坏。
不断地响(长声):内存条未插紧或损坏。
不停地响:电源、显示器未和显卡连接好。
重复短响:电源有问题。
无声音无显示:电源有问题。
所以我们有必要学习蜂鸣器的使用, 同时在fpga设计中,如果能够灵活应用蜂鸣器,可以作为帮助我们快速检测 bug 的一个手段。当然在学习中如果能编写出不同音响效果也增加了我们学习FPGA的趣味性。
在PRX100T-D的开发板中, 我们使用的是表贴的(SMT) 7.5mm * 7.5mm * 2.5mm 的器件。具体型号可以参考该板的BOM。硬件原理如图1和图2所示:
图1
图2
只要在buzzer 端提供不同频率信号, 蜂鸣器就可以连续发声根据官方的手册中提供的图3所示的频响曲线:
图3
从上图我们可以看到, 在100hz 到10k hz 下,蜂鸣器可以正常发出声音。(纵坐标单位dB)
根据蜂鸣器的特性, 我们设计了一个实验: 利用PRX100T-D 开发板中的7个按键, 实现 1,2,3,4,5,6,7 (do, re, mi, fa, so, la, si):
1: 523.25Hz, 1911132 ns
2: 587.33Hz, 1702620 ns
3: 659.26Hz, 1516852 ns
4: 698.46Hz, 1431721 ns
5: 783.99Hz, 1275526 ns
6: 880.00Hz, 1136363 ns
7: 987.77Hz, 1012381 ns
FPGA 代码如下:
module TOP# ( SIM_MODE = "FALSE" ) ( input IN_CLK_50M, //外部时钟 input [7:1] PB, //外部按键 消抖后选择需要的使用 output buzzer, //buzzer pin 输出pin output led //fpga心跳 ); //================================================================================== //时钟模块 复位电路 wire clk_50m; wire locked; pll SYS_PLL ( .clk_in1 (IN_CLK_50M), .locked (locked), .clk_out1 (clk_50m), .reset (1'b0) ); wire pb_rst; //按键复位脉冲 高电平有效 wire rst_r_n; //复位寄存 assign rst_r_n = locked; //低有效 locked 或按键触发 //================================================================================== reg [31:0] rst_cnt = 0; //复位延时计数 reg sys_rst_n = 0; //系统时钟 locked 系统复位 always @ (posedge clk_50m) if(!rst_r_n) sys_rst_n <= 0; else begin if(rst_cnt >= 500) //delay 500ms sys_rst_n <= 1; else begin sys_rst_n <= 0; //计数不到 保持复位状态 rst_cnt <= rst_cnt +1; end end wire sys_clk = clk_50m; //================================================================================== wire [7:1] pb_flag = 0; // PRX100T-D low level = button press always @ (posedge sys_clk) pb_flag <= ~PB; //================================================================================== buzzer_top #( .MAIN_CLK (50) ) buzzer_top_inst ( .sys_clk (sys_clk), //系统时钟 .pb_flag (pb_flag), .buzzer (buzzer), .rst_n (sys_rst_n) ); //================================================================================== reg [23:0] led_cnt = 0; always @ (posedge sys_clk) if(!sys_rst_n) led_cnt <= 0; else led_cnt <= led_cnt + 1; assign led = led_cnt[23]; //================================================================================== endmodule
端口设计:
input IN_CLK_50M, //外部时钟
input [7:1] PB, //外部按键 消抖后选择需要的使用output buzzer, //buzzer pin 输出pinoutput led //fpga心跳
其中 PB 为prx100t上的7个按键,buzzer 为 蜂鸣器的输出, led 为 fpga的心跳灯
buzzer 模块例化为:
由于prx100t-d硬件设计中,按键平时为高, 按下键后 PB为低。 所以:
reg [7:1] pb_flag = 0; // PRX100T-D low level = button press
always @ (posedge sys_clk) pb_flag <= ~PB;
fpga phy 代码:
localparam CLK_NS = MAIN_CLK == 50 ? 20 : 10;
localparam DO_FREQ_X2 = 1911132/2; // 523.25Hz, 1911132 ns
//=============================================================
reg [23:0] do_ns = 0;
always @ (posedge sys_clk)
if(do_ns >= DO_FREQ_X2) do_ns <= 0;
else do_ns <= do_ns + CLK_NS;
wire do_r = (do_ns >= DO_FREQ_X2) ? 1’b1 : 1’b0; // 523.25Hz, 1911132 ns
always @ (posedge sys_clk)
if(do_r) do_freq <= ~do_freq;
这时 do_freq 输出为 1 (do)对应的频率(523.25Hz),以此类推可以得到其它6个音符的频率,程序细节可以参照工程中的程序。
按键选择代码:
wire [6:0] audio_key = pb_flag; always @ (posedge sys_clk) if(!rst_n) buzzer <= 0; else case (audio_key) 7’b000_0001: buzzer <= do_freq; // 按键1, 选择 do 7’b000_0010: buzzer <= re_freq; // 按键2, 选择 re 7’b000_0100: buzzer <= mi_freq; // 按键3, 选择 mi 7’b000_1000: buzzer <= fa_freq; // 按键4, 选择 fa 7’b001_0000: buzzer <= so_freq; // 按键5, 选择 so 7’b010_0000: buzzer <= la_freq; // 按键6, 选择 la 7’b100_0000: buzzer <= si_freq; // 按键7, 选择 si default: ; endcase
总结:本文根据不同的按键, 选择do, re, mi, fa, so, la, si 等不同的频率。这里仅介绍了音符的简单设计方法,以此类推只要有足够的按键,全音符,和弦甚至乐曲等音乐内容都可以实现。
实验视频:
工程代码(注册用户可见)
相关资料下载:
buzzer_cmt-7525-80-smt-tr