STM32无源蜂鸣器播放音乐

开发板:野火霸天虎V2
单片机:STM32F407ZGT6
开发软件:MDK+STM32CubeMX

文章目录

  • 前言
  • 一、找一篇音乐的简谱
  • 二、确定音调
  • 三、确定节拍
  • 四、使用STM32CubeMX生成初始化代码
  • 五、代码分析


前言

本实验使用的是低电平触发的无源蜂鸣器

无源蜂鸣器是指没有振荡源的蜂鸣器,因此必须使用一定频率的方波才能驱动它发声,所以无源蜂鸣器播放音乐的本质就是使用定时器的PWM,随着节奏拍调节延时、根据音符调节驱动信号的频率,这样就能播放音乐了。

STM32无源蜂鸣器播放孤勇者


一、找一篇音乐的简谱

找一篇稍微简单点的音乐的简谱,我这里找的是孤勇者。
孤勇者简谱

二、确定音调

① 确定音调,区分高中低音很简单,就看数字上方下方有没有点。
高中低音
② 确定音调对应的频率,如下图所示。
简谱音名和频率关系
③ 定义一个常量浮点型数组,把各音名对应的频率放入。

const float pitch_name_frequency[21] = {
	//低音
	//1		2		3		4		5		6		7
	261.63,	293.67,	329.63,	349.23,	391.99,	440,	493.88,//0-6
	//中音
	//1		2		3		4		5		6		7
	532.25,	587.33,	659.25,	698.46,	783.99,	880,	987.76,//7-13
	//高音
	//1		2		3		4		5		6		7
	1046.50,1174.66,1318.51,1396.92,1567.98,1760,	1975.52//14-20
};

④ 开始抄吧,定义一个常量无符号8位类型数组,把乐谱音名对应频率数组序号放入,抄的过程一定仔细,一不小心就可能抄错。怎么抄
0代表休止符,不发声,这里用21表示,方便后续判断处理,抄完结果如下,每一行都与简谱对应。

const uint8_t gu_yong_zhe[] = {
	9,21,21,7,8,7,9,21,7,8,7,8,9,5,7,5,7,5,7,8,7,
	6,21,21,9,21,21,7,8,7,9,21,7,8,7,8,9,5,7,5,7,5,7,9,8,6,21,21,
	5,7,12,12,12,12,11,12,12,11,12,11,12,11,9,9,9,21,21,5,7,12,12,12,11,12,11,13,13,13,12,13,    
	13,12,9,9,21,9,11,9,8,9,8,9,8,9,11,9,11,9,8,9,8,9,8,21,7,8,
	9,5,7,9,8,9,8,7,7,5,21,21,12,13,14,15,13,14,14,14,13,14,15,13,14,14,14,15,
	16,15,16,15,16,16,15,16,18,16,12,13,14,15,13,14,14,14,13,14,15,13,14,14,14,15,
	16,15,16,15,16,16,15,16,18,16,18,16,18,16,18,16,18,19,16,18,18,16,18,16,18,16,18,19,16,18,18,18,
	16,15,15,15,14,16,16,15,15,15,14,14,12,21,21,18,18,16,15,15,15,14,16,16,15,15,15,14,14,12,21,21,
	21,21,21,21,21,21,21,21,21,21,21,21,12,11,12,11,12,11,12,11,12,12,11,12,11,12,11,
	9,9,9,21,21,12,11,12,11,12,11,12,11,13,13,13,12,13,12,9,9,9,21,21,9,11,9,
	8,9,8,9,8,9,11,9,11,9,8,9,8,9,8,21,7,8,9,12,14,16,15,16,15,14,14,12,21,12,13,
	12,5,7,9,13,13,13,13,12,12,12,21,5,7,9,13,13,13,13,12,12,12,21,12,13,12,21,21
};

三、确定节拍

确定音乐的节拍,也就是PWM持续的时间,即延时时间。
节拍
我们看表格的第一列,音符右方、下方的短横线和右方的圆点共同表示音符的时长。
以音符5为例,设音符 5 (即1拍)延时时间tdelay=4x
右方增加1条横线表示延时时间增加1倍,5 - 的延时时间tdelay=8x,加2条横线表示增加2倍,5 - -的延时时间tdelay=12x。
右方增加1个圆点表示延时时间增加一个半拍,5 · 的延时时间tdelay=6x。
下方增加1条横线表示延时时间减少一半,tdelay=2x,下方增加2条横线表示延时时间减少为1/4,tdelay=x。

