目录
一、理论部分
1、蜂鸣器概述
2、驱动原理
3、实验目标
使蜂鸣器依次输出Do、Re、Mi、Fa、So、La、Si七个音调,每个音调持续时间为0.5s,占空比为50%.
二、模块框图
三、波形图
1、时钟与复位信号
2、计数器
(1)0.5s计数器
因为系统时钟为50MHz 所以0.5s需要24_999_999个时钟周期
(2)音调频率计数器
对0.5s进行计数,7个音调为一个周期。
(3)分频计数器
与音调频率有关,例如Do为262Hz,故需要的时钟周期个数为:
经计算:
波形如下:
(4)频率变量最大值计数器
(5)占空比计数器
3、输出信号
以Do为例,当音调频率计数值(freq_cnt)小于 占空比计数值(duty_data)时为低电平,大于则为高电平。
四、代码部分
1、Verilog代码
module beep
#(
parameter CNT_MAX = 25'd24_999_999,
parameter DO = 18'd190839,
parameter RE = 18'd170067,
parameter MI = 18'd151514,
parameter FA = 18'd143265,
parameter SO = 18'd127550,
parameter LA = 18'd113635,
parameter XI = 18'd101213
)
(
input wire sys_clk,
input wire sys_rst_n,
output reg beep
);
reg [24:0] cnt;
reg [2:0] cnt_500ms;
reg [17:0] freq_cnt;
reg [17:0] freq_data;
wire [16:0] duty_data;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt = 25'd0;
else if(cnt == CNT_MAX)
cnt = 25'd0;
else
cnt = cnt + 25'd1;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_500ms <= 3'd0;
else if((cnt_500ms == 3'd6) && (cnt == CNT_MAX))
cnt_500ms <= 3'd0;
else if(cnt == CNT_MAX)
cnt_500ms <= cnt_500ms + 3'd1;
else
cnt_500ms <= cnt_500ms;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
freq_cnt <= 18'd0;
else if((freq_cnt == freq_data) || (cnt == CNT_MAX)) //如果cnt到达最大值,就进入下一音调频率的计数,故此音调频率清零
freq_cnt <= 18'd0;
else
freq_cnt <= freq_cnt + 18'd1;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
freq_data <= DO;
else case(cnt_500ms)
3'd0:freq_data <= DO;
3'd1:freq_data <= RE;
3'd2:freq_data <= MI;
3'd3:freq_data <= FA;
3'd4:freq_data <= SO;
3'd5:freq_data <= LA;
3'd6:freq_data <= XI;
default:freq_data <= DO;
endcase
assign duty_data = freq_data >> 1; //左移一位相当于乘以2,右移一位除2
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
beep <= 1'b0;
else if(freq_cnt >= duty_data)
beep <= 1'b1;
else
beep <= 1'b0;
endmodule
2、tb仿真代码
`timescale 1ns/1ns
module tb_beep();
reg sys_clk;
reg sys_rst_n;
wire beep;
initial
begin
sys_clk = 1'b1;
sys_rst_n <= 1'b0;
#20
sys_rst_n <= 1'b1;
end
always #10 sys_clk = ~sys_clk;
beep
#(
.CNT_MAX (25'd24_999_99),
.DO (18'd19083),
.RE (18'd17006),
.MI (18'd15151),
.FA (18'd14326),
.SO (18'd12755),
.LA (18'd11363),
.XI (18'd10121)
)
beep_inst
(
.sys_clk(sys_clk),
.sys_rst_n(sys_rst_n),
.beep(beep)
);
endmodule
五、仿真结果
经分析,仿真结果正确