STM32蜂鸣器播放音乐

news2025/3/29 12:59:20

STM32蜂鸣器播放音乐

STM32蜂鸣器播放音乐 Do, Re, Mi, Fa,

1. 功能概述

本系统基于STM32F7系列微控制器,实现了以下功能:

  1. 通过7个按键控制蜂鸣器发声,按键对应不同的音符。
  2. 每个按键对应一个音符(Do, Re, Mi, Fa, Sol, La, Si),按下按键时蜂鸣器播放对应音符的声音。
  3. 利用PWM技术控制蜂鸣器发声频率,实现不同音符的效果。
  4. 按键松开时蜂鸣器停止发声,防止连续触发。

在这里插入图片描述

2. 硬件接线

2.1 按键与GPIO连接

系统使用STM32F7的GPIOB端口,连接7个按键,其中:

  • 按键1: GPIO_PIN_0
  • 按键2: GPIO_PIN_1
  • 按键3: GPIO_PIN_3
  • 按键4: GPIO_PIN_4
  • 按键5: GPIO_PIN_5
  • 按键6: GPIO_PIN_6
  • 按键7: GPIO_PIN_7

每个按键的另一端连接到地(GND),GPIO引脚配置为上拉输入模式(GPIO_PULLUP)。

2.2 蜂鸣器与GPIO连接

蜂鸣器通过GPIOA的PA6引脚与STM32连接:

  • PA6配置为TIM3_CH1通道的PWM输出。
  • 蜂鸣器的一端连接到PA6,另一端连接到GND。

2.3 电源

  • STM32主控板通过USB供电。
  • 所有按键和蜂鸣器的电源均由STM32供电。

3. 软件实现原理

3.1 功能模块

软件设计主要包含以下功能模块:

3.1.1 PWM模块
  • 利用定时器TIM3的PWM功能产生控制蜂鸣器的信号。
  • 根据不同音符的频率设置PWM的周期(ARR)值,调整占空比控制音量。
3.1.2 按键扫描模块
  • 周期性读取GPIOB的引脚状态,判断按键是否按下。
  • 通过数组 KeyStatus[] 保存每个按键的状态(按下为1,松开为0)。
3.1.3 音符播放模块
  • 根据按键状态决定是否播放音符。
  • 使用Play_Tone()函数设置PWM频率并播放音符。
  • 使用Stop_Tone()函数停止蜂鸣器播放。

3.2 软件流程

3.2.1 主程序流程

主程序主要流程如下:

  1. 初始化系统时钟和HAL库。
  2. 配置GPIO用于按键输入和蜂鸣器输出。
  3. 初始化TIM3定时器的PWM功能。
  4. 主循环中:
    • 调用按键扫描函数Keypad_Read()更新按键状态。
    • 检查每个按键状态,对应播放音符。
    • 播放音符后延时一定时间避免重复触发。
    • 调用Stop_Tone()停止蜂鸣器播放。
3.2.2 按键扫描流程

按键扫描采用循环遍历方式:

  1. 定义GPIOB引脚的数组 pins[],保存每个按键对应的GPIO引脚。
  2. 遍历引脚数组,调用HAL_GPIO_ReadPin()读取每个按键状态。
  3. 如果引脚电平为低(GPIO_PIN_RESET),表示按键被按下。
  4. 更新 KeyStatus[] 数组。
3.2.3 音符播放流程

音符播放利用PWM实现:

  1. 根据音符频率计算PWM的自动重装载值(ARR)。
  2. 调用__HAL_TIM_SET_AUTORELOAD()更新TIM3的ARR值。
  3. 调用__HAL_TIM_SET_COMPARE()设置占空比。
  4. 开始PWM输出,蜂鸣器发声。
  5. 延时指定时间后停止PWM输出。

主函数代码:

#include "stm32f7xx.h"
#include "main.h"
#include "./tim/bsp_basic_tim.h"
#include "./led/bsp_led.h"
#include "./usart/bsp_usart.h"
#include "./beep_music/beep_music.h"
TIM_HandleTypeDef htimx; // 定义一个全局定时器句柄

void SystemClock_Config(void);
void PWM_Init(void);
void Set_PWM_Frequency(uint32_t frequency);
void Play_Music(int *tune, float *duration, int length);
/**
  * @brief  主函数
  * @param  无
  * @retval 无
  */
int main(void) 
{
	/* 初始化系统时钟为216MHz */
	SystemClock_Config();
	
	/* 初始化LED */
	LED_GPIO_Config();
	
  /* 初始化基本定时器定时,1s产生一次中断 */
	//TIMx_Configuration();
	PWM_Init();               // 初始化 PWM
	
//	int length = sizeof(tune) / sizeof(tune[0]); // 获取音符数量
//    Play_Music(tune, duration, length);
  
	
	play_music();	
	
	while(1)
	{   
		
	}
}

