最近学习stm32芯片,使用的是蓝桥杯的f103的旧板子,看到上面有蜂鸣器,所以就想写代码来控制蜂鸣器播放一首音乐。
  这里我参考了这篇文章基于STM32F103,用蜂鸣器播放歌曲。同这篇文章一样,我也遇到了蜂鸣器发出的声音不对。参考了这篇文章,以及查找网上的其他资料,最终完成了蜂鸣器的调试,以及歌曲的编写,文章最后会附上代码。
  先对音符这类东西进行说明吧。因为自己也不是学音乐的,一些关于音乐的知识都是网上搜集的,所以如果有讲得不对的地方,也请各位读者在评论指正,我会及时改正。
  首先在百度上搜索每个音符的频率,这里我参考的是音符与频率对照表

其实对于哪个调来说,我感觉不出来什么差别(可能我没有什么艺术细胞吧),而且在代码里我的音符的频率对应图片里的音符的频率是高一个八度。【如下图】

//               0   1    2  3   4   5   6   7  8   9  10   11  12  13   14   15
//              低7 1    2  3   4   5   6   7  高1 高2 高3  高4 高5 高6  高7    高高1
uc16 tone[] = {247,262,294,330,349,392,440,494,523,587,659,698,784,880,988,1046,0};

  也许我上面说的有些迷糊,但是我们通过上面那张表就可以得到每个音符所对应的频率,这个是我们需要的。
  有了每个音符的频率还不够,我们还需要知道每个音符持续的时间,也就是音符时值。
  这里我拿我的选的一个曲子举例子。

  Eb\text{Eb}Eb指的是曲子的调是Eb调,(每个调之前的区别,我个人感觉不出大差别,所以我的音符频率是按C调频率来的),后面的44\frac4444​指的是以四分音符为一拍,一小节四拍。在后面的音符=120,指的是一分钟120拍,所以我们从这里就可以知道,一个四分音符的时值是0.5s.
那么什么是四分音符呢?

  如上图,音符下面有三条横线的,就是三十二分音符,有两条横线的就是十六分音符,一条横线的就是八分音符,没有横线的就是四分音符
  这些音符对应的时值分别为(设四分音符的时值为ttt)

  • 四分音符=ttt
  • 八分音符=t/2t/2t/2
  • 十六分音符=t/4t/4t/4
  • 三十二音符=t/8t/8t/8

  除了上面四个音符外,有时谱子里还会遇到一个音符跟着一个小点,这种称为附点

有附点的音符的时值,与附点跟随的音符有关。附点的时值为跟随的音符时值的一半。所以有附点的音符的时值为 跟随的音符的时值×1.5

例如,图中的3˙.‾\underline{\dot 3.}3˙.​的时值计算如下
设四分音符的时值为 ttt
3˙‾\underline{\dot 3}3˙​为八分音符,时值为 t/2t/2t/2
附点的时值为跟随音符的时值的一半,在这里也就是 t/4t/4t/4
因此 3˙.‾\underline{\dot 3.}3˙.​ 的时值为t/2+t/4=3t/4t/2+t/4=3t/4t/2+t/4=3t/4
//--------------------------------------------------------------------------
举一反三 6.6.6.的时值计算如下
设四分音符的时值为 ttt
666为四分音符,所以时值为 ttt
附点为跟随音符的时值的一半,为 t/2t/2t/2
所以 6.6.6.的时值为 t+t/2=3t/2t+t/2=3t/2t+t/2=3t/2

  关于音符的介绍差不多就到这里了,接下来就是代码相关的东西了。
【蜂鸣器的控制就不用我说了吧,一般原理图上都是用三极管驱动蜂鸣器,所以引脚出高低就能控制蜂鸣器的叫与不叫,至于引脚出高还是低,蜂鸣器响,具体的还是看自己板子上的原理图吧】
首先是定义一个音符的频率数组,至于数组中的数从哪来,可以参考我前面发的音符频率对照表,或者要是知道音符频率的关系,自己算也可以。

//               0   1    2  3   4   5   6   7  8   9  10   11  12  13   14   15
//              低7 1    2  3   4   5   6   7  高1 高2 高3  高4 高5 高6  高7    高高1
uc16 tone[] = {247,262,294,330,349,392,440,494,523,587,659,698,784,880,988,1046,0};

接下来就是写谱子的音符,这里我就截我选的曲子

