前言
在8051及stm32各类教辅资料中,均有无源蜂鸣器相关的实验。可以通过单片机控制无源蜂鸣器发出指定频率和时长的声音,从而实现播放音乐的功能。
在以往的此类案例中,乐谱的谱写非常不方便,除了案例提供的乐谱数据外,学者要将一个其它的简谱转换成单片机可以播放的数据,基本不可能实现。另外在以往的案例中,音乐的播放也比较单调粗糙。
今天要分享的内容,是通过stm32f103x单片机控制无源蜂鸣器播放音乐《猪八戒背媳妇》片段,以此向大家展示如何可以自由的将简谱转换成单片机可以播放的程序数据。
效果展示
说教是比较枯燥的,我们先看下成品效果:
stm32f103 控制无源蜂鸣器播放音乐《猪八戒背媳妇》
Keil 工程
以上展示效果的完整的keil工程,见附件。
主程序展示
在stm32程序中,我们以main.c中定义实现我们需要的功能,下面是上述视频效果的main.c程序
#include "stm32f10x.h" // Device header
#include "tone.h" //提供音乐播放接口
#include "music.h" //提供简谱数据接口,可以方便的将简谱转换为程序数据
#include "delay.h" //提供延时功能
#include "dyyOLED.h" //提供oled显示功能
MusicalNotation_t song;
// 歌曲简谱
Note123_e song_notes[] = { note1, note6_l, note3, note5,
note3, note6_l, note1,
note6_l, note1, note6_l, note1, note3,
note3, note2, note3, note1, note6_l,
note3, note5, note6, note6,
note6, note3, note5,
note3, note5, note3, note5, note6, note6,
note6, note3, note5,
note5, note6_l, note5, note6_l,
note4, note2, note3, note1,
note2, note2,
note2, note1, note2, note3, note5,
note6, note3_h,
note3, note3_h,
note3, note3_h, note3, note3_h,
note4, note2, note3, note1,
note2, note2,
note2, note1, note2, note3, note5,
note6};
float song_beats[] = { 0.25, 1.0, 0.75, 0.25,
0.5, 0.5, 1.0,
0.25, 0.25, 0.25, 0.25, 1.0,
0.25, 0.25, 0.25, 0.25, 1.0,
0.75, 0.25, 0.5, 0.5,
0.5, 0.5, 1.0,
0.25, 0.25, 0.25, 0.25, 0.5, 0.5,
0.5, 0.5, 1.0,
0.5, 0.5, 0.5, 0.5,
0.5, 0.25, 0.25, 1.0,
1.0, 1.0,
0.5, 0.25, 0.25, 0.5, 0.5,
1.0, 1.0,
1.0, 1.0,
0.5, 0.5, 0.5, 0.5,
0.5, 0.25, 0.25, 1.0,
1.0, 1.0,
0.5, 0.25, 0.25, 0.5, 0.5,
2.0};
int main(void){
delay_init(); //初始化延时函数
toneInit(TIM2, TIM_Channel_1); //配置定时器和输出端口,并以此端口驱动无源蜂鸣器发声
oledInit(); //初始化 oled 功能
char song_name[] = "zhuBaJie";
float song_beatSpd_bpm = 88; //以 4分音符 为准的拍速,如果乐曲是以 8分音符为基准定义的拍速,则需要 / 2 换算成以 4分音符 为准的拍速
song.name = song_name; //曲名
song.beatSpd_bpm = song_beatSpd_bpm; //以 4分音符为准的 拍速
song.notationBase = note_c1; //调式,note_c1 即为 C 调, note_d1 即为 D 调, 以此类推, note_g1 即为 G 调
song.notes = song_notes; //简谱的音符序列
song.beats = song_beats; //简谱每一个音符的拍数:如果单独一个音符,则为1, 如果有一个下划线,则为0.5;如果有两个下划线,则为 0.25; 如果后面有跟n个短横线,则 +n
song.notesCount = sizeof(song_notes) / sizeof(song_notes[0]); //计算音符数量
song.beatsCount = sizeof(song_beats) / sizeof(song_beats[0]); //计算节拍数量
oledShowString(1, 1, "Music playing..."); //在 oled 屏上显示一行消息(第1行)
while (1)
{
oledClearLane(2); //清空 oled 屏第2行
oledShowString(2,1,song.name); //在 oled 屏第2行显示乐曲名称
song.playIdx = 0; //复位播放位置
while (!playOver(&song)){ //如果没有播放完,则一直循环
toneSing(getNoteFre(&song)); //获取简谱播放位置的音符对应的声音频率,并播放该频率的声音
delay_ms(getNoteBeat(&song) * 60000.0f / song.beatSpd_bpm); //获取简谱播放位置的音符时长,并延时时长的时间
toneQuiet(); //停止音符的播放
song.playIdx++; //后移播放位置
delay_ms(5); //延时5ms
}
delay_ms(1000); //1s 后,循环播放下一首音乐
}
}
音符的表示
在以
标签:蜂鸣器,song,0.25,note3,0.5,stm32,无源,播放,音符 From: https://blog.csdn.net/weixin_42148809/article/details/145083585