15无源蜂鸣器

一、蜂鸣器
1、什么是蜂鸣器
蜂鸣器按其结构可分为电磁式蜂鸣器和压电式蜂鸣器两种类型;蜂鸣器按其是否带有信号源又分为有源蜂鸣器和无源蜂鸣器。
有源蜂鸣器的内部装有集成电路,不需要音频驱动电路,只需要接通直流电源就能直接发出声响;而无源蜂鸣器只有外加音频驱动信号才能发出声响。
2、无源蜂鸣器原理
无源蜂鸣器与有源蜂鸣器不同,因其内部不带震荡源,所以其无法像有源蜂鸣器那样直接用直流信号驱动,这里需要使用PWM方波才能驱动其发声。
输入不同频率和占空比的PWM方波发出的声音是不同的,其中频率对音调有影响,占空比对音量大小有影响。
在这里插入图片描述

二、实现
目标:实现七个音调的循环发声,每个音调发声五秒,占空比50%
例如:DO的频率时262Hz,其计数周期为0~19084之间循环计数
15无源蜂鸣器_第1张图片

同理,其余的也是这样,其表格如下,占空比对音量的大小有关系,我们要求的是50%,因此其计数值时音调分频计数值的一半
15无源蜂鸣器_第2张图片

1.波形图
15无源蜂鸣器_第3张图片

2.程序

module beep
#(
    parameter   CNT_MAX = 25'd24999999,
    parameter   DO      = 18'd190839,//"哆"音调分频计数值(频率262)
    parameter   RE      = 18'd170067,//"来"音调分频计数值(频率294)
    parameter   MI      = 18'd151514,//"咪"音调分频计数值(频率330)
    parameter   FA      = 18'd143265,//"发"音调分频计数值(频率349)
    parameter   SO      = 18'd127550,//"梭"音调分频计数值(频率392)
    parameter   LA      = 18'd113635,//"拉"音调分频计数值(频率440)
    parameter   SI      = 18'd101213 //"西"音调分频计数值(频率494)

)

(
    input   wire    sys_clk,
    input   wire    sys_rst_n,
    
    output  reg     beep
);

reg     [24:0]  cnt         ;   //0.5s计数器
reg     [2:0]   cnt_500ms   ;   //0.5s个数计数
reg     [17:0]  fre_cnt     ;   //音调计数器
reg     [17:0]  fre_data    ;   //音调分频计数值
wire    [16:0]  duty_data   ;   //占空比计数值

//cnt:0.5s循环计数器
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 + 1'b1;
 //cnt_500ms:对500ms个数进行计数,每个音阶鸣叫时间0.5s,7个音节一循环       
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 + 1'b1;
    else
        cnt_500ms <= cnt_500ms;
        
 /*fre_cnt:当计数到音阶计数值或跳转到下一音阶时,开始重新计数
与下面的方式一样能够实现其功能,此方法比较复杂,只供参考*/
 
/* always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        fre_cnt <= 18'd0;
    else    case (cnt_500ms)
        3'd0:   if ((fre_cnt == DO)||(cnt == CNT_MAX))
                    fre_cnt <= 18'd0;
                else
                    fre_cnt <= fre_cnt +18'd1;
        3'd1:   if ((fre_cnt == RE)||(cnt == CNT_MAX))
                    fre_cnt <= 18'd0;
                else
                    fre_cnt <= fre_cnt +18'd1;
        3'd2:   if ((fre_cnt == MI)||(cnt == CNT_MAX))
                    fre_cnt <= 18'd0;
                else
                    fre_cnt <= fre_cnt +18'd1;
        3'd3:   if ((fre_cnt == FA)||(cnt == CNT_MAX))
                    fre_cnt <= 18'd0;
                else
                    fre_cnt <= fre_cnt +18'd1;
        3'd4:   if ((fre_cnt == SO)||(cnt == CNT_MAX))
                    fre_cnt <= 18'd0;
                else
                    fre_cnt <= fre_cnt +18'd1;
        3'd5:   if ((fre_cnt == LA)||(cnt == CNT_MAX))
                    fre_cnt <= 18'd0;
                else
                    fre_cnt <= fre_cnt +18'd1;
        3'd6:   if ((fre_cnt == SI)||(cnt == CNT_MAX))
                    fre_cnt <= 18'd0;
                else
                    fre_cnt <= fre_cnt +18'd1;
        default:    fre_cnt <= 18'd0;
        endcase */
        
 //fre_cnt:当计数到音阶计数值或跳转到下一音阶时,开始重新计数    
always@(posedge sys_clk or negedge sys_rst_n)
    if (sys_rst_n == 1'b0)
        fre_cnt <= 18'd0;
    else if ((fre_cnt == fre_data)||(cnt == CNT_MAX))
        fre_cnt <= 18'd0;
    else
        fre_cnt <= fre_cnt +1'b1;

//不同时间鸣叫不同的音阶
always@(posedge sys_clk or negedge sys_rst_n)
    if (sys_rst_n == 1'b0)
        fre_data <= DO;
    else    case (cnt_500ms)
        3'd0: fre_data <= DO;
        3'd1: fre_data <= RE;
        3'd2: fre_data <= MI;
        3'd3: fre_data <= FA;
        3'd4: fre_data <= SO;
        3'd5: fre_data <= LA;
        3'd6: fre_data <= SI;
        default: fre_data <= DO;
        endcase
        
//设置50%占空比:音阶分频计数值的一半即为占空比的高电平数        
assign duty_data = fre_data >> 1;

//beep:输出蜂鸣器波形
always@(posedge sys_clk or negedge sys_rst_n)
    if (sys_rst_n == 1'b0)
        beep <= 1'b0;
    else if (duty_data >= fre_cnt)
        beep <= 1'b1;
    else if (duty_data < fre_cnt)
        beep <= 1'b0;
    else
        beep <= beep;
   
   
endmodule

3、仿真程序

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


reg     sys_clk     ;   //时钟
reg     sys_rst_n   ;   //复位


//对时钟,复位信号赋初值
initial
    begin
        sys_clk     =   1'b1;
        sys_rst_n   <=  1'b0;
        #100
        sys_rst_n   <=  1'b1;
    end

//产生时钟信号
always #10 sys_clk =   ~sys_clk;


beep
#(
    .CNT_MAX   (25'd24999),   //0.5s计数值
    .DO        (18'd190  ),   //"哆"音调分频计数值(频率262)
    .RE        (18'd170  ),   //"来"音调分频计数值(频率294)
    .MI        (18'd151  ),   //"咪"音调分频计数值(频率330)
    .FA        (18'd143  ),   //"发"音调分频计数值(频率349)
    .SO        (18'd127  ),   //"梭"音调分频计数值(频率392)
    .LA        (18'd113  ),   //"拉"音调分频计数值(频率440)
    .SI        (18'd101  )    //"西"音调分频计数值(频率494)
)
beep_inst
(
    .sys_clk     (sys_clk   ),   //系统时钟,频率50MHz
    .sys_rst_n   (sys_rst_n ),   //系统复位,低有效

    .beep        (beep      )    //输出蜂鸣器控制信号
);

endmodule

你可能感兴趣的:(FPGA学习,verilog,嵌入式,fpga/cpld,编程语言)