蓝色线截选的音符,就是我让单片机播放的曲子片段。
相应的音符数组如下

u8 BrokenMoon[]={3,5,6,8,9,8,9,10,8,6,5,3,8,9,6,6,8,9,8,9,10,12,13,15,14,13,14,13,12,13,12,10,9,10,8,9,8,9,10,6,8,9,8,6,6,5,6,5,6,8,9,10,9,5,6
};

数组里对应的数字,就是tone数组的元素下标,也就是每个音符。
  然后是关于音符时值的数组【每个音符具体的时值与你选的谱子的曲速和音符种类有关,我在上面都讲解了一下,如果还是没看懂的话,可以去B站看看相关知识,大概几分钟就可以看完】

//因为我选的曲子速度是每分钟120拍,所以可以算出每个音符相对应时值
//时值 全音符2s  二分音符 1s 四分音符 0.5s 八分音符 0.25s
//     十六分音符 0.125s     三十二分音符 0.0625s
//比例为32:1
//全音符 64    二分音符 32 四分音符 16 八分音符 8
//十六分音符 4 三十二分音符 2u8 scale = 16;//每个音符时值放大的比例,用于将时值数组转换为实际的时间长度
//其实scale的值应该为32,但是测试的时候,感觉播放的速度过快,所以调成16
//大家在实际操作的时候,也可以改一改,但是建议能不改scale的值就别改scale的值
u8 BrokenMoonTime[]={8,8,8,8,16,8,8,16,8,8,8,8,8,8,16,8,8,16,8,8,16,8,8,8,8,2,2,4,8,16,8,8,16,8,8,16,8,8,12,4,4,4,8,16,8,8,12,2,2,8,8,8,8,16,32
};

  准备好音符和时值数组之后,一个重要的函数就来了。