因为孤勇者中最小的是1/4拍,因此取1/4拍为单位时间,定义一个常量无符号8位类型数组,将简谱上音名对应节拍抄入,又是一个漫长的过程。
抄入节拍
结果如下。

const uint8_t beat[] = {
	8,4,1,1,1,1,8,3,1,1,1,1,1,3,1,3,1,3,1,2,2,
	8,4,4,8,4,1,1,1,1,8,3,1,1,1,1,1,3,1,3,1,3,1,2,2,8,4,4,
	1,1,2,1,1,1,1,2,1,1,1,1,1,1,1,3,4,4,2,1,1,3,1,1,1,1,1,3,1,1,1,2,
	1,2,1,8,1,1,1,1,3,1,3,1,3,1,1,1,1,1,3,1,3,1,4,2,1,1,
	2,2,2,2,3,1,1,1,2,8,4,2,1,1,1,1,1,1,2,1,1,1,1,1,1,2,1,1,
	1,1,1,1,2,1,1,2,2,2,1,1,1,1,1,1,2,1,1,1,1,1,1,2,1,1,
	1,1,1,1,2,1,1,2,2,2,2,3,1,3,1,1,1,1,1,2,2,3,1,3,1,1,1,1,1,2,1,1,
	1,1,2,2,1,1,1,1,2,2,1,1,8,4,2,1,1,1,1,2,2,1,1,1,1,2,2,1,1,8,4,4,
	4,4,4,4,4,4,4,4,4,4,4,4,2,1,1,3,1,1,1,1,1,2,1,1,1,1,1,1,
	1,3,4,4,2,1,1,3,1,1,1,1,1,3,1,1,1,1,1,1,3,4,4,1,1,1,1,
	3,1,3,1,3,1,1,1,1,1,3,1,3,1,4,2,1,1,2,2,2,2,3,1,1,1,2,12,2,1,1,
	2,2,2,2,4,2,1,1,1,3,12,2,2,2,2,4,2,1,1,1,3,8,2,1,1,8,4,4
};

四、使用STM32CubeMX生成初始化代码

点击Clock Configuration配置时钟树,F407ZGT6最大时钟为168MHz。
时钟树
点击Pinout & Configuration配置RCC。
RCC
配置SYS。
SYS
配置TIM时钟源为内部时钟,通道1为PWM生成。
在这里插入图片描述
配置参数,PSC设置为0不分频,ARR、Pulse都可以设置为0,因为后面程序中会修改的,注意Mode设置为PWM Mode 1,CH Polarity(通道有效极性)设置为0,因为我使用的是低电平触发的无源蜂鸣器。
参数
将TIM2通道1的GPIO引脚速度改为高。
GPIO
点击Project,配置工程名、位置、IDE及IDE版本。
1
勾选这两项,将所有库文件复制到工程文件夹、每个初始化外设生成一个.c和.h文件,下面这项必勾。
2
生成代码,打开工程。

五、代码分析

ARR寄存器的值控制着PWM的周期、频率,因为F407 TIM2时钟已经配置为不分频,所以fcnt=84M,Tcnt=1/84 * 10-6s,Tpwm = ARR * Tcnt ,所以fcnt = ARR * fpwm,ARR = fcnt / fpwm, fcnt=84M,fpwm音调对应频率pitch_name_frequency[gu_yong_zhe[i]]。开始生成PWM,根据节拍延时一段时间,关闭PWM。注意关闭PWM后清零CNT计数器,不然会发生错误。代码:__HAL_TIM_SetCounter(&htim2, 0);