/**
  * @brief  System Clock 配置
  *         System Clock 配置如下 : 
  *         System Clock source            = PLL (HSE)
  *         SYSCLK(Hz)                     = 216000000
  *         HCLK(Hz)                       = 216000000
  *         AHB Prescaler                  = 1
  *         APB1 Prescaler                 = 4
  *         APB2 Prescaler                 = 2
  *         HSE Frequency(Hz)              = 25000000
  *         PLL_M                          = 25
  *         PLL_N                          = 432
  *         PLL_P                          = 2
  *         PLL_Q                          = 9
  *         VDD(V)                         = 3.3
  *         Main regulator output voltage  = Scale1 mode
  *         Flash Latency(WS)              = 7
  * @param  无
  * @retval 无
  */
void SystemClock_Config(void)
{
  RCC_ClkInitTypeDef RCC_ClkInitStruct;
  RCC_OscInitTypeDef RCC_OscInitStruct;
  HAL_StatusTypeDef ret = HAL_OK;

  /* 使能HSE,配置HSE为PLL的时钟源,配置PLL的各种分频因子M N P Q 
	 * PLLCLK = HSE/M*N/P = 25M / 25 *432 / 2 = 216M
	 */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLM = 25;
  RCC_OscInitStruct.PLL.PLLN = 432;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = 9;
  
  ret = HAL_RCC_OscConfig(&RCC_OscInitStruct);
  if(ret != HAL_OK)
  {
    while(1) { ; }
  }
  
  /* 激活 OverDrive 模式以达到216M频率  */  
  ret = HAL_PWREx_EnableOverDrive();
  if(ret != HAL_OK)
  {
    while(1) { ; }
  }
  
  /* 选择PLLCLK作为SYSCLK,并配置 HCLK, PCLK1 and PCLK2 的时钟分频因子 
	 * SYSCLK = PLLCLK     = 216M
	 * HCLK   = SYSCLK / 1 = 216M
	 * PCLK2  = SYSCLK / 2 = 108M
	 * PCLK1  = SYSCLK / 4 = 54M
	 */
  RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2);
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;  
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2; 
  
	/* 在HAL_RCC_ClockConfig函数里面同时初始化好了系统定时器systick,配置为1ms中断一次 */
  ret = HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_7);
  if(ret != HAL_OK)
  {
    while(1) { ; }
  }  
}



/**
 * @brief 配置系统时钟
 * @retval 无
 */

/**
 * @brief 初始化 PWM
 * @retval 无
 */
void PWM_Init(void)
{
    // 开启定时器和 GPIO 时钟
    __HAL_RCC_TIM3_CLK_ENABLE();  // 使用 TIM3 作为示例
    __HAL_RCC_GPIOA_CLK_ENABLE(); // 使用 GPIOA 作为示例

    // 配置 PWM 输出引脚
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    GPIO_InitStruct.Pin = GPIO_PIN_6;       // 使用 PA6(TIM3_CH1)作为 PWM 输出
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; // 复用推挽模式
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    // 配置定时器
    htimx.Instance = TIM3;                        // 定时器实例为 TIM3
    htimx.Init.Prescaler = (SystemCoreClock / 1000000) - 1; // 定时器频率分频到 1MHz (1μs 精度)
    htimx.Init.CounterMode = TIM_COUNTERMODE_UP;  // 向上计数模式
    htimx.Init.Period = 1000 - 1;                 // 默认周期,产生 1kHz 方波
    htimx.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
    htimx.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
    HAL_TIM_PWM_Init(&htimx);                     // 初始化定时器 PWM

    // 配置 PWM 通道
    TIM_OC_InitTypeDef sConfigOC = {0};
    sConfigOC.OCMode = TIM_OCMODE_PWM1;           // PWM 模式 1
    sConfigOC.Pulse = 500;                        // 默认占空比 50%
    sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;   // 高电平有效
    sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
    HAL_TIM_PWM_ConfigChannel(&htimx, &sConfigOC, TIM_CHANNEL_1); // 配置通道 1

    // 启动 PWM 输出
    HAL_TIM_PWM_Start(&htimx, TIM_CHANNEL_1);
}

/**
 * @brief 设置 PWM 输出频率
 * @param frequency 频率 (Hz)
 * @retval 无
 */