void BUZZER_Play(u16 frq){u32 time;if(frq){//      time = 500000/((u32)frq);//单个脉冲的高电平持续时间(单位为us)为1*10^6/2f=500000/f f为音符的频率time = 50000/((u32)frq);BUZZER_ON();delay_us(time);BUZZER_OFF();delay_us(time*9);//调节占空比}else delay_us(1000);
}

  这是用蜂鸣器播放一个脉冲的函数。函数的参数,频率frq,即单个音符对应频率。函数执行的就是蜂鸣器播放该频率下的一个脉冲。
  根据,之前的参考的文章,他们的设置高电平的占空比为50%,但我具体测试的时候,发现修改time的值虽然会有使音色改善,但也造成了播放速度过快,后面想了想,觉得蜂鸣器的占空比为50%不太合理,根据测试,选择了10%的占空比,大家具体测试的时候,如果发现音色不好,可以修改高电平的占空比。

具体方法如下:

  1. 先将time= 500000/((u32)frq);写到BUZZER_Play()函数里,然后让蜂鸣器响和不响的延时时间都相同,为time
  2. 下载代码测试音色,根据实际情况,修改time = 500000/((u32)frq)中的500000的值,直到自己一个满意的效果。然后比较修改后time的值与原来time = 500000/((u32)frq)的。将原来time值假设为t0t_0t0​,调试完之后的值为t1t_1t1​
  3. 将蜂鸣器响的延迟时间设置为t1t_1t1​,将蜂鸣器关闭的延迟时间设置为t0−t1t_0-t_1t0​−t1​

修改完的代码,样子如下

void BUZZER_Play(u16 frq){u32 time;if(frq){time = m/((u32)frq);//m根据实际测试结果进行修改BUZZER_ON();delay_us(time);BUZZER_OFF();delay_us(t_0-t_1);//t_0-t_1的值根据实际测试结果计算出来的}else delay_us(1000);
}

  写完播放一个固定频率的脉冲之后,就是写在一段时间内播放固定频率的脉冲的函数。

void MUSIC_Play(void){u16 i,j;for(i=0;i<i<sizeof(music)/sizeof(music[0]);i++)for(j=0;j<((u16)time[i])*tone[music[i]]/scale;j++) //time[i]*tone[music[i]]表示的是脉冲个数BUZZER_Play((u32)tone[music[i]]);
}

对于第一个循环语句

for(i=0;i<i<sizeof(music)/sizeof(music[0]);i++)

sizeof(music)/sizeof(music[0])的效果等价于求music数组的长度,所以这里的循环就是读取数组中的每个音符。

这个函数里最重要的一句就是

for(j=0;j<((u16)time[i])*tone[music[i]]/scale;j++)

  前面说过time数组是music中对应音符的时值,scale是将音符时值放大的比例,之所以要放大音符的时值就是为了避免数组中存在小数,方便书写和储存。因此在计算脉冲个数的时候就需要变换回实际的时值,所以除以放大的比例。【可以发现这是整数除法,会舍弃小数,所以存在一点误差,不过问题也不大】
  所以(u16)time[i])*tone[music[i]]/scale表示的就是脉冲的个数,也就是执行BUZZER_Play()的次数。

  好了,讲完了所用的函数,我们就应该从总体上来分析,我们为什么这么写。首先蜂鸣器的发声频率不同就会产生不同的声音,因此我们控制蜂鸣器开关时间就可以控制蜂鸣器的产生不同频率的声波。


具体就是控制高低电平的时间,产生不同的声音,产生脉冲的个数就是其持续的时间。

最后贴一个我的代码。

//               0   1    2    3   4    5   6    7   8    9   10   11  12  13   14   15
//              低7 1    2    3   4    5   6    7   高1  高2 高3  高4 高5 高6  高7  高高1
uc16 tone[] = {247,262,294,330,349,392,440,494,523,587,659,698,784,880,988,1046,0};u8 scale = 16;//每个音符时值放大的比例,用于将时值数组转换为实际的时间长度u8 BrokenMoon[]={3,5,6,8,9,8,9,10,8,6,5,3,8,9,6,6,8,9,8,9,10,12,13,15,14,13,14,13,12,13,12,10,9,10,8,9,8,9,10,6,8,9,8,6,6,5,6,5,6,8,9,10,9,5,6
};
u8 BrokenMoonTime[]={8,8,8,8,16,8,8,16,8,8,8,8,8,8,16,8,8,16,8,8,16,8,8,8,8,2,2,4,8,16,8,8,16,8,8,16,8,8,12,4,4,4,8,16,8,8,12,2,2,8,8,8,8,16,32
};void BUZZER_Play(u16 frq){u32 time;if(frq){//      time = 500000/((u32)frq);//单个脉冲的高电平持续时间(单位为us)为1*10^6/2f=500000/f f为音符的频率time = 50000/((u32)frq);BUZZER_ON();delay_us(time);BUZZER_OFF();delay_us(time*9);//调节占空比}else delay_us(1000);
}void MUSIC_Play(u8 *music,u8 *time,u16 length){u16 i,j;for(i=0;i<length;i++)for(j=0;j<((u16)time[i])*tone[music[i]]/scale;j++) //time[i]*tone[music[i]]表示的是脉冲个数BUZZER_Play((u32)tone[music[i]]);
}void MUSIC1_Play(void){MUSIC_Play(BrokenMoon,BrokenMoonTime,sizeof(BrokenMoon)/sizeof(BrokenMoon[0]));
}

这里我想修改代码方便调用,就将MUSIC_Play(u8 *music,u8 *time,u16 length)封装起来方便调用,暂时还没测试可行性,等我测试完之后,看实际情况进行修改,大家如果有什么代码建议也可以发表在评论,一起讨论讨论

stm32蜂鸣器播放音乐相关推荐

  1. STM32蜂鸣器播放音乐实例项目 【评论区留言领取项目资料】

    本文用STM32单片机蜂鸣器来演奏音乐,用的开发软件是STM32CubeIDE. 实验效果 蜂鸣器 有源蜂鸣器 内部有震荡源,只要通电就会有响声,但是声音频率固定. 无源蜂鸣器 内部不含振荡源,蜂鸣器 ...

  2. FPGA蜂鸣器播放音乐

      最近做EDA课设,看到自己的买的板子上有蜂鸣器,所以就打算做一个FPGA控制蜂鸣器播放音乐.   这里我使用的板子是睿智助学的FPGA开发板,板子上的芯片是EP4CE6E22C8,如果是你使用的是 ...

  3. stm32无源蜂鸣器定时器_STM32无源蜂鸣器播放音乐

    1.STM32产生PWM波驱动无源蜂鸣器使其发声 1)查看原理图,找到对应引脚(我这里时PA1) 2)打开CubeMax,输入自己芯片的类型确定后,配置好系统时钟RCC,我这里是80Mhz,找到相应引 ...

  4. 蜂鸣器播放音乐 fpga实现

    目录 原理 实现 原理 蜂鸣器分为有源蜂鸣器和无源蜂鸣器,即以有无震荡源分类, 有震荡源直接通直流电就可发生,无震荡源则需要通震荡波才能发声. 这里介绍无源蜂鸣器播放音乐的方法. 思路: 利用计数器产 ...

  5. 【FPGA】五、蜂鸣器播放音乐

    文章目录 前言 一.蜂鸣器简介 二.音频音符简介 三.任务要求 四.程序设计 1.设计思路 2.程序代码 总结 前言 蜂鸣器(Buzzer)是现代常用的一种电子发声器,主要用于产生声音信号.它是一种一 ...

  6. 单片机并行口控制蜂鸣器播放音乐

    要用单片机并行口控制蜂鸣器播放音乐,需要完成以下步骤: 设计音乐:需要先确定音乐的节拍和音符,并将其转换为代码中的数值. 设置并行口:需要将单片机的并行口配置为输出模式,以便控制蜂鸣器. 编写代码:需 ...

  7. MCU-51:单片机蜂鸣器播放音乐和提示音

    目录 一.蜂鸣器介绍 二.驱动电路 2.1 三极管驱动 2.2 集成电路驱动 三.蜂鸣器播放音乐 3.1 键盘与音符对照 3.2 音符与频率对照 3.3 简谱 四.代码演示 4.1 按键蜂鸣器播放提示 ...

  8. 51单片机_11-2 蜂鸣器播放音乐

    文章目录 要求 资源 main函数 要求 控制蜂鸣器播放音乐 资源 工程文件压缩包 链接:https://pan.baidu.com/s/1hA-aa0JRP33IlOYFNzKf7A 提取码:0id ...

  9. Arduino 蜂鸣器播放音乐LED灯闪烁

    一.实验所需组件: led灯 三脚蜂鸣器 面包板 Arduino开发板 杜邦线 二.实验原理 蜂鸣器实现音乐播放: 控制好频率和节拍,就能演奏出好听的音乐.因此,在实验之前要先弄清楚各音调的频率.可参 ...

  10. STC-B学习板蜂鸣器播放音乐

    功能:单片机烧录好程序后,按key1按键播放<IF YOU>,再次按key1可暂停播放,按key2可切换歌曲到<国际歌>,再按key3可切换歌曲到<孤勇者> 芯片: ...