void play_music(void)
{
	uint32_t i, delay_time, tune;
	for(i=0;i<(sizeof(gu_yong_zhe)/sizeof(gu_yong_zhe[0]));i++)
	{
		delay_time = beat[i] * 250; //250ms 1/4拍, 1s 1拍
		if(gu_yong_zhe[i] != 21) // 不是休止符
		{
			tune = (uint32_t)84*1000*1000/pitch_name_frequency[gu_yong_zhe[i]];
//			__HAL_TIM_SetAutoreload(&htim2, tune); // 和下一句作用一样
			TIM2->ARR = tune; // 改变频率
//			__HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_1, tune/2); // 和下一句作用一样
			TIM2->CCR1 = tune/2; // 占空比为50%
			HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);
			HAL_Delay(delay_time); // 根据节拍延时
			HAL_TIM_PWM_Stop(&htim2, TIM_CHANNEL_1);
			__HAL_TIM_SetCounter(&htim2, 0); // CNT寄存器值清0,不然会发生错误
		}
		else // 是休止符
		{
			HAL_TIM_PWM_Stop(&htim2, TIM_CHANNEL_1);
			HAL_Delay(delay_time);
		}
	}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/648304.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

微信小程序文本框输入显示已经输入的字数

我们遇到这样的需求&#xff0c;就是微信小程序的输入框下面需要显示输入的字数&#xff1a; 我们通常会使用bindinput事件&#xff0c;让显示的字数等于value的长度&#xff0c;看下面的图&#xff1a; 但在实践中&#xff0c;真机测试中&#xff0c;我们会发现以下问题: 这个…

C++笔记之Unix时间戳、UTC、TSN、系统时间戳、时区转换、local时间笔记

C++笔记之Unix时间戳、UTC、TSN、系统时间戳、时区转换、local时间笔记 ——2024-05-26 夜 code review! 参考博文 C++笔记之获取当前本地时间以及utc时间

深入分析 Android Activity (四)

文章目录 深入分析 Android Activity (四)1. Activity 的生命周期详解1.1 onCreate1.2 onStart1.3 onResume1.4 onPause1.5 onStop1.6 onDestroy1.7 onRestart 2. Activity 状态的保存与恢复2.1 保存状态2.2 恢复状态 3. Activity 的启动优化3.1 延迟初始化3.2 使用 ViewStub3.…

【C语言】自定义类型:联合与枚举的简明概述

&#x1f525;引言 关于自定义类型除了我们常用的结构体&#xff0c;还有联合与枚举也是属于自定义类型。本篇将简单介绍联合与枚举基本概念和使用方法 &#x1f308;个人主页&#xff1a;是店小二呀 &#x1f308;C语言笔记专栏&#xff1a;C语言笔记 &#x1f308;C笔记专栏&…

基于jeecgboot-vue3的Flowable新建流程定义(三)

因为这个项目license问题无法开源&#xff0c;更多技术支持与服务请加入我的知识星球。 接上一节 8、同时可以进行流程的编辑 /** 编辑流程设计弹窗页面 */const handleLoadXml (row) > {console.log("handleLoadXml row",row)designerData.title "流程设…

Unity学习日志

目录 获取相机可视范围的世界坐标(2D) 视口转世界坐标和屏幕转世界坐标的区别: 屏幕转世界坐标 视口转屏幕坐标 视口转屏幕结合3D数学实现可视范围的怪物生成 transform.up游戏对象的方向问题 其实还有一种不用Translate的写法: 修改 transform.up 的行为和影响 C#抽象…

ROM的简单实现

描述 实现一个深度为8&#xff0c;位宽为4bit的ROM&#xff0c;数据初始化为0&#xff0c;2&#xff0c;4&#xff0c;6&#xff0c;8&#xff0c;10&#xff0c;12&#xff0c;14。可以通过输入地址addr&#xff0c;输出相应的数据data。 接口信号图如下&#xff1a; 使用Veri…

MIPS汇编语言详解

MIPS&#xff08;Microprocessor without Interlocked Pipeline Stages&#xff09;是一种精简指令集计算机&#xff08;RISC&#xff09;架构&#xff0c;由MIPS计算机系统&#xff08;现在是MIPS Technologies&#xff09;开发。它以其简单性和效率而闻名&#xff0c;特别适用…

【数据结构】排序算法大全(快速、堆、归并、插入、折半、希尔、冒泡、计数、基数)各算法比较、解析+完整代码

文章目录 八、排序1.插入排序1.1 直接插入排序1.2 折半插入排序1.3 希尔排序 2.交换排序2.1 冒泡排序2.2 快速排序 3.选择排序3.1 简单选择排序3.2 堆3.2.1 堆排序3.2.2 堆插入删除*完善代码 堆 4.归并、基数、计数排序4.1 归并排序4.2 基数排序4.3 计数排序 5.内部排序算法的比…

