目录
蜂鸣器介绍
蜂鸣器是一种一体化结构的电子讯响器,采用直流电压供电,广泛应用于计算机、打印机、复印机、报警器、电子玩具、汽车电子设备、电话机、定时器等电子产品中作发声器件。
蜂鸣器按其结构可分为电磁式蜂鸣器和压电式蜂鸣器两种类型。
电磁式蜂鸣器由振荡器、电磁线圈、磁铁、振动膜片及外壳组成。压电式蜂鸣器主要由多谐振荡器、压电蜂鸣片、阻抗匹配器以及共鸣箱、外壳等组成。压电式蜂鸣器是以压电陶瓷的压电效应,来带动金属片的振动而发声;而电磁式蜂鸣器则是用电磁的原理,通电时将金属振动 膜吸下,不通电时以振动膜的弹力弹回。由于两种蜂鸣器发声原理不同,电压式结构简单耐用但音调单一、音色差,适用于报警器等设备;而电磁式由于音色好,所以多用于语音、音乐等设备。
蜂鸣器按驱动方式可分为有源蜂鸣器和无源蜂鸣器
左为有源蜂鸣器,右为无源蜂鸣器
区别 | 有源蜂鸣器 | 无源蜂鸣器 |
---|---|---|
外形高度 | 高 | 低 |
引脚部位 | 黑胶封闭 | 绿色电路板 |
电压 | 高 | 低 |
响声 | 连续发声 | 响一次停一次 |
有源蜂鸣器:内部自带振荡源(LCD振荡电路),将正负极接上直流电压即可持续发声,频率固定。
无源蜂鸣器:内部不带振荡源,需要控制器提供振荡脉冲才可发声,调整提供振荡脉冲的频率,可发出不同频率的声音。
注:人耳可以听到的声音频率在20Hz~20kHz之间的声波
模块接线
vcc接工作电压,Gnd接地,信号线接单片机IO口。
GPIO口驱动能力弱,不能直接驱动无源蜂鸣器,使用用三极管开关。
有源:低电平触发就是IO口输入为0就可发声。
无源:低电平时间在一个周期内越长声音越响。
有源蜂鸣器
有源蜂鸣器内部包含一个振荡电路,能将恒定的直流电转化为一定频率的脉冲信号,从而实现磁场交变,带动蜂鸣器振动发音。它不需要额外的驱动电路,只要接通直流电源即可工作
TMB12A05电磁式蜂鸣器采用直流电压供电,发声频率为2.4Khz(不可改变)。
驱动代码
该模块与单色LED模块驱动代码一样,将LED改成Buzzer即可
注意:
1.蜂鸣器的触发方式 2.撕掉蜂鸣器贴纸有惊喜!!!
buzzer.h
#ifndef _BUZZER_H_
#define _BUZZER_H_
#define Buzzer_ON 0
#define Buzzer_OFF 1
void Buzzer_Init(void);
void Buzzer_SetON(void);
void Buzzer_SetOFF(void);
void Buzzer_Turn(void);
#endif
buzzer.c
#include "stm32f10x.h" // Device header
#include "Buzzer.h"
void Buzzer_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_0;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStruct);
//GPIO默认输出低电平
GPIO_WriteBit(GPIOA,GPIO_Pin_0,(BitAction)Buzzer_OFF); //输出高电平 GPIO_SetBits(GPIOA, GPIO_Pin_0)
}
void Buzzer_SetON(void)
{
GPIO_WriteBit(GPIOA,GPIO_Pin_0,(BitAction)Buzzer_ON);
}
void Buzzer_SetOFF(void)
{
GPIO_WriteBit(GPIOA,GPIO_Pin_0,(BitAction)Buzzer_OFF);
}
void Buzzer_Turn(void)
{
if(GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_0)==Buzzer_ON)
{
Buzzer_SetOFF();
}
else
{
Buzzer_SetON();
}
}
无源蜂鸣器
无源蜂鸣器内部不带振荡源,因此不能直接将直流电转化为声能。它需要接收 2K~5K 的方波信号才能工作,通过外部电路产生振荡信号来驱动蜂鸣器发音。通过调整输入方波信号的占空比,可以控制蜂鸣器的音量;改变输入方波信号的频率,可以控制蜂鸣器的音调(音量指声音的强弱,即声音的振动幅度;音调指声音的高低,即声音的振动频率)。
for循环+delay延时实现方波信号
乐谱
p_buzzer.h
#ifndef _P_BUZZER_H_
#define _P_BUZZER_H_
#define Buzzer_ON 0
#define Buzzer_OFF 1
void Buzzer_Init(void);
void Buzzer_SetON(void);
void Buzzer_SetOFF(void);
void Buzzer_Turn(void);
void Buzzer_Work(uint16_t Freq,uint16_t Timeout,uint8_t Volume);
#endif
p_buzzer.c
#include "stm32f10x.h" // Device header
#include "p_buzzer.h"
#include "Delay.h"
void Buzzer_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_0;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStruct);
//GPIO默认输出低电平
GPIO_WriteBit(GPIOA,GPIO_Pin_0,(BitAction)Buzzer_OFF); //输出高电平 GPIO_SetBits(GPIOA, GPIO_Pin_0)
}
void Buzzer_SetON(void)
{
GPIO_WriteBit(GPIOA,GPIO_Pin_0,(BitAction)Buzzer_ON);
}
void Buzzer_SetOFF(void)
{
GPIO_WriteBit(GPIOA,GPIO_Pin_0,(BitAction)Buzzer_OFF);
}
void Buzzer_Turn(void)
{
if(GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_0)==Buzzer_ON)
{
Buzzer_SetOFF();
}
else
{
Buzzer_SetON();
}
}
/**
* @brief 无源蜂鸣器设置方波
* @param Freq 频率 范围:(2000~5000)hz
Timeout 声音持续时间 单位:ms
Volume 音量范围:0~99
* @retval none
*/
void Buzzer_Work(uint16_t Freq,uint16_t Timeout,uint8_t Volume)
{
uint16_t i;
uint16_t Cycle=1000000.0/Freq; //一个周期的时间 单位us 范围(2000~5000)us
uint16_t H_time=Volume/100.0*Cycle; //高电平时间 单位us
uint16_t L_time=Cycle-H_time; //低电平时间 单位us
uint16_t n=Timeout*1000/Cycle; //多少个周期
for(i=0;i<n;i++)
{
Buzzer_SetON();
Delay_us(H_time);
Buzzer_SetOFF();
Delay_us(L_time);
}
}
main.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "Buzzer.h"
int main(void)
{
Buzzer_Init();
while (1)
{
//中音1~7
Buzzer_Work(523,225,1);//1
Delay_ms(5);
Buzzer_Work(587,225,1);//2
Delay_ms(5);
Buzzer_Work(659,225,1);//3
Delay_ms(5);
Buzzer_Work(698,225,1);//4
Delay_ms(5);
Buzzer_Work(784,225,1);//5
Delay_ms(5);
Buzzer_Work(880,225,1);//6
Delay_ms(5);
Buzzer_Work(988,225,1);//7
//小星星
Buzzer_Work(523,225,1);//1
Delay_ms(5);
Buzzer_Work(523,225,1);//1
Delay_ms(5);
Buzzer_Work(784,225,1);//5
Delay_ms(5);
Buzzer_Work(784,225,1);//5
Delay_ms(5);
Buzzer_Work(880,225,1);//6
Delay_ms(5);
Buzzer_Work(880,225,1);//6
Delay_ms(5);
Buzzer_Work(784,225*2,1);//5
Delay_ms(5);
Buzzer_Work(698,225,1);//4
Delay_ms(5);
Buzzer_Work(698,225,1);//4
Delay_ms(5);
Buzzer_Work(659,225,1);//3
Delay_ms(5);
Buzzer_Work(659,225,1);//3
Delay_ms(5);
Buzzer_Work(587,225,1);//2
Buzzer_Work(587,225,1);//2
Buzzer_Work(523,225*2,1);//1
Delay_ms(5);
Buzzer_Work(784,225,1);//5
Delay_ms(5);
Buzzer_Work(784,225,1);//5
Delay_ms(5);
Buzzer_Work(698,225,1);//4
Delay_ms(5);
Buzzer_Work(698,225,1);//4
Delay_ms(5);
Buzzer_Work(659,225,1);//3
Delay_ms(5);
Buzzer_Work(659,225,1);//3
Delay_ms(5);
Buzzer_Work(587,225*2,1);//2
Delay_ms(5);
Buzzer_Work(784,225,1);//5
Delay_ms(5);
Buzzer_Work(784,225,1);//5
Delay_ms(5);
Buzzer_Work(698,225,1);//4
Delay_ms(5);
Buzzer_Work(698,225,1);//4
Delay_ms(5);
Buzzer_Work(659,225,1);//3
Delay_ms(5);
Buzzer_Work(659,225,1);//3
Delay_ms(5);
Buzzer_Work(587,225*2,1);//2
Delay_ms(5);
Buzzer_Work(523,225,1);//1
Delay_ms(5);
Buzzer_Work(523,225,1);//1
Delay_ms(5);
Buzzer_Work(784,225,1);//5
Delay_ms(5);
Buzzer_Work(784,225,1);//5
Delay_ms(5);
Buzzer_Work(880,225,1);//6
Delay_ms(5);
Buzzer_Work(880,225,1);//6
Delay_ms(5);
Buzzer_Work(784,225*2,1);//5
Delay_ms(5);
Buzzer_Work(698,225,1);//4
Delay_ms(5);
Buzzer_Work(698,225,1);//4
Delay_ms(5);
Buzzer_Work(659,225,1);//3
Delay_ms(5);
Buzzer_Work(659,225,1);//3
Delay_ms(5);
Buzzer_Work(587,225,1);//2
Delay_ms(5);
Buzzer_Work(587,225,1);//2
Delay_ms(5);
Buzzer_Work(523,225*2,1);//1
Delay_ms(5);
}
}
定时器PWM驱动的代码
上面代码不断for循环,接下来用定时器PWM驱动驱动无源蜂鸣器
在这之前,我尝试了定时器中断的方法,无论是改变PSC和ARR都会改变方波频率,控制频率比较简单,但是控制占空比(蜂鸣器音量)不易。
1.按照乐谱对应的psc或者arr值进入中断,在中断中反转IO口,但是进入更新中断的都是arr溢出的,无法分时间翻转。
2.1us进一次中断,分段控制IO口,但是频率是固定的,没法改变。
最终我采用定时器的PWM功能,频率和占空比改变容易
乐谱
p_buzzer.h
#ifndef _BUZZER_H_
#define _BUZZER_H_
void Buzzer_Init(void);
void Buzzer_Play();
void Buzzer_SetVolume(uint8_t Volume);
#endif
p_buzzer.c
#include "stm32f10x.h" // Device header
#include "Buzzer.h"
#include "Delay.h"
//播放速度,值为四分音符的时长(ms)
#define Speed 500
//音符对应定时器分频系数的索引,P:休止符,L:低音,M:中音,H:高音,下划线:升半音符号#
#define P 0
#define L1 1
#define L1_ 2
#define L2 3
#define L2_ 4
#define L3 5
#define L4 6
#define L4_ 7
#define L5 8
#define L5_ 9
#define L6 10
#define L6_ 11
#define L7 12
#define M1 13
#define M1_ 14
#define M2 15
#define M2_ 16
#define M3 17
#define M4 18
#define M4_ 19
#define M5 20
#define M5_ 21
#define M6 22
#define M6_ 23
#define M7 24
#define H1 25
#define H1_ 26
#define H2 27
#define H2_ 28
#define H3 29
#define H4 30
#define H4_ 31
#define H5 32
#define H5_ 33
#define H6 34
#define H6_ 35
#define H7 36
//音符对应的分频系数(PSC)
uint16_t FreqBuffer[]=
{
0,2748,2599,2449,23152182,2063,1946,1837,1735,1636,1545,1452,1377,1300,1227,1158,
1093,1032,973,918,866,818,773,729,688,649,613,578,546,515,486,459,433,409,386,364
};
//天空之城乐谱
const uint16_t Music[]=
{
//音符,时值,
P, 4,
P, 4,
P, 4,
M6, 2,
M7, 2,
H1, 4+2,
M7, 2,
H1, 4,
H3, 4,
M7, 4+4+4,
M3, 2,
M3, 2,
//2
M6, 4+2,
M5, 2,
M6, 4,
H1, 4,
M5, 4+4+4,
M3, 4,
M4, 4+2,
M3, 2,
M4, 4,
H1, 4,
//3
M3, 4+4,
P, 2,
H1, 2,
H1, 2,
H1, 2,
M7, 4+2,
M4_,2,
M4_,4,
M7, 4,
M7, 8,
P, 4,
M6, 2,
M7, 2,
//4
H1, 4+2,
M7, 2,
H1, 4,
H3, 4,
M7, 4+4+4,
M3, 2,
M3, 2,
M6, 4+2,
M5, 2,
M6, 4,
H1, 4,
//5
M5, 4+4+4,
M2, 2,
M3, 2,
M4, 4,
H1, 2,
M7, 2+2,
H1, 2+4,
H2, 2,
H2, 2,
H3, 2,
H1, 2+4+4,
//6
H1, 2,
M7, 2,
M6, 2,
M6, 2,
M7, 4,
M5_,4,
M6, 4+4+4,
H1, 2,
H2, 2,
H3, 4+2,
H2, 2,
H3, 4,
H5, 4,
//7
H2, 4+4+4,
M5, 2,
M5, 2,
H1, 4+2,
M7, 2,
H1, 4,
H3, 4,
H3, 4+4+4+4,
//8
M6, 2,
M7, 2,
H1, 4,
M7, 4,
H2, 2,
H2, 2,
H1, 4+2,
M5, 2+4+4,
H4, 4,
H3, 4,
H3, 4,
H1, 4,
//9
H3, 4+4+4,
H3, 4,
H6, 4+4,
H5, 4,
H5, 4,
H3, 2,
H2, 2,
H1, 4+4,
P, 2,
H1, 2,
//10
H2, 4,
H1, 2,
H2, 2,
H2, 4,
H5, 4,
H3, 4+4+4,
H3, 4,
H6, 4+4,
H5, 4+4,
//11
H3, 2,
H2, 2,
H1, 4+4,
P, 2,
H1, 2,
H2, 4,
H1, 2,
H2, 2+4,
M7, 4,
M6, 4+4+4,
P, 4,
0xFF //终止标志
};
void Buzzer_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; ;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
TIM_InternalClockConfig(TIM2);
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStructure.TIM_Period = 100 - 1; //ARR
TIM_TimeBaseInitStructure.TIM_Prescaler = 1 - 1; //PSC
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCStructInit(&TIM_OCInitStructure);
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; //取反PWM波形
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = 50; //CCR 默认占空比为50,音量50
TIM_OC1Init(TIM2, &TIM_OCInitStructure);
TIM_Cmd(TIM2, ENABLE);
}
void PWM_SetPrescaler(uint16_t Prescaler)
{
TIM_PrescalerConfig(TIM2, Prescaler, TIM_PSCReloadMode_Immediate);
}
void Buzzer_Play()
{
static uint16_t MusicSelect=0,FreqSelect=0,TimeSelect=0;
while(Music[MusicSelect]!=0xFF)
{
TIM_Cmd(TIM2, ENABLE);
FreqSelect=Music[MusicSelect];
PWM_SetPrescaler(FreqBuffer[FreqSelect]);
TimeSelect=Music[++MusicSelect];
Delay_ms(Speed/4*TimeSelect);
MusicSelect++;
Delay_ms(5);
}
if(Music[MusicSelect]==0xFF)
{
MusicSelect=0;
TIM_Cmd(TIM2, DISABLE);
}
}
void Buzzer_SetVolume(uint8_t Volume)
{
TIM_SetCompare1(TIM2, Volume);
}
main.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "Buzzer.h"
int main(void)
{
Buzzer_Init();
Buzzer_SetVolume(1);
while(1)
{
Buzzer_Play();
Delay_ms(1000);
Buzzer_SetVolume(99);//增大声音后再播放一次
Buzzer_Play();
}
}
参考手册(有源):