void Set_PWM_Frequency(uint32_t frequency)
{
    if (frequency == 0) // 如果频率为 0,停止 PWM 输出
    {
        __HAL_TIM_SET_COMPARE(&htimx, TIM_CHANNEL_1, 0);
        return;
    }

    uint32_t period = 1000000 / frequency; // 周期 = 1秒(1000000us) / 频率
    __HAL_TIM_SET_AUTORELOAD(&htimx, period - 1); // 设置自动重装载值
    __HAL_TIM_SET_COMPARE(&htimx, TIM_CHANNEL_1, period / 2); // 设置占空比为 50%
}

/**
 * @brief 播放音乐
 * @param tune 音符数组
 * @param duration 音符持续时间数组
 * @param length 音符数量
 * @retval 无
 */
void Play_Music(int *tune, float *duration, int length)
{
    for (int i = 0; i < length; i++)
    {
        if (tune[i] == 0) // 如果音符为 0,停止播放,表示间隔
        {
            Set_PWM_Frequency(0); // 停止 PWM
        }
        else
        {
            Set_PWM_Frequency(tune[i]); // 设置音符对应的频率
        }
        
        HAL_Delay(duration[i] * 1000); // 持续时间(将秒转换为毫秒)
    }

    Set_PWM_Frequency(0); // 播放完成后停止 PWM
}

/*********************************************END OF FILE**********************/

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

解码未来:DeepSeek开源FlashMLA,推理加速核心技术,引领AI变革

前言&#xff1a; DeepSeek 兑现了自己的诺言&#xff0c;开源了一款用于 Hopper GPU 的高效型 MLA 解码核&#xff1a;FlashMLA。 项目地址&#xff1a;https://github.com/deepseek-ai/FlashMLA 1:FlashMLA 是什么呀&#xff1f; MLA是DeepSeek大模型的重要技术创新点&…

leetcode:136. 只出现一次的数字(python3解法)

难度&#xff1a;简单 给你一个 非空 整数数组 nums &#xff0c;除了某个元素只出现一次以外&#xff0c;其余每个元素均出现两次。找出那个只出现了一次的元素。 你必须设计并实现线性时间复杂度的算法来解决此问题&#xff0c;且该算法只使用常量额外空间。 示例 1 &#xf…

Isaac Sim与Isaac Lab初使用

目录 基于Omiverse下载Isaacsim安装Isaac Lab配置isaacsim环境测试克隆仓库配置python环境强化学习训练的测试 IsaacLab模板配置vscode环境ros接口安装 作为nvidia出品的仿真软件&#xff0c;很多机器人、机器狗【具身智能】都可以有很不错的效果&#xff0c;所以会使用isaac s…

Spring AI Alibaba 工具(Function Calling)使用

一、工具(Function Calling)简介 Spring AI Alibaba工具(Function Calling)&#xff1a;https://java2ai.com/docs/1.0.0-M6.1/tutorials/function-calling/ 1、工具(Function Calling) “工具&#xff08;Tool&#xff09;”或“功能调用&#xff08;Function Calling&#xf…

Touch Diver:Weart为XR和机器人遥操作专属设计的触觉反馈动捕手套

在虚拟现实&#xff08;VR&#xff09;和扩展现实&#xff08;XR&#xff09;领域&#xff0c;触觉反馈技术正逐渐成为提升沉浸感和交互体验的重要因素。Weart作为这一领域的创新者&#xff0c;凭借其TouchDIVER Pro和TouchDIVER G1触觉手套&#xff0c;为用户带来了高度逼真的…

[深度学习]图片分类任务

图片分类任务 文章目录 图片分类任务分类任务回归和分类如何做分类的输出 图片分类卷积神经网络保持特征图大小不变更大的卷积核和更多的卷积核层数特征图怎么变小卷积神经网络中特征图改变卷积到全连接分类任务的LOSS一个基本的分类神经网络 经典神经网络AlexNetVggNetResNet …

Nodejs 项目打包部署方式

方式一&#xff1a;PM2 一、准备工作 确保服务器上已安装 Node.js 环境建议使用 PM2 进行进程管理&#xff08;需要额外安装&#xff09; 二、部署步骤 1.首先在服务器上安装 PM2&#xff08;推荐&#xff09;&#xff1a; npm install -g pm22.将项目代码上传到服务器&…

C++类与对象的的第三个简单的实战练习-3.25笔记

哔哩哔哩C面向对象高级语言程序设计教程&#xff08;118集全&#xff09; 简单实战三 创建项目 打开VS&#xff0c;点击创建一个新项目 创建一个空项目 点击下一步 点击工程名称&#xff0c;选择添加 选择新建项 选择C类 取名 点击确定&#xff0c;这时候还需要一个main.cpp …

HarmonyOS-ArkUI Grip组件

我们在学习List的时候&#xff0c;已经捎带引入了Grid。讲解如下图所示&#xff1a; 也就是&#xff0c;如果一个表&#xff0c;长宽基本都是一致的&#xff0c;那么此时可以完全不用Grid也可以实现&#xff0c;并且&#xff0c;优先考虑的就是List。 如果List实现不了的情况下…