PCL 二维凸包切片法计算树冠体积

目录 一、算法原理1、原理概述2、参考文献二、代码实现三、结果展示本文由CSDN点云侠原创,原文链接。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的爬虫与GPT。 一、算法原理 1、原理概述 二维凸包法是先将树冠等间隔分层切片,如图(e)采用二维凸包算法对每层…

中国改革报是什么级别的报刊?在哪些领域具有较高的影响力?

中国改革报是什么级别的报刊&#xff1f;在哪些领域具有较高的影响力&#xff1f; 《中国改革报》是国家发展和改革委员会主管的全国性综合类报纸。它在经济领域和改革发展方面具有重要的影响力&#xff0c;是传递国家政策、反映改革动态的重要平台。该报对于推动中国的经济改…

实验室课程|基于SprinBoot+vue的实验室课程管理系统(源码+数据库+文档)

实验室课程管理系统 目录 基于SprinBootvue的实验室课程管理系统 一、前言 二、系统设计 三、系统功能设计 1管理员功能模块 2学生功能模块 3教师功能模块 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&#xff1a; 博主介…

PyTorch深度学习实战(44)——基于 DETR 的目标检测模型

PyTorch深度学习实战&#xff08;44&#xff09;——基于 DETR 的目标检测模型 0. 前言1. Transformer1.1 Transformer 基础1.2 Transformer 架构 2. DETR2.1 DETR 架构2.2 实现 DETR 模型 3. 基于 DETR 实现目标检测3.1 数据加载与模型构建3.2 模型训练与测试 小结系列链接 0.…

WindowsCMD窗口配置OhMyPosh

WindowsCMD窗口配置OhMyPosh 文章目录 WindowsCMD窗口配置OhMyPosh1. 按装Clink1. 安装Oh-My-Posh2. 安装Clink2. 安装后的位置 2. 编写Lua脚本1. oh-my-posh Lua脚本2. 重启cmd窗口看效果 OhMyPosh对Windows CMD 没有现成的支持。 然而可以使用Clink来做到这一点&#xff0c;它…

深度学习——自己的训练集——训练模型(CNN)

训练模型 1.导入必要的库2.加载类别名称3.创建标签映射字典4.加载图像数据和对应的标签5.构建和编译CNN模型6.训练模型7.保存训练好的模型 1.导入必要的库 导入处理数据和训练模型时需要的库 os: 这个模块提供了与操作系统交互的功能&#xff0c;比如文件和目录操作。 cv2: 这…

2024-5-10-从0到1手写配置中心Config之Spring Value热更新

定义SpringValueProcessor处理类 实现BeanPostProcessor后置处理器接口&#xff0c;扫描所有的Spring value&#xff0c;保存起来。实现ApplicationListener接口&#xff0c;在配置变更时&#xff0c;更新所有的spring value 实现BeanPostProcessor后置处理器接口 实现postPr…

移动云:连接未来的智慧之旅

随着数字化转型的加速&#xff0c;云服务在各行各业中的应用越来越广泛。移动云不仅提供了灵活的计算和存储资源&#xff0c;还通过创新的技术手段&#xff0c;为企业和开发者解决了许多实际问题。在这个变革的大背景下&#xff0c;移动云服务作为中国移动倾力打造的云业务品牌…

155. 最小栈

题目&#xff1a; 设计一个支持 push &#xff0c;pop &#xff0c;top 操作&#xff0c;并能在常数时间内检索到最小元素的栈。 实现 MinStack 类: MinStack() 初始化堆栈对象。void push(int val) 将元素val推入堆栈。void pop() 删除堆栈顶部的元素。int top() 获取堆栈顶…

深入解析内置模块OS:让你的Python代码更懂操作系统

新书上架~&#x1f447;全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目录 一、OS模块简介与基础应用 二、文件与目录操作详解 三、OS模块的高级应用&#xff1a;双色…

【算法】前缀和——除自身以外数组的乘积

本节博客是用前缀和算法求解“除自身以外数组的乘积”&#xff0c;有需要借鉴即可。 目录 1.题目2.前缀和算法3.变量求解4.总结 1.题目 题目链接&#xff1a;LINK 2.前缀和算法 1.创建两个数组 第一个数组第i位置表示原数组[0,i-1]之积第二个数组第i位置表示原数组[i1,n-1]…