最新文章

  1. 财务大数据比赛有python吗-大数据工作内容有哪些?老男孩Python数据培训
  2. 右键新建里面没有word和excel_Excel中为什么修改了新建工作簿的选项,新建以后还是没有生效...
  3. 大数据可视化设计需遵守什么原则
  4. 凸包算法(Convex Hull Algorithm)
  5. RapidScada免费开源Scada组态软件系列教程1-初识RapidScada
  6. php将日期转为时间戳,php将指定日期转换为时间戳的方法
  7. JavaWeb学习笔记——Mac os下在idea中创建Web项目以及部署Tomcat
  8. VMware Workstation 10.0.7 安装
  9. 计算机启动显示不正确的分区表,分区表无效怎么办_一开机就显示分区表无效怎么解决...
  10. ChatGPT专业应用:自动生成长尾关键词
  11. 【AD小知识】PCB布线理论及实际操作
  12. HDU - 2014 青年歌手大奖赛_评委会打分
  13. android x86 v2ex,v2ex签到脚本改进 - 就爱阅读网
  14. Ambari配置邮件警告--监控大数据平台
  15. win本地安装xxl-job服务
  16. 如何快速保存PPT中的图片资源
  17. 小空同学的第一次文学尝试
  18. eNSP网络仿真软件配置局域网vlan
  19. CAD中用多重插入块加密的图纸怎么分解?
  20. USB 2.0 A型、B型、Mini和Micro接口 type-c 定义及封装

热门文章

  1. kmz文件转为arcgis的图层(制作底图)
  2. 重学数据结构:三对角矩阵公式推导过程
  3. CentOS5.8分区与文件系统
  4. android nfc读写demo,android nfc常用标签读取总结
  5. android6.0闪光灯源码,android手电筒+闪光灯基本源码_linux编程_linux公社-linux系统门户网站...
  6. 《给产品经理讲技术》笔记之第三章:开发技术
  7. oracle根据中文获取拼音全拼函数
  8. quartus仿真文件的编写
  9. DirectX修复工具有什么用
  10. 数据结构课程设计实验报告