在FPGA 实验中, 我们也会使用蜂鸣器作为人机交互的接口, 蜂鸣器在硬件设计中经常会被使用。 最熟悉的就是我们平时使用的台式计算机。几乎每个计算机都保留了蜂鸣器的功能。 蜂鸣器的硬件设计通常比较简单, 硬件连接也比较容易, 在硬件电路设计中, 往往被用来作为调试和警告来使用。 比如计算机的蜂鸣器有很多不同的发声方式, 代表着不同的硬件状态。举例:
1长3短:键盘控制器错误。
1长9短:主板Flash RAM或EPROM错误,BIOS损坏。
不断地响(长声):内存条未插紧或损坏。
不停地响:电源、显示器未和显卡连接好。
重复短响:电源有问题。
无声音无显示:电源有问题。
所以我们有必要学习一蜂鸣器的使用, 同时在fpga设计中,如果能够灵魂应用蜂鸣器,可以帮助我们快速检测 bug 的一个手段。
在PRX100T-D的开发板中, 我们使用的是表贴的(SMT) 7.5mm * 7.5mm * 2.5mm 的器件。
硬件原理图如下:
只要在buzzer 端提供不同频率信号, 蜂鸣器就可以连续发声根据官方的手册中提供的频响曲线:

我们可以看到, 在100hz 到10k hz 下,蜂鸣器可以正常出声音
根据蜂鸣器的特性, 我们设计了一个实验: 利用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 输出pin output led //fpga心跳
其中 PB 为prx100t上的7个按键,buzzer 为 蜂鸣器的输出, led 为 fpga的心跳灯 buzzer 模块例化为:
buzzer_top
#(
.MAIN_CLK ( 50 )
)
buzzer_top_inst
(
.sys_clk ( sys_clk ), //系统时钟
.pb_flag ( pb_flag ),
.buzzer ( buzzer ),
.rst_n ( sys_rst_n )
);
由于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)以此类推。
按键选择代码:
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 等不同的频率。
工程代码如下:
[content_control]
[/content_control]
对应视频:

