STM32 | 有源蜂鸣器响,无源蜂鸣器播音乐

目录

 Overview

有源蜂鸣器

无源蜂鸣器

有源蜂鸣器控制

GPIO配置

控制程序

无源蜂鸣器控制

反转GPIO控制

GPIO配置

控制接口

PWM控制

GPIO配置

控制函数

改变频率播音乐

原理

1. 频率决定音调

2. 占空比决定音量

GPIO初始化

结构体定义和音符频率表

 播放接口

播放生日快乐歌


 Overview

有源蜂鸣器

【结构与工作原理】

内部集成了振荡电路,只需提供直流电源(通常为 3-5V)即可发声,频率固定(常见为 2-4kHz)。

【驱动电路】

驱动简单,直接通过 GPIO 控制通断即可。需注意添加限流电阻(约 100Ω)保护 IO 口。

无源蜂鸣器

【结构与工作原理】

内部不含振荡电路,需要外部提供 PWM(脉冲宽度调制)信号驱动,通过调整频率和占空比可发出不同音调

【驱动电路】

需要 PWM 信号驱动,需配置 STM32 的定时器产生特定频率的方波。例如,若需发出 4kHz 的声音,则 PWM 频率应设为 4kHz。

有源蜂鸣器控制

GPIO配置

我的这个有源蜂鸣器模块带三个引脚,分别是VCC,I/O和GND,I/O口输入高电平时,蜂鸣器响。

(也有一些有源蜂鸣器只有两个引脚,当电压差满足驱动就会响)

  • 连接I/O引脚的GPIO引脚,配置为简单的输出即可。
// 外部有源蜂鸣器
void ExtActiveBuzzerInit()
{GPIO_InitTypeDef  GPIO_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE);	 //使能GPIOE端口时钟GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;				 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		 //推挽输出GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;	 //速度为50MHzGPIO_Init(GPIOE, &GPIO_InitStructure);	 //根据参数初始化GPIO_ResetBits(GPIOE, GPIO_Pin_2);//输出0,关闭蜂鸣器输出
}

控制程序

  • 一秒响,一秒不响
void task1_task(void *pvParameters)
{ExtActiveBuzzerInit();while(1){SetExtActiveBuzzer(1);printf("SetExtActiveBuzzer(1)\r\n");delay_ms(1000);SetExtActiveBuzzer(0);printf("SetExtActiveBuzzer(0)\r\n");delay_ms(1000);}
}

无源蜂鸣器控制

        无源蜂鸣器内部不含振荡电路,需要外部提供 PWM(脉冲宽度调制)信号驱动,通过调整频率和占空比可发出不同音调。

        不使用 PWM 的情况下,也可以通过 GPIO 软件翻转模拟 PWM 信号驱动无源蜂鸣器

反转GPIO控制

因为想观察不同的频率,所以我配置了两个GPIO,以不同频率做电平翻转

GPIO配置

void ExtPassiveBuzzerInit()
{GPIO_InitTypeDef  GPIO_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE);	    //使能GPIOE端口时钟GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;	                //BEEP 端口配置GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		    //推挽输出GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;	        //速度为50MHzGPIO_Init(GPIOE, &GPIO_InitStructure);	                    //根据参数初始化GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;GPIO_Init(GPIOE, &GPIO_InitStructure);}

控制接口

一个基础的循环周期为100us

  • 对于PE1,每100us后,电平翻转一次,所以方波周期是200us,频率就是5KHz
  • 对于PE3,每1000us(1ms)后,电平翻转一次,所以方波周期是2ms,频率就是500Hz

频率决定音调的高低,而更高的频率通常会让人感觉 “更刺耳”

void task1_task(void *pvParameters)
{int i = 0;int bE1Set = 0;int bE3Set = 0;ExtPassiveBuzzerInit();while (1){i++;if (i >= 10000) {printf("i = %d \r\n",i);i = 0;}if ( i % 2 == 0){if (bE1Set == 1){GPIO_ResetBits(GPIOE, GPIO_Pin_1);bE1Set = 0;}else{GPIO_SetBits(GPIOE, GPIO_Pin_1);bE1Set = 1;}}if ( i % 20 == 0){if (bE3Set == 1){GPIO_ResetBits(GPIOE, GPIO_Pin_3);bE3Set = 0;}else{GPIO_SetBits(GPIOE, GPIO_Pin_3);bE3Set = 1;}}// 半个周期100usdelay_us(100);}}

PWM控制

使用PA6,复用TIM3的通道1

GPIO配置

void ExtPassiveBuzzerPWMInit()
{GPIO_InitTypeDef GPIO_InitStructure;TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;TIM_OCInitTypeDef  TIM_OCInitStructure;// 使用PA6,做TIM3_CH1RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//设置该引脚为复用输出功能,输出TIM3 CH1的PWM脉冲波形	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; 			//TIM_CH1GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  	//复用推挽输出GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);				//初始化GPIO//初始化TIM3TIM_TimeBaseStructure.TIM_Period = 35999; 			//设置在下一个更新事件装入活动的自动重装载寄存器周期的值TIM_TimeBaseStructure.TIM_Prescaler = 0; 			//设置用来作为TIMx时钟频率除数的预分频值 TIM_TimeBaseStructure.TIM_ClockDivision = 0; 		//设置时钟分割:TDTS = Tck_timTIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); 	//根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位//初始化TIM3 Channel1 PWM模式	 TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; 				//选择定时器模式:TIM脉冲宽度调制模式TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; 	//比较输出使能TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; 		//输出极性:TIM输出比较极性高TIM_OC1Init(TIM3, &TIM_OCInitStructure);  						//根据T指定的参数初始化外设TIM3TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable);  //使能TIM3在CCR1上的预装载寄存器TIM_Cmd(TIM3, ENABLE);  //使能TIM3}

控制函数

占空比会用于实现音量高低变化

void task1_task(void *pvParameters)
{ExtPassiveBuzzerPWMInit();while(1){printf("Beep --- High Volume\r\n");// 高音量 (占空比约75%)TIM_SetCompare1(TIM3, 27000);  // 36000 * 0.75 = 27000delay_ms(1000);printf("Beep --- Low Volume\r\n");// 低音量 (占空比约10%)TIM_SetCompare1(TIM3, 3600);delay_ms(1000);}
}

改变频率播音乐

原理

PWM(脉冲宽度调制)通过改变输出信号的频率占空比,可以驱动无源蜂鸣器播放音乐。

如何理解频率和占空比的作用:

1. 频率决定音调
  • 频率:指 PWM 信号每秒的周期数(单位:Hz)。

  • 音调:不同频率对应不同音符,例如:

    • Do (C4) = 262 Hz

    • Re (D4) = 294 Hz

    • Mi (E4) = 330 Hz

通过快速切换 PWM 频率,可以组合出音乐旋律。

2. 占空比决定音量
  • 占空比:指高电平时间占整个周期的比例(通常用百分比表示)。

  • 音量:对于无源蜂鸣器,50% 占空比通常能产生最大音量,因为此时信号对称,能充分驱动蜂鸣器振动。

GPIO初始化

和上面的函数一样,但是留出了控制频率的参数输入

void ExtPassiveBuzzerAdvancePWMInit(uint32_t frequency)
{GPIO_InitTypeDef GPIO_InitStructure;TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;TIM_OCInitTypeDef  TIM_OCInitStructure;// 计算自动重装载值和预分频值uint32_t timer_clock = 72000000;  // 72MHzuint16_t psc = 1;uint16_t arr;// 使用PA6,做TIM3_CH1RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//设置该引脚为复用输出功能,输出TIM3 CH1的PWM脉冲波形	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; 			//TIM_CH1GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  	//复用推挽输出GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);				//初始化GPIO//初始化TIM3// 计算自动重装载值,确保不超过16位arr = timer_clock / (frequency * psc);if (arr > 65535) {psc = timer_clock / (65535 * frequency) + 1;arr = timer_clock / (frequency * psc);}TIM_TimeBaseStructure.TIM_Period = arr; 			//设置在下一个更新事件装入活动的自动重装载寄存器周期的值TIM_TimeBaseStructure.TIM_Prescaler = psc-1; 			//设置用来作为TIMx时钟频率除数的预分频值 TIM_TimeBaseStructure.TIM_ClockDivision = 0; 		//设置时钟分割:TDTS = Tck_timTIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); 	//根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位//初始化TIM3 Channel1 PWM模式	 TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; 				//选择定时器模式:TIM脉冲宽度调制模式TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; 	//比较输出使能TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; 		//输出极性:TIM输出比较极性高TIM_OC1Init(TIM3, &TIM_OCInitStructure);  						//根据T指定的参数初始化外设TIM3TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable);  //使能TIM3在CCR1上的预装载寄存器TIM_Cmd(TIM3, ENABLE);  //使能TIM3// 设置初始占空比为50%TIM_SetCompare1(TIM3, arr / 2);}

结构体定义和音符频率表

// 音乐结构定义
typedef struct {const uint8_t* melody;     // 音符数组const uint8_t* duration;   // 节拍数组uint8_t length;            // 音符长度
} Music_t;// 音符频率表 (Hz)
const uint16_t notes[] = {0,    // 休止符262,  // C4 (Do)294,  // D4 (Re)330,  // E4 (Mi)349,  // F4 (Fa)392,  // G4 (Sol)440,  // A4 (La)494,  // B4 (Si)523   // C5 (Do高八度)
};

 播放接口

beat节拍,每一拍100ms

// 播放单个音符
void PlayNote(uint8_t note_index, uint8_t beat)
{uint16_t frequency;if (note_index > 8) return;  // 确保索引有效frequency = notes[note_index];if (frequency > 0) {// 初始化PWM频率ExtPassiveBuzzerAdvancePWMInit(frequency);} else {// 休止符: 关闭PWM输出TIM_SetCompare1(TIM3, 0);}// 播放指定节拍 (1拍 = 100ms)delay_ms(beat * 100);
}// 播放音乐
void PlayMusic(const Music_t* music)
{uint8_t i;for (i = 0; i < music->length; i++) {PlayNote(music->melody[i], music->duration[i]);}// 播放结束,关闭蜂鸣器TIM_SetCompare1(TIM3, 0);
}

播放生日快乐歌

音符(控制PWM频率)和节拍数(控制音符对于频率PWM持续时长)

void task1_task(void *pvParameters)
{// 定义任务局部的音乐结构体指针static Music_t birthday;// 示例音乐:生日快乐歌static const uint8_t birthday_melody[] = {5, 5, 6, 5, 1, 7, 5, 5, 6, 5, 2, 1, 5, 5, 5, 3, 1, 7, 6, 4, 4, 3, 1, 2, 1};static const uint8_t birthday_duration[] = {2, 2, 4, 4, 4, 8, 2, 2, 4, 4, 4, 8, 2, 2, 2, 4, 4, 4, 8, 2, 2, 4, 4, 4, 8};// 在任务启动时初始化结构体birthday.melody = birthday_melody;birthday.duration = birthday_duration;birthday.length = sizeof(birthday_melody);while(1){// 循环播放生日快乐歌PlayMusic(&birthday);delay_ms(1000);  // 播放间隔}
}

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

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

相关文章

第十四章 gin基础

文章目录Gin快速搭建一个web服务Gin数据交互JSON串内容规范Gin使用结构体返回数据给前端Gin配置POST类型的路由Gin获取GET请求参数Gin获取POST请求参数-form-data类型Gin获取POST请求参数-JSON类型Gin获取参数绑定至结构体Gin快速搭建一个web服务 下载包 \\新建一个文件&…

Baumer工业相机堡盟工业相机如何通过YoloV8的深度学习模型实现PCB的缺陷检测(C#代码,UI界面版)

Baumer工业相机堡盟工业相机如何通过YoloV8的深度学习模型实现PCB的缺陷检测&#xff08;C#代码&#xff0c;UI界面版&#xff09;工业相机使用YoloV8模型实现PCB的缺陷检测工业相机实现YoloV8模型实现PCB的缺陷检测的技术背景在相机SDK中获取图像转换图像的代码分析工业相机图…

【Vivado那些事儿】AMD-XILINX 7系列比特流加密

前提&#xff1a;加密有风险&#xff0c;操作需谨慎前言在许多项目中&#xff0c;经过漫长的等待&#xff0c;我们的 FPGA 设计终于可以投入现场部署了。前期的资金的投入及知识产权的保护&#xff0c;我们需要对现场部署的 FPGA 进行比特流保护以防止逆向工程和未经授权的重复…

RK3588 安卓adb操作

adb&#xff08;Android Debug Bridge&#xff09;是一个用于与安卓设备进行通信和控制的工具。adb可以通过USB或无线网络连接安卓设备&#xff0c;执行各种命令&#xff0c;如安装和卸载应用&#xff0c;传输文件&#xff0c;查看日志&#xff0c;运行shell命令等。adb是安卓开…

【华为机试】70. 爬楼梯

文章目录70. 爬楼梯描述示例 1示例 2提示解题思路核心分析问题建模算法实现方法1&#xff1a;动态规划&#xff08;标准解法&#xff09;方法2&#xff1a;空间优化动态规划&#xff08;最优解&#xff09;方法3&#xff1a;递归 记忆化方法4&#xff1a;数学公式&#xff08;…

山东大学软件学院面向对象期末复习

面向对象 文章目录面向对象04 类封装接口 抽象类05 消息&#xff0c;实例化&#xff0c;静态变量方法消息动/静态类型语言对象创建类及实例具有下面特征对象数组的创建静态数据成员构造函数06_0 继承继承是向下传递的JAVA为什么不支持多重继承继承的形式特殊化继承替换原则规范…

让 Windows 用上 macOS 的系统下载与保姆级使用教程

模拟苹果桌面软件下载&#xff1a;https://xpan.com.cn/s/8NFAGT 还记得 Windows 11刚发布时&#xff0c;很多人就说“果里果气"的&#xff0c;但界面确实做的漂亮。 不知道现在有多少小伙伴正用着macOS&#xff0c;不过我敢确定&#xff0c;喜欢macOS的人绝对不少&#…

嵌入式硬件篇---继电器

继电器是一种通过小电流控制大电流的电磁开关&#xff0c;广泛应用于自动化控制、电力系统和电子设备中。以下从工作原理、应用场景和电路特点三个方面详细介绍&#xff1a;一、工作原理继电器本质是电磁控制的机械式开关&#xff0c;核心部件包括&#xff1a;线圈&#xff08;…

鸿蒙网络编程系列58-仓颉版TLS数字证书查看及验签示例

1. TLS数字证书验签简介 数字证书的签名验证是网络编程中一个重要的功能&#xff0c;它保证了数字证书是由可信任的签发方签署的&#xff0c;在此基础上&#xff0c;我们才可以信任该证书&#xff0c;进而信任基于该证书建立的安全通道&#xff0c;所以说&#xff0c;数字证书…

【React Native】安装配置 Expo Router

过去开发React Native&#xff0c;所使用的路由都是React Navigation。但是这个东西使用起来非常困难&#xff0c;配置无比繁琐。Expo&#xff0c;为了简化操作&#xff0c;就基于React Navigation开发了Expo Router。 Expo Router用起来就要简单的多了&#xff0c;配置也相对…

美国VPS服务器Linux内核参数调优的实践与验证

美国vps服务器Linux内核参数调优的实践与验证在云计算和虚拟化技术日益普及的今天&#xff0c;美国VPS服务器因其稳定的网络环境和优越的性价比&#xff0c;成为众多企业和开发者的首选。Linux内核参数的默认配置往往无法充分发挥VPS的性能潜力。本文将深入探讨美国VPS服务器上…

在Vscode中使用Kimi K2模型:实践指南,三分钟生成个小游戏

Kimi K2是一款基于多专家&#xff08;MoE&#xff09;架构的强大代码与代理能力基础模型。本文将通过在VS Code及其扩展Cline和RooCode中的实际应用&#xff0c;详细说明如何使用Kimi K2-0711-preview模型。不得不说kimi这次的K2模型就是强大&#xff0c;在vscode中配置使用体验…

基于SpringBoot+Uniapp球场预约小程序(腾讯地图API、Echarts图形化分析、二维码识别)

“ &#x1f388;系统亮点&#xff1a;腾讯地图API、Echarts图形化分析、二维码识别”01系统开发工具与环境搭建前后端分离架构 项目架构&#xff1a;B/S架构 运行环境&#xff1a;win10/win11、jdk17前端&#xff1a; 技术&#xff1a;框架Vue.js&#xff1b;UI库&#xff1a;…

windows + phpstorm 2024 + phpstudy 8 + php7.3 + thinkphp6 配置xdebug调试

windows phpstorm 2024 phpstudy 8 php7.3 thinkphp6 配置xdebug调试 下载配置phpstudyPhp.ini配置phpstorm配置xdebug运行一会就停了配置虚拟机 0localhost_90.conf 配置php.ini配置下载 在下面地址下载合适的xdebug 放到对应的php https://xdebug.org/wizard 配置phpst…

python的pywebview库结合Flask和waitress开发桌面应用程序简介

pywebview的用途与特点 用途 pywebview是一个轻量级Python库&#xff0c;用于创建桌面应用程序&#xff08;GUI&#xff09;。它通过嵌入Web浏览器组件&#xff08;如Windows的Edge/IE、macOS的WebKit、Linux的GTK WebKit&#xff09;&#xff0c;允许开发者使用HTML/CSS/Java…

C#通过HslCommunication连接西门子PLC1200,并防止数据跳动的通用方法

textEdit30.Text ReadValue<int>(() > plc.ReadInt32("DB57.DBD16"), ref _last_num).ToString();// 通用读取方法&#xff08;支持所有值类型&#xff09;private T ReadValue<T>(Func<OperateResult<T>> readFunc, ref T lastValue) w…

Linux切换到Jenkins用户解决Jenkins Host key verification failed

以root或sudo user身份, 切换到jenkins用户 su -s /bin/bash jenkins前往jenkins的home目录 cd /var/lib/jenkins/查看.ssh下是否已经有known_hosts, 有的话, 是什么内容, 正常情况下, 这时候是没有对应IP记录的 cd .ssh/ more known_hosts访问一下对应IP, 记录公钥 ssh 192.16…

7.17 Java基础 | 集合框架(下)

接上文&#xff1a; 7.16 Java基础 | 集合框架&#xff08;上&#xff09;-CSDN博客 【1】Map集合 Map 集合是一种能存储键值对的数据结构。它的主要功能是依据键&#xff08;Key&#xff09;来快速查找对应的值&#xff08;Value&#xff09; 1、声明 Map<Integer,Integer…

【LeetCode刷题指南】--反转链表,链表的中间结点,合并两个有序链表

&#x1f525;个人主页&#xff1a;草莓熊Lotso &#x1f3ac;作者简介&#xff1a;C研发方向学习者 &#x1f4d6;个人专栏&#xff1a; 《C语言》 《数据结构与算法》《C语言刷题集》《Leetcode刷题指南》 ⭐️人生格言&#xff1a;生活是默默的坚持&#xff0c;毅力是永久的…

ubuntu上面的wps2019格式很乱在复制粘贴的时候

问题&#xff1a;在复制内容到 Ubuntu 上的 WPS 2019 出现如下问题&#xff1a;列表符号、换行和缩进错乱&#xff0c;表现为每行前的点符号&#xff08;•&#xff09;变成不规则对齐或空格间距不统一。原因分析✅ 主要原因是&#xff1a;WPS 2019 在 Ubuntu 上的兼容性较差&a…