2025清华大学:DeepSeek教程全集(PDF+视频精讲,共10份).zip

一、资料列表 第一课&#xff1a;Deepseek基础入门 第二课&#xff1a;DeepSeek赋能职场 第三课&#xff1a;普通人如何抓住DeepSeek红利 第四课&#xff1a;让科研像聊天一样简单 第五课&#xff1a;DeepSeek与AI幻觉 第六课&#xff1a;基于DeepSeek的AI音乐词曲的创造法 第…

mac vim命令快捷键

目录 移动光标插入模式复制/粘贴删除搜索/替换退出 移动光标 快捷键说明0 / ^跳到行首&#xff0c;移动到光标所在行的"行首"$跳到行末&#xff0c;移动到光标所在行的"行尾"gg跳到文件第一行G移动到文章的最后[n]G跳到第n行w光标跳到下个字的开头e光标跳…

低代码配置式Web组态解析

低代码配置式Web组态技术通过可视化操作和预置组件库&#xff0c;大幅降低开发门槛&#xff0c;适用于工业控制、物联网监控、数据可视化等场景。以下是综合行业实践和产品特性的分析&#xff1a; ‌一、核心功能与优势‌ ‌可视化编辑与拖拽布局‌ 提供图形化编辑器&#xff0…

基于web的家政服务网站

内容摘要 由于互联网的使用&#xff0c;人们在管理、应用、服务等领域使用数据更加简洁、方便&#xff0c;大大提高了工作效率。互联网正逐渐融入我们的生活&#xff0c;影响和改变我们的生活。 家政服务管理系统是典型的信息管理系统&#xff08;MIS&#xff09;。其开发主要…

聚水潭数据集成到MySQL的最佳实践分享

聚水潭数据集成到MySQL的技术案例分享 在本次技术案例中&#xff0c;我们将探讨如何通过轻易云数据集成平台&#xff0c;将聚水潭的数据高效、可靠地集成到MySQL数据库中。具体的集成方案为“聚水潭-商品信息查询-->BI初本-商品信息表_copy”。该方案旨在实现从聚水潭获取商…

线性代数核心概念与NumPy科学计算实战全解析

前言 学习方法&#xff1a; 思维导图&#xff0c;梳理 多记忆&#xff0c;函数名和功能&#xff0c;参数 学会应用&#xff0c;不要钻牛角尖 一、浅解线性代数 1.1标量 标量是一个只有大小没有方向的量。在数学上&#xff0c;标量通常表示为一个普通的数字&#xff0c;如‌质量…

C#自定义曲线便器功能实现(简化版)

目录 一、曲线编辑器实现功能 二、实现方法说明 三、关键代码说明 1、绘制背景板和曲线 2、绘制坐标系面板 3、绘制曲线 四、工程下载连接 一、曲线编辑器实现功能 添加或者删除控制点&#xff0c;通过移动控制点来修改曲线形状 二、实现方法说明 1、坐标系系统&#x…

解锁U盘属性0字节困境,重获数据生机

在数字化浪潮中&#xff0c;U盘宛如一位忠诚的“数据信使”&#xff0c;频繁穿梭于各种设备之间&#xff0c;为我们存储和传输着重要信息。然而&#xff0c;当U盘突然显示属性为0字节时&#xff0c;就如同这位信使突然“失声”&#xff0c;让我们陷入了数据丢失的恐慌之中。U盘…

⭐算法OJ⭐二叉树的直径【树】(C++实现)Binary Tree Paths

543. Binary Tree Paths&#xff08;二叉树的直径&#xff09; Given the root of a binary tree, return the length of the diameter of the tree. The diameter of a binary tree is the length of the longest path between any two nodes in a tree. This path may or m…

字典树与01trie

字典树简介 当我们通过字典查一个字或单词的时候&#xff0c;我们会通过前缀或关键字的来快速定位一个字的位置&#xff0c;进行快速查找。 字典树就是类似字典中索引表的一种数据结构&#xff0c;能够帮助我们快速定位一个字符串的位置。 字典树是一种存储字符串的数据结构…

vue - [Vue warn]: Duplicate keys detected: ‘0‘. This may cause an update error.

问题描述&#xff1a; vue项目中&#xff0c;对表单数组赋值时&#xff0c;控制台抛出警告&#xff1a; 问题代码&#xff1a; 问题分析&#xff1a; 1、Vue 要求每个虚拟 DOM 节点必须有唯一的 key。该警告信息通常出现在使用v-for循环的场景中&#xff0c;多个同级节点使用…