FPGA学习日志——无源蜂鸣器beep

无源蜂鸣器beep

有源/无源蜂鸣器

无源这里的“源”不是指电源,而是指震荡源。也就是说,有源蜂鸣器内部带震荡源,所以只要一通电就会叫。而无源内部不带震荡源,所以如果用直流信号无法令其鸣叫。

无源蜂鸣器的优点是:1、便宜;2、声音频率可控,可以做出“多来米发索拉西”的效果;3、在一些特例中,可以和LED复用一个控制口。
有源蜂鸣器的优点是:程序控制方便。

无源蜂鸣器的驱动原理

无源蜂鸣器因其内部不带震荡源,所以无法像有源蜂鸣器一样直接用直流信号驱动,这里需要使用PWM方波才能驱动其发声。输入不同频率和占空比的PWM方波发出的声音是不同的,其中频率对音调有影响,占空比对音量大小有影响。

在这里插入图片描述

实验原理

实验目的:每隔0.5s实现音阶的循环发声

使用PWM的方式发出特定频率和占空比的信号,每隔0.5s转换音阶,也就是说在0.5s内产生同一个信号的固定频率和固定占空比信号。(实验仅实现占空比50%)

以音阶Do为例:262hz 一个时钟周期为1/262=3816794ns,系统时钟50Mhz,20ns。即一个时钟周期计数190840个,为实现50%占空比,计数将为一半即95420个。
在这里插入图片描述

实验框图与波形

在这里插入图片描述

首先由于实验目的为0.5s循环,所以计数器cnt计数最大值为24_999_999,并且设定计数器cnt_500ms进行7个音阶的计数实现循环并且控制计数器进行相应计数,在每个0.5s计数周期内设定计数器freq_cnt实现每个0.5s内的不同频率计数,再根据duty_data实现占空比的控制。

上述波形图的输出beep,不方便绘制全部音阶输出,以音阶Do为例具体分析:

在这里插入图片描述

其他音阶同理。

实验代码

module  beep
#(
    parameter   CNT_MAX=25'd24_999_999,
                DO     =18'd190839,
                RE     =18'd170067,
                MI     =18'd151514,
                FA     =18'd143265,
                SO     =18'd127550,
                LA     =18'd113635,
                XI     =18'd101365    
)
(
    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))//当计数器记到最大值也需要强制清零
                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;//左移一位相当于x2,右移一位相当于/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

对于参数进行统一参数设定,无论是0.5s还是音阶都方便后期模块的更改和调用。

仿真代码

`timescale  1ns/1ns
module  tb_beep();

reg     sys_clk;
reg     sys_rst_n;

initial 
    begin
        sys_clk=1'b0;
        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'd10136)    

)
beep_inst
(
    .sys_clk(sys_clk),
    .sys_rst_n(sys_rst_n),
    
    .beep(beep)
);
endmodule
  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Chendy_00

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值