这是我参与8月更文挑战的第5天,活动详情查看:8月更文挑战
平时在使用单片机驱动蜂鸣器的时候,大多数使用的是有源蜂鸣器,只能发出滴滴的声音,声音比较单调也比较刺耳。在使用空调的时候,按下空调上的按键,发出的声音是叮铃铃那种,听起来比较悦耳,很好听。 那么自己能不能蜂鸣器实现这种效果呢?当然是可以的,这种声音可以通过无源蜂鸣器发出和旋音来实现。
驱动原理图如下:
要实现和弦音必须通过2个IO口来控制,其中一个口控制蜂鸣器供电,另一个口控制震荡频率。
首选A点输出高电平,三极管Q1和Q2导通,开始给电容C1充电。然后B点开始输出PWM波,此时蜂鸣器开始发声,输出一定频率的声音,在音乐结束前,A点输出低电平,此时Q1和Q2关断,蜂鸣器靠电容C1放电提供能量给蜂鸣器发声。这样蜂鸣器的声音随着电容的放电就会越来越小,就能实现拖音的效果,然后在不同的时间设置PWM输出的频率不同。这样蜂鸣器就可以实现演奏音乐的效果了。
实现代码如下:
#include "buzzer.h"
#include "stm8s103f3p.h"
_Bool Beep_Power @PD_ODR:3; //控制电源
_Bool Beep_Pre @PD_ODR:4; //输出PWM
// 频率 震荡持续时间 供电持续时间
TONE_Def Tone1[] = {{FREQ_2K6, 100, 20},{FREQ_NO, 0, 0}};//单音
TONE_Def Tone2[] = {{FREQ_2K3, 20, 20},{FREQ_2K6, 20, 20},{FREQ_2K9, 210, 10},{FREQ_NO, 0, 0}};//开机和弦音
TONE_Def Tone3[] = {{FREQ_2K9, 20, 20},{FREQ_2K6, 20, 20},{FREQ_2K3, 210, 10},{FREQ_NO, 0, 0}};//关机和弦音
TONE_Def * pTone;
unsigned char BuzzerStatus =2;
void buzzer_gpio_init(void)
{
PD_DDR|=(1<<3); //PD3 输出 控制蜂鸣器供电
PD_CR1|=(1<<3); //PD3 推挽输出
PD_DDR|=(1<<4); //PD4 输出 控制蜂鸣器频率
PD_CR1|=(1<<4); //PD4 推挽输出
}
//用于蜂鸣器供电引脚
void BeepPwrOn(void)
{
Beep_Power=1;
}
void BeepPwrOff(void)
{
Beep_Power=0;
}
////////////////////////
//用于kai关PWM
void BEEP_On(void)
{
TIM1_CR1 |=(1<<0); //使能定时器
Beep_Pre=1; //频率控制引脚打开
}
void BEEP_Off(void)
{
TIM1_CR1 &=~(1<<0); //禁止定时器
Beep_Pre=0; //关闭频率控制引脚
}
//设置铃声类型 0 1 2
void BuzzerStart(Tone_Type ToneType)
{
switch (ToneType)
{
case MONO: //0 单音
pTone = Tone1;
break;
case POLY_ON: //1 开机
pTone = Tone2;
break;
case POLY_OFF: //2 关机
pTone = Tone3;
break;
default:
pTone = Tone1; //单音
break;
}
BuzzerStatus = 1;
}
//响声控制
void BuzzerCtrl(void)
{
static TONE_Def Tone; //音调 频率 震荡时间 供电时间
switch (BuzzerStatus) //
{
case 1: //调用音调数组
Tone = *pTone;
if (Tone.Freq != FREQ_NO) //频率不为0
{
//先判断供电持续时间
if (Tone.PWRTime != 0) //供电时间不为0
{
Tone.PWRTime --;
BeepPwrOn();
}
else
{
BuzzerStatus = 3;
break;
}
//再判断振荡持续时间
if (Tone.OSCTime != 0) //振荡时间不为0
{
Tone.OSCTime--;
BEEP_SetFreq(Tone.Freq); //设置频率
BEEP_On();
}
else
{
BeepPwrOff();
BuzzerStatus = 3;
break;
}
//判断完成,开始递减计时
BuzzerStatus = 2;
}
else /* Tone.Freq == FREQ_NO */ //是结束符
{
BuzzerStatus = 3;
}
break;
case 2: //延迟 直到时间为0 切换下一个音调
if (Tone.PWRTime != 0)
{
Tone.PWRTime --;
}
else
{
BeepPwrOff();
}
if (Tone.OSCTime != 0)
{
Tone.OSCTime --;
}
else
{
BEEP_Off();
pTone ++; //取下一个音调
BuzzerStatus = 1;
}
break;
default:
break;
}
}
//定时器1初始化 测试用
void TIM1_Init(void)
{
TIM1_CR1 = 0x00; //向上的计数方向,中断计数不停
TIM1_IER = 0x01; //允许更新中断
TIM1_PSCRH = 0x00; //进行16分频 =16M/(15+1)=1M CNTR计数一次为 1/1M=1us
TIM1_PSCRL = 0x0e;
TIM1_ARRH = 265/255; //250us
TIM1_ARRL = 265%255;
TIM1_CR1 |=0x01; //启动定时器
}
//定时器1 中断函数
//250us取反一次 500us一个周期 频率为2K
@far @interrupt void TIM1_OVER_Int(void)
{
TIM1_SR1 = 0x00;
Beep_Pre=~Beep_Pre;
}
//改变蜂鸣器频率
void BEEP_SetFreq(FREQ_Type Freq)
{
unsigned char prescal=0;
switch(Freq)
{
case FREQ_2K :prescal=265; //2K 265
break;
case FREQ_2K3:prescal=230; //2.3K 230
break;
case FREQ_2K6:prescal=205; //2.6K 205
break;
case FREQ_2K9:prescal=182; //2.9K 182
break;
default: prescal=265;
break;
}
TIM1_CR1|=(1<<7); //自动预装载允许
TIM1_IER = 0x01; //允许更新中断
TIM1_PSCRH = 0x00; //进行3分频 =16M/(15+1)=1M CNTR计数一次为 1/1M=1us
TIM1_PSCRL = 0x0e;
TIM1_ARRH = prescal/255; //1000ms
TIM1_ARRL = prescal%255;
TIM1_CR1 |=0x01; //使能定时器
}
单片机的PD3引脚控制电源开关,PD4引脚输出PWM波。PWM的频率通过定时器来实现,在定时器中对PD4引脚取反,改变定时器的定时时间会改变PD4引脚的翻转时间,从而改变PWM输出的频率。
下来在主函数中直接调用蜂鸣器输出和弦音。
#include "stm8s103f3p.h"
#include "delay.h"
#include "buzzer.h"
extern unsigned char BuzzerStatus;
void CLK_Init(void)
{
CLK_SWR=0xe1; //HSI为主时钟源 16MHz CPU时钟频率
CLK_CKDIVR=0x00; //CPU时钟0分频,系统时钟0分频
}
void test(void)
{
char i=0;
for(i=0; i<10; i++)
{
delay_ms(500);
BuzzerStart(0); //单声音
while(BuzzerStatus!=3)
{
BuzzerCtrl();
delay_ms(5);
}
}
for(i=0; i<10; i++)
{
delay_ms(500);
BuzzerStart(1); //开机和弦
while(BuzzerStatus!=3)
{
BuzzerCtrl();
delay_ms(5);
}
}
for(i=0; i<10; i++)
{
delay_ms(500);
BuzzerStart(2); //关机和弦
while(BuzzerStatus!=3)
{
BuzzerCtrl();
delay_ms(5);
}
}
}
main()
{
unsigned char key;
CLK_Init();
_asm("sim"); //禁止中断
delay_init(16);
buzzer_gpio_init();
_asm("rim"); //开启中断
while (1)
{
test();
}
}
在主函数中对三种和弦音进行了一个调用测试,每种声音循环调用10次。如果将PWM输出的频率按照歌曲的节拍输出,这样通过无源蜂鸣器就可播放音乐了。