本章节将讲解如何使用STM32CubeMx配置定时器,并使用PWM控制无源蜂鸣器频率演奏
1.软件准备:STM32CubeMx、Keil5_ MDK
2.硬件准备:STM32F103最小系统板、无源蜂鸣器模块、杜邦线若干
本实验所使用的所有器件清单和工程源码已上传至百度网盘
链接:https://pan.baidu.com/s/11HC05dnI-CEzDaU9OL2ugA?pwd=80o8
提取码:80o8
如图所示为蜂鸣器电路。
一般来说,3.3V直流产生的电信号功率很小,不足以驱动蜂鸣器发出可听见的响声,所以整个模块中有一个电流放大模块,这便是图中的晶体三极管。图中的放大电路是典型的共发射极接法,蜂鸣器接在集电极上,就实现了电流的放大(详细的晶体管放大电路原理请见《模拟电子技术》)
蜂鸣器分为有源和无源两种。所谓的源,指的是其中内部的振荡源,有源蜂鸣器中的振荡器一般是多谐振荡器,其原理就是模拟电路中RC振荡器的一般原理(放大电路、正反馈、相位差90°、稳压电路),有源蜂鸣器内部的振荡源频率是固定的,所以使用时不可调频,且输入的电信号必须是直流。
相比之下,无源蜂鸣器没有内部振荡源,发声的基本原理是电磁感应,其内部的基本结构是一匝匝线圈以及一个微型扬声器。由于没有振荡源,且内部的主要结构是线圈,所以其工作时输入的电信号必须是交流,而不能是频率很低的直流(直流不能通过无负载的线圈,负责线圈会因为短路而被烧坏)。与有源蜂鸣器一样,无源蜂鸣器也必须使用放大电路来增大输入信号的功率。
脉冲宽度调制(PWM) 是一种数字信号,最常用于控制电路。该信号在预定义的时间和速度中设置为高(5v或3.3v)和低(0v)。通常,我们将PWM的高电平称为1,低电平为0。
PWM主要有 PWM频率(f)、 PWM周期(T)、 PWM占空比等参数。
PWM频率:是指一秒钟内从高电平时间在到低电平时间,再从低电平跳到高电平的瞬间次数,也就是一秒钟内有多少个PWM的周期。f = T / 1(HZ)。
PWM周期:是指一秒钟内从高电平时间在到低电平时间,T = f / 1(s)。
PWM占空比:是指一个周期内高电平时间和总时间的比值。
例如:PWM的周期为1ms,高电平时间为0.5ms,低电平时间为0.5ms,则频率就为1kHz,占空比就为百分之五十。
如图所示,为示波器
pwm的调节作用来源于对“占周期”的宽度控制,“占周期”变宽,输出的能量就会提高,通过阻容变换电路所得到的平均电压值也会上升,“占周期”变窄,输出的电压信号的电压平均值就会降低,通过阻容变换电路所得到的平均电压值也会下降
也就是,在一定的频率下,通过不同的占空比即可得到不同的输出模拟电压,由此,我们可以通过控制PWM输出频率控制蜂鸣器发出不同音调。
如图所示为不同音调对应的频率,我们通过修改定时器psc即可修改不同频率对应的音调。
为计算所得产生中断周期,其中为自动重装载值,为预分频,为对应时钟频率。
若要使音调对应定时器频率,以低音DO为例,将, 带入上述公式,即可求出的值,修改不同的对应不同的音调。
由定时器周期计算公式我们可知,Tclk为定时器挂靠时钟总线频率,arr为设定定时器自动重装载值,f已知为不同音调频率,图中“dao”频率为262,通过计算得出psc赋给定时器以获得不同音调。
将所有音调计算出来,放在.h文件宏定义。
(一)音调
音阶分为中音、高音、低音,点在上面为高音,没有点为中音,点在下面为低音
(二)音长
简谱对应音阶下无横线为一拍,有单横线为半拍,双横线为1/4拍。音阶数字后有点加半拍音长,有横线加一拍。
五、程序实现
本次实验同样通过STM32CubeMx实现,
打开之前创建的工程
设置psc和arr,因为本次实验是通过修改psc控制定时器频率,所以初始化psc的值可任意 ,arr的值会影响到占空比的大小,一般设置为1000,方便自己计算即可。
设置占空比为50%,其余设置保持默认即可。设置完成后生成代码。
根据音调表对应频率宏定义音调
#define proport 72000 //Tclk/(arr+1)=72000000/(1000)
//根据Tout= ((arr+1)*(psc+1))/Tclk推出psc值就是本句define定义的值,Tout为音调频率131Hz的倒数,Tclk=72MHz
#define L1 ((proport/262)-1)//低调 do 的频率
#define L2 ((proport/296)-1)//低调 re 的频率
#define L3 ((proport/330)-1)//低调 mi 的频率
#define L4 ((proport/349)-1)//低调 fa 的频率
#define L5 ((proport/392)-1)//低调 sol 的频率
#define L6 ((proport/440)-1)//低调 la 的频率
#define L7 ((proport/494)-1)//低调 si 的频率
#define M1 ((proport/523)-1)//中调 do 的频率
#define M2 ((proport/587)-1)//中调 re 的频率
#define M3 ((proport/659)-1)//中调 mi 的频率
#define M4 ((proport/699)-1)//中调 fa 的频率
#define M5 ((proport/784)-1)//中调 sol的频率
#define M6 ((proport/880)-1)//中调 la 的频率
#define M7 ((proport/988)-1)//中调 si 的频率
#define H1 ((proport/1048)-1)//高调 do 的频率
#define H2 ((proport/1176)-1)//高调 re 的频率
#define H3 ((proport/1320)-1)//高调 mi 的频率
#define H4 ((proport/1480)-1)//高调 fa 的频率
#define H5 ((proport/1640)-1)//高调 sol的频率
#define H6 ((proport/1760)-1)//高调 la 的频率
#define H7 ((proport/1976)-1)//高调 si 的频率
#define Z0 0//
到此为止,底层基本书写完毕,接下来就是寻找歌曲简谱,实现功能
这里推荐乐谱查询网址陈奕迅《孤勇者》吉他谱_G调吉他弹唱谱_高清六线谱_玩吉他 (wanjita.com)
对应音调编写以下代码
《孤勇者》
/**
* NAME: void Solitary_brave(void)
* FUNCTION : Solitary_brave
*/
void Solitary_brave(void)
{
int16_t solitary_brave[]=
{
M6,50,M7,50,H1,50,H2,50,M7,50,H1,50,H1,100,Z0,10, //爱你孤身走暗巷
H1,50,M7,50,H1,50,H2,50,M7,50,H1,50,H1,100,Z0,10, //爱你不跪的模样
H1,50,H2,50,H3,50,H2,50,H3,50,H2,50,H3,100,H3,50,H3,50,H2,50,H3,100,H5,100,H3,100,Z0,10 //爱你对峙过绝望不肯哭一场
};
int length = sizeof(solitary_brave)/sizeof(solitary_brave[0]);
for(uint8_t i=0;i<(length/2);i++)
{
buzzer_on(solitary_brave[i*2],200);
HAL_Delay(5*solitary_brave[i*2+1]);
}
}
《起风了》
void Wind_Rises(void)
{
int wind_rise[]=
{
//前奏
L7,25,M1,25,M2,25,M3,25,L3,50,M5,25,M3,25,M3,50,Z0,150, L7,25,M1,25,M2,25,M3,25,L2,50,M5,25,M3,25,M2,25,M3,25,M1,25,M2,25,L7,25,M1,25,L5,25,Z0,25, L7,25,M1,25,M2,25,M3,25,L3,50,M5,25,M3,75,Z0,150,L7,25,M1,25,M2,25,M3,25,L2,50,M5,25,M3,25,M2,25,M3,25,M1,25,M2,25,Z0,20,
//这一路上走走停停 顺着少年漂流的痕迹
M2,50,M2,50,M1,25,M2,50,M2,50,M1,25,M2,50,M3,50,M5,50,M3,50, M2,50,M2,50,M1,25,M2,50,M2,50,M1,25,M2,25,M3,25,M2,25,M1,25,L6,100,Z0,10,
//迈出车站的前一刻 竟有些犹豫
M2,50,M2,50,M1,25,M2,50,M2,50,M1,25,M2,50,M3,50,M5,50,M3,50, M2,50,M2,50,M3,25,M2,50,M1,50,M2,100,Z0,50,
//不仅笑着这近乡情怯 仍无法避免
M2,50,M2,50,M1,25,M2,50,M2,50,M1,25,M2,50,M3,50,M5,50,M3,50, M2,50,M2,50,M3,25,M2,50,M1,50,L6,100,Z0,10
//而长野的天 依旧那么暖 风吹起了从前
M3,25,M2,25,M1,25,M2,25,M1,100, M3,25,M2,25,M1,25,M2,25,M1,50,M1,50, M5,25,M3,25,M2,25,M1,25,M2,25,M1,100,M1,150,Z0,30
//从前初识这世间 万般留恋 看着天边似在眼前 也甘愿赴汤蹈火去走它一遍
M1,50,M2,50,M3,50,M1,50,M6,50,M5,25,M6,25,M6,50,M6,50, M1,25,M7,50,M6,25,M7,25,M7,100,Z0,5, M7,50,M6,25,M7,25,M7,50,M3,50,H1,25,H2,25,H1,25,M7,25,M6,50,M5,50, M6,50,M5,25,M6,25,M6,25,M5,25,M6,25,M5,25,M6,50,M5,25,M2,25,M2,25,M5,50,M5,50,M3,100,M3,100,Z0,25,
//如今走过这世间 万般留恋 翻过岁月不同侧脸 措不及防闯入你的笑颜
M1,50,M2,50,M3,50,M1,50,M6,50,M5,25,M6,25,M6,50,M6,50, M1,25,M7,50,M6,25,M7,25,M7,100,Z0,5, M7,50,M6,25,M7,25,M7,50,M3,50,H1,25,H2,25,H1,25,M7,25,M6,50,M5,50, M6,50,H3,25,H3,25,H3,50,M5,50,M6,50,H3,25,H3,25,H3,25,M5,50,M6,25,M6,100,M6,100,M6,100,Z0,25,
//我曾难自拔于世界之大 也沉溺于其中梦话
H1,50,H2,50,H3,50,H6,25,H5,25,H5,50,H6,25,H5,25,H5,50,H6,25,H5,25,H5,50,H2,25,H3,25,H3,50, H6,25,H5,25,H5,50,H6,25,H5,25,H5,50,H6,25,H5,25,H5,25,H3,50,H3,50,
//不得真假 不做挣扎 不惧笑话
H2,50,H1,25,M6,25,M6,25,H1,50, M6,25,H2,25,H1,25,M6,50,M6,25,H1,50,H1,50, H3,100,H3,25,H4,25,H3,50,H3,25,H2,50,H2,50,Z0,25,
//我曾将青春翻涌成她 也曾指尖弹出盛夏 心之所动且就随缘去吧
H1,50,H2,50,H3,50,H6,25,H5,25,H5,50,H6,25,H5,25,H5,50,H6,25,H5,25,H5,50,H2,50, H3,50,H6,25,H5,25,H5,50,H6,25,H5,25,H5,50,H6,25,H5,25,H5,50,H3,50,H3,50, H2,50,H1,25,M6,25,M6,25,H3,50,H3,50, H2,50,H1,25,M6,25,M6,25,H1,50,H1,50,H1,100,H1,100,Z0,10,
//短短的路走走停停 也有了几分的距离
M2,50,M2,50,M1,25,M2,50,M2,50,M1,25,M2,50,M3,50,M5,50,M3,50, M2,50,M2,50,M1,25,M2,50,M2,50,M1,25,M2,25,M3,25,M2,25,M1,25,L6,100,Z0,10,
//不知抚摸的是故事还是段心情
M2,50,M2,50,M1,25,M2,50,M2,50,M1,25,M2,50,M3,50,M5,50,M3,50, M2,50,M2,50,M3,25,M2,50,M1,50,M2,100,Z0,50,
//也许期待的不过是与时间为敌
M2,50,M2,50,M1,25,M2,50,M2,50,M1,25,M2,50,M3,50,M5,50,M3,50, M2,50,M2,50,M3,25,M2,50,M1,50,L6,100,Z0,10,
//再次见到你 微凉晨光里 笑的很甜蜜
M3,25,M2,25,M1,25,M2,25,M1,100, M3,25,M2,25,M1,25,M2,25,M1,50,M1,50, M5,25,M3,25,M2,25,M1,25,M2,25,M1,100,M1,150,Z0,30,
//从前初识这世间 万般留恋 看着天边似在眼前 也甘愿赴汤蹈火去走它一遍
M1,50,M2,50,M3,50,M1,50,M6,50,M5,25,M6,25,M6,50,M6,50, M1,25,M7,50,M6,25,M7,25,M7,100,Z0,5, M7,50,M6,25,M7,25,M7,50,M3,50,H1,25,H2,25,H1,25,M7,25,M6,50,M5,50, M6,50,M5,25,M6,25,M6,25,M5,25,M6,25,M5,25,M6,50,M5,25,M2,25,M2,25,M5,50,M5,50,M3,100,M3,100,Z0,25,
//如今走过这世间 万般留恋 翻过岁月不同侧脸 措不及防闯入你的笑颜
M1,50,M2,50,M3,50,M1,50,M6,50,M5,25,M6,25,M6,50,M6,50, M1,25,M7,50,M6,25,M7,25,M7,100,Z0,5, M7,50,M6,25,M7,25,M7,50,M3,50,H1,25,H2,25,H1,25,M7,25,M6,50,M5,50, M6,50,H3,25,H3,25,H3,50,M5,50,M6,50,H3,25,H3,25,H3,25,M5,50,M6,25,M6,100,M6,100,M6,100,Z0,25,
//我曾难自拔于世界之大 也沉溺于其中梦话
H1,50,H2,50,H3,50,H6,25,H5,25,H5,50,H6,25,H5,25,H5,50,H6,25,H5,25,H5,50,H2,25,H3,25,H3,50, H6,25,H5,25,H5,50,H6,25,H5,25,H5,50,H6,25,H5,25,H5,25,H3,50,H3,50,
//不得真假 不做挣扎 不惧笑话
H2,50,H1,25,M6,25,M6,25,H1,50, M6,25,H2,25,H1,25,M6,50,M6,25,H1,50,H1,50, H3,100,H3,25,H4,25,H3,50,H3,25,H2,50,H2,50,Z0,25,
//我曾将青春翻涌成她 也曾指尖弹出盛夏 心之所动且就随缘去吧
H1,50,H2,50,H3,50,H6,25,H5,25,H5,50,H6,25,H5,25,H5,50,H6,25,H5,25,H5,50,H2,50, H3,50,H6,25,H5,25,H5,50,H6,25,H5,25,H5,50,H6,25,H5,25,H5,50,H3,50,H3,50, H2,50,H1,25,M6,25,M6,25,H3,50,H3,50, H2,50,H1,25,M6,25,M6,25,H1,50,H1,50,H1,100,H1,100,Z0,10,
//逆着光行走任风吹雨打吧
M6,25,H3,50,H3,50,H2,50,H1,25,M6,25,M6,25,H3,50,H2,50,H1,25,M6,25,M6,25,H1,50,H1,50,H1,50,H1,100,Z0,25,
//晚风吹起你鬓间的白发 抚平回忆留下的疤
H1,50,H2,50,H2,25,H3,50,H6,25,H5,25,H5,50,H6,25,H5,25,H5,50,H6,25,H5,25,H5,50,H2,25, H3,25,H3,50,H6,25,H5,25,H5,50,H6,25,H5,25,H5,50,H6,25,H5,25,H5,25,H3,50,H3,50,Z0,5,
//你的眼中明暗交杂 一笑生花 暮色遮住你蹒跚的步伐
H2,50,H1,25,M6,25,M6,25,H1,50,M6,25,H2,25,H1,25,M6,50,M6,50, H1,50,H1,50,H3,100,H3,25,H4,25,H3,50,H3,25,H2,50,H2,50,H1,100,H2,100,H3,100,H6,25,H5,25,H5,50,H6,25,H5,25,H5,50,H6,25,H5,25,H5,50,H2,50,
//走进床头藏起的画 画中的你(低着头说话)
H3,50,H6,25,H5,25,H5,50,H6,25,H5,25,H5,50,H6,25,H5,25,H3,100,H3,50,H2,50,H1,25,M6,25,M6,25,H3,50,H3,50,H2,50,H1,25,M6,25,M6,25,H1,100,H1,50,Z0,5,
//我仍 了 以爱之名你还愿意吗(衔接头有问题)
H1,50,H2,50,H1,50,H1,100,M6,25,H3,50,H3,50,H2,50,H1,25,H6,25,H6,25,H3,50,H3,50,H2,50,H1,25,H6,25,H6,25,H1,50,H1,50,H1,100,Z0,5
};
int length = sizeof(wind_rise)/sizeof(wind_rise[0]);
for(int i=0;i<(length/2);i++)
{
buzzer_on(wind_rise[i*2],260);
HAL_Delay(wind_rise[i*2+1]*5);
}
}
可以打开视频看到演示效果
蜂鸣器演奏孤勇者