蜂鸣器是一种一体化结构的电子讯响器,采用直流电压供电,广泛应用于计算机、打印机、复印机、报警器、电子玩具、汽车电子设备、电话机、定时器等电子产品中作发声器件。在一般设计中,可利用蜂鸣器检测有些按键是否按下,或者有些功能是否正常等,也可以让蜂鸣器演奏音乐。
蜂鸣器分为:有源蜂鸣器、无源蜂鸣器;
①有源蜂鸣器:
有源蜂鸣器内部有振荡驱动电路,只要加上电源就可以发声,可以用作报警器的发声器件,但是缺点就是它的频率是固定的,因此只有一个单一的音调。
②无源蜂鸣器:
无源内部不带震荡源,所以如果用直流信号无法令其鸣叫。必须用2K~5K的方波去驱动它。
蜂鸣器原理图
本设计使用的是无源蜂鸣器,也可称为声响器,原理电路图如下所示。它没有内部驱动电路,无源蜂鸣器工作的理想信号为方波,如果给直流,蜂鸣器是不响应的,因为磁路恒定,钼片不能震动发音。
下面我们开始详细介绍蜂鸣器实现音乐播放的详细流程。
打开quartus,【File】→【New Project Wizard 】
编辑项目相关信息
选中empty project
后面是添加文件的,这里是新建直接next。
选择芯片:EP4CE6F17C8
选择你的仿真软件版本(根据你自己安装的版本进行选择)
配置信息完成,点击Finish;(注意对比信息,如果信息不对,可back重新编辑)
创建好后,主界面如示
点击【File】→【New】→【Verilog HDL File】→【OK】
出现了一个空白界面,在右边输入你的Verilog 代码
选择File
代码编辑完成后,点击保存;
弹出dialog,保存在你的项目路径下
单击保存,此后就出现了一个one.v的文档(保存的名字需要和模块例化名一致,以免报错)
创建工程所有文件,最后进行编译
至此,项目创建以及Verilog代码编写就完成了,下面看具体的实现。
按照上述流程,创建对应file,编写Verilog代码;
①pwm_buzzer
module pwm_buzzer(
input clk ,
input rst_n ,
output buzzer //驱动蜂鸣器
);
//参数定义
localparam M1 = 95600,
M2 = 85150,
M3 = 75850,
M4 = 71600,
M5 = 63750,
M6 = 56800,
M7 = 50600;
parameter TIMES = 500;
//信号定义
reg buzzer_r ;
reg [16:0] cnt0 ;//计数每个音符对应的周期
reg [8:0] cnt1 ;//计数每个音符重复多少次
reg [5:0] cnt2 ;//一共有多少个音符
reg [16:0] pre_set;//预装载值
reg [16:0] pre_div;//设定占空比
always@(posedge clk or negedge rst_n)begin
if(~rst_n)begin
cnt0 <= 0;
end
else begin
if(cnt0 == pre_set-1)
cnt0 <= 0;
else
cnt0 <= cnt0 + 1;
end
end
always@(posedge clk or negedge rst_n)begin
if(~rst_n)begin
cnt1 <= 0;
end
else if(cnt0 == pre_set-1)begin
if(cnt1 == TIMES-1)
cnt1 <= 0;
else
cnt1 <= cnt1 + 1;
end
end
always@(posedge clk or negedge rst_n)begin
if(~rst_n)begin
cnt2 <= 0;
end
else if(cnt1 == TIMES-1 && cnt0 == pre_set-1)begin
if(cnt2 == 32-1)
cnt2 <= 0;
else
cnt2 <= cnt2 + 1;
end
end
//pre_set 查找表 选择每个音频对应的计数周期
always@(posedge clk or negedge rst_n)begin
if(~rst_n)begin
pre_set <= 0;
end
else begin
case(cnt2)
0 :pre_set <= M1;
1 :pre_set <= M2;
2 :pre_set <= M3;
3 :pre_set <= M1;
4 :pre_set <= M1;
5 :pre_set <= M2;
6 :pre_set <= M3;
7 :pre_set <= M1;
8 :pre_set <= M3;
9 :pre_set <= M4;
10:pre_set <= M5;
11:pre_set <= M3;
12:pre_set <= M4;
13:pre_set <= M5;
14:pre_set <= M5;
15:pre_set <= M6;
16:pre_set <= M5;
17:pre_set <= M4;
18:pre_set <= M3;
19:pre_set <= M1;
20:pre_set <= M5;
21:pre_set <= M6;
22:pre_set <= M5;
23:pre_set <= M4;
24:pre_set <= M3;
25:pre_set <= M1;
26:pre_set <= M2;
27:pre_set <= M5;
28:pre_set <= M1;
29:pre_set <= M2;
30:pre_set <= M5;
31:pre_set <= M1;
default:pre_set <= M1;
endcase
end
end
always @ (posedge clk or negedge rst_n)begin
if(~rst_n)begin
pre_div <= 0;
end
else begin
pre_div <= pre_set>>1;
end
end
//assign pre_div = pre_set>>1;// /2; 设定占空比为50%
always @ (posedge clk or negedge rst_n)begin
if(~rst_n)begin
buzzer_r <= 1'b1;
end
else if(cnt0 < pre_div)begin
buzzer_r <= 1'b1;
end
else begin
buzzer_r <= 1'b0;
end
end
assign buzzer = buzzer_r;
endmodule
②pwm_buzzer_tb
`timescale 1ns/1ns
module pwm_buzzer_tb();
reg tb_clk ;
reg tb_rst_n ;
wire tb_buzzer;
pwm_buzzer u_pwm(
.clk (tb_clk ),
.rst_n (tb_rst_n ),
.buzzer (tb_buzzer ) //驱动蜂鸣器
);
parameter CLOCK_PERIOD = 20;
defparam u_pwm.TIMES = 50;
initial tb_clk = 1'b0;
always #(CLOCK_PERIOD/2) tb_clk = ~tb_clk;
initial begin
tb_rst_n = 1'b0;
#(CLOCK_PERIOD*20);
tb_rst_n = 1'b1;
#(CLOCK_PERIOD*200000000);
$stop;
end
endmodule
点击编译(或者上述标注的快捷键)
编译信息
编译进度
编译结果
【Tools】→【Netlist Viewers】→【RTL Viewer】
原理图
配置仿真环境
【tools】→【options】
按图示操作
查看仿真
添加测试文件
【Assignment】→【Settings…】
按序号操作
点击出现
选择测试文件
选择test文件
复制名字到上面
此后,就一直点OK。
查看仿真波形
选中模块,鼠标右键点击添加波形
点击下标wave,查看
左边加入(快捷键Ctrl A+Ctrl G)
波形示意图
至此仿真部分就结束了。
在电脑左下角输入“设备管理器”
找到“人体学输入设备”,继续下面的操作
再次全编译
编译无误,连接开发板,打开电源进行烧录
连接开发板
选择全编译,查看是否出错
编译无误,点击烧录
出现如示界面则点击红色方框内容,添加驱动
选择驱动,点击close
ps:如果没有驱动,需要自己下载,
查看信息,点击start烧录
烧录成功