教你如何使用STM32控制无源蜂鸣器发声播放音乐

发布者:Aq123456258最新更新时间:2022-04-21 来源: eefocus关键字:STM32  无源蜂鸣器  播放音乐 手机看文章 扫描二维码
随时随地手机看文章

一、无源蜂鸣器有源蜂鸣器

有源蜂鸣器内含振荡源,只要一通电就发声,但发生频率固定,音色单一;无源蜂鸣器内部不含振荡源,内部结构相当于电磁场扬声器,可以通过给他输出一定频率的信号才能发声。


人耳能听到的频率范围在20Hz--20kHz之间,通过STM32的GPIO引脚快速切换高低电平输出就能实现无源蜂鸣器的发声,切换的频率不同,发出的音调就不一样。


二、音乐播放的实现

一段音乐就是不同频率的声音按一定的时间节拍转换发出。所以音乐包含音调和节拍信息。


C调各音符频率如下:

音符

频率 Hz

音符

频率 Hz

低1 Do

262

中1 Do

523

低2 Re

294

中2 Re

587

低3 Mi

330

中3 Mi

659

低4 Fa

349

中4 Fa

698

低5 So

392

中5 So

784

低6 La

440

中6 La

880

低7 Si

523

中7 Si

988

如果要实现歌曲“红尘情歌”,要准备相应的数据。

歌谱如下:

程序中首先准备音频数据表:

//         低Si Do Re  Mi  Fa So  La  Si ¸高Do¸高Re¸高Mi¸高Fa¸高So 无

uc16 tone[] ={247,262,294,330,349,392,440,294,523,  587,  659,  698,  784,  1000};

u8 music[]={  5,5,6,8,7,6,5,6,13,13,……};//音调

u8 time[] = {  2,4,2,2,2,2,2,8,4, 4, ……}; //节拍时间

依次从音调数组中取music[i],然后根据music[i]的值在tone数组中得到该音的发声频率(tone[music[i]]),调用sound函数控制蜂鸣器发声,声音的发声时间有time数组控制。

三、项目创建与配置

1、创建项目文件夹(设为pMusic)

2、通过Keil5创建新项目,保存在所创建的文件夹中(设项目名为pMusic),选择MCU芯片为"STM32F103ZE"(本程序使用的硬件为:STM32-PZ6806L开发板)

3、在pMusic项目文件夹中新建"CMSIS"、"Device"、"Public"、"Startup"、"User"和"Lib"文件夹。

①  在"CMSIS"文件夹中复制"core_cm3.h"和"core_cm3.c"文件;

②  在" Device "文件夹中复制"stm32f10x.h"、"system_stm32f10x.h"和"system_stm32f10x.c"文件;

③  在" Startup "文件夹中复制"startup_stm32f10x_hd.s"文件;

④在"Lib"文件夹中新建"inc"和"src"两个子文件夹,在"inc"文件夹中复制"misc.h"、"stm32f10x_gpio.h"和"stm32f10x_rcc.h"文件;在"src"文件夹中复制"misc.c"、"stm32f10x_gpio.c"和"stm32f10x_rcc.c"文件;

4、为项目添加"CMSIS"、"Device"、"Public"、"Startup"、"User"和"Lib"组,并将上述C程序文件和"startup_stm32f10x_hd.s"启动文件加入到相应组中。展开项目树如下:

5、打开“项目配置”对话框,在"Output"选项卡中选择"Create HEX File",在"C/C++"选项卡中的"Include Paths"中添加如下包含路径:".CMSIS;", ".Device;", ".Libinc;",".Public;"。

(以上步骤可以参看:使用STM32固件库操作控制LED灯(CMSIS)   使用STM32固件库函数操作控制LED灯

6、在"stm32f10x.h"中添加函数参数检查宏

(参看:使用STM32固件库函数操作控制LED灯)

#ifdef  USE_FULL_ASSERT

/**

  * @brief  这个assert_param宏用于函数参数检查

  * @param  expr:如果expr是 false,就调用 assert_failed函数报告源文件名和

  *         失败的行号,如果expr是 true ,就返回一个空值

  * @retval None

  */

  #define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__))

/* Exported functions ------------------------------------------------------- */

  void assert_failed(uint8_t* file, uint32_t line);

#else

  #define assert_param(expr) ((void)0)

#endif /* USE_FULL_ASSERT */

7、新建一个文件(system.h),保存到"Public"文件夹中,内容为:

#ifndef __SYSTEM__H

#define __SYSTEM__H

#include "stm32f10x.h"

//定义位带地址宏

#define BITBAND(addr,bitnum) ((addr&0xF0000000) + 0x02000000 + ((addr&0x000FFFFF)<<5) + (bitnum<<2))

#define MEM_ADDR(addr) *((volatile unsigned long *)(addr))

#define BIT_ADDR(addr,bitnum) MEM_ADDR(BITBAND(addr,bitnum))

//IO口地址映射

//数据输出寄存器地址

#define GPIOA_ODR_Addr          (GPIOA_BASE + 12)

#define GPIOB_ODR_Addr (GPIOB_BASE + 12)

#define GPIOC_ODR_Addr (GPIOC_BASE + 12)

#define GPIOD_ODR_Addr          (GPIOD_BASE + 12)

#define GPIOE_ODR_Addr (GPIOE_BASE + 12)

#define GPIOF_ODR_Addr (GPIOF_BASE + 12)

#define GPIOG_ODR_Addr          (GPIOG_BASE + 12)

//数据输入寄存器地址

#define GPIOA_IDR_Addr  (GPIOA_BASE + 12)

#define GPIOB_IDR_Addr  (GPIOB_BASE + 12)

#define GPIOC_IDR_Addr  (GPIOC_BASE + 12)

#define GPIOD_IDR_Addr  (GPIOD_BASE + 12)

#define GPIOE_IDR_Addr   (GPIOE_BASE + 12)

#define GPIOF_IDR_Addr   (GPIOF_BASE + 12)

#define GPIOG_IDR_Addr  (GPIOG_BASE + 12)

#endif

该文件定义了GPIO端口位带操作的宏。

(位带操作请参看:通过位带地址操作GPIO在数码管显示数字)

8、新建文件"SysTick.h",保存到"Public"文件夹中,内容为:

#ifndef __SysTick__H

#define __SysTick__H

#include "stm32f10x.h"

void SysTick_Init(u8 SYSCLK);

void delay_us(u32 nus);

void delay_ms(u16 nms);

#endif

新建文件"SysTick.c",保存到"Public"文件夹中,内容为:

#include "SysTick.h"

#include "misc.h"

u8 fac_us = 0;

u16 fac_ms = 0;

void SysTick_Init(u8 SYSCLK)

{undefined

         SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);

         fac_us = SYSCLK / 8;

         fac_ms = (u16)fac_us*1000;

}

 

void delay_us(u32 nus)

{undefined

         u32 temp;

         SysTick->LOAD = nus * fac_us;

         SysTick->VAL = 0;

         SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;

         do{undefined

                   temp = SysTick->CTRL;

         }while((temp&0x01)&&(!(temp&(1<<16))));

         SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;

         SysTick->VAL = 0;

}

void delay_ms(u16 nms)

{undefined

         u32 temp;

         SysTick->LOAD = nms * fac_ms;

         SysTick->VAL = 0;

         SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;

         do{undefined

                   temp = SysTick->CTRL;

         }while((temp&0x01)&&(!(temp&(1<<16))));

         SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;

         SysTick->VAL = 0;

}

这两个文件实现了通过SysTick精准延时的函数,提供给后续的音频频率产生程序使用。

(关于SysTick,请参看:在STM32项目中使用SysTick实现延时)

将"SysTick.c"文件添加到项目的"Public"组中。

9、实现发声

①开发板无源蜂鸣器的电路连接如下:

从电路连接可以看出通过MCU的PB5(GPIOB_5)控制蜂鸣器的发声。

②在项目文件夹的"User"文件夹下新建"Beep"文件夹,在项目中新建"beep.h"文件,保存在"User/Beep"文件夹中,文件内容为:

#ifndef __BEEP__H

#define __BEEP__H

#include "system.h"

#include "stm32f10x_gpio.h"

#include "stm32f10x_rcc.h"

//定义GPIOB的位地址变量宏

#define PBout(n) BIT_ADDR(GPIOB_ODR_Addr,n)

#define PBeep PBout(5)

#define BEEP_PORT   GPIOB

#define BEEP_PIN      GPIO_Pin_5

#define BEEP_PORT_RCC RCC_APB2Periph_GPIOB

void BEEP_Init(void);

void Sound(u16 frq);

void play(void);

#endif

③在项目中新建"beep.c"文件,保存在"User/Beep"文件夹中,文件内容为:

#include "beep.h"

#include "systick.h"

void BEEP_Init(void)

{undefined

         GPIO_InitTypeDef GPIO_mode;

         RCC_APB2PeriphClockCmd( BEEP_PORT_RCC, ENABLE );         //使能GPIOB时钟

         GPIO_mode.GPIO_Pin = BEEP_PIN;

         GPIO_mode.GPIO_Speed = GPIO_Speed_50MHz;

         GPIO_mode.GPIO_Mode = GPIO_Mode_Out_PP;

         GPIO_Init(BEEP_PORT, &GPIO_mode);      //设置GPIOB_5为推挽输出,50MHz速度

}

 

void Sound(u16 frq)

{undefined

         u32 n;

         if(frq != 1000) //如果频率不为1000则按频率输出,否则只延时

         {undefined

                   n = 500000/((u32)frq);

                   PBeep = 0;

                   delay_us(n);

                   PBeep = 1;

                   delay_us(n);

         }else

                   delay_us(1000);

}

 

void play(void)

{undefined

         //             低7  1   2   3   4   5   6   7  高1 高2 高3 高4 高5 不发音

         uc16 tone[] = {247,262,294,330,349,392,440,294,523,587,659,698,784,1000};//音频数据表

         //红尘情歌

         u8 music[]={       5,5,6,8,7,6,5,6,13,13,//音调

                                                                           5,5,6,8,7,6,5,3,13,13,

                                                                   2,2,3,5,3,5,6,3,2,1,

[1] [2] [3]
关键字:STM32  无源蜂鸣器  播放音乐 引用地址:教你如何使用STM32控制无源蜂鸣器发声播放音乐

上一篇:4.3、使用寄存器版本点亮LED灯(内附代码)
下一篇:10、STM32的串口(UART)及串口通信原理(内附代码)

推荐阅读最新更新时间:2024-11-13 05:08

stm32所有I/O和控制引脚的电流能力
疑问 :所有I/O和控制引脚上的总注入电流(4) ±25 照这句话 理解如果点个 10mA的光耦 那只能点 2只半了??那这个电流也太小了点吧? 答案:在注2中给出了注入电流的定义:当VIN VDD时,有一个正向注入电流;当VIN VSS时,有一个反向注入电流。 从这个定义可以看出,注入电流与正常的输出电流和正常的入地的吸收(Sink)电流是不同的。注入电流是当VIN VDD时或当VIN VSS时才会出现,而正常的时候是不会有注入电流的。 正常的输出电流和正常的入地的吸收(Sink)电流的极限值分别是:I VDD 和I VSS ,它们分别有150mA。 请注意,这个表里的参数是极限值,即如果任何一个参数超过了这里列
[单片机]
<font color='red'>stm32</font>所有I/O和控制引脚的电流能力
关于STM32中的assert_param()
在STM32的固件库和提供的例程中,到处都可以见到assert_param()的使用。如果打开任何一个例程中的stm32f10x_conf.h文件,就可以看到实际上assert_param是一个宏定义; 在固件库中,它的作用就是检测传递给函数的参数是否是有效的参数。 所谓有效的参数是指满足规定范围的参数,比如某个参数的取值范围只能是小于3的正整数,如果给出的参数大于3,则这个assert_param()可以在运行的程序调用到这个函数时报告错误,使程序员可以及时发现错误,而不必等到程序运行结果的错误而大费周折。 这是一种常见的软件技术,可以在调试阶段帮助程序员快速地排除那些明显的错误。 它确实在程序的运行上牺牲了效率(但
[单片机]
stm32 中怎样把变量定义到flash中
目的:将变量定义到flash中 其实写这个是相当于一个记录而已,突然在做字模显示问题,想到如果将字模数据放到内存中的话,难免多了很容易出问题,不如就放在flash中,这样就可以不去改变他 int a;a在内存中 const int a;a在flash中,这个可以通过打印地址来看
[单片机]
使用Ulink2的JTAG与SWD 调试stm32 区别
一、硬件连接 我调试stm32F407使用的ULINK2,Ulink2内部实物图如下。 1.1 JTAG interface 标准20pin JTAG引脚中,JTAG调试只使用8pin,定义如下: 1)NTRST ---------------Test ReSeT/ pin — Use 100K Ohm pull-up resistor to VCC. 必须有该引脚 2)TDI -----------------Test Data In pin — Use 100K Ohm pull-up resistor to VCC.数据输入 必须有该引脚 3)TMS/SW
[单片机]
使用Ulink2的JTAG与SWD 调试<font color='red'>stm32</font> 区别
Cartesiam发布优化STM32开发板的新版NanoEdge™ AI Studio
嵌入式系统人工智能(AI)软件开发公司Cartesiam发布了针对STM32开发板优化的新版NanoEdge™AI Studio软件工具。STM32是横跨多重电子应用领域的全球领先的半导体供应商意法半导体(STMicroelectronics,简称ST;纽约证券交易所代码:STM)开发的市场领先的微控制器。Cartesiam的NanoEdge AI Studio开发环境消除了传统的AI开发障碍,面向缺乏机器学习专业资源的企业。新版本让任何嵌入式开发者都可以用STM32微控制器快速开发强大的AI解决方案。在其诸多优化功能中,它还可直接通过STM32的串行/ USB端口和Cartesiam增强版自动数据符合性检查和质量验证工具在Nan
[单片机]
STM32按键的短按/长按/双击
上一篇文章已经写好了定时器,并且实现了按键长按。 现在狭隘的用一下: https://mp.weixin.qq.com/s?__biz=MzUyOTM0NDkyMA==&mid=2247484014&idx=1&sn=b07bde8a1d5b15467b2c80dfd7ae3547&chksm=fa633299cd14bb8f8e9334282059930bafabf44dfcf502b0a39b7f30326268f8574acc0b0ccf&mpshare=1&scene=23&srcid=0606fxjOEkyOf9zu21GHV78G#rd //⑥外部中断 2 服务程序 按键效果!!! void EXTI2_I
[单片机]
基于ZigBee和STM32的智能家居控制系统的设计与实现(五)--终结
##基于ZigBee和STM32的智能家居控制系统的设计与实现(五)–终结篇 ###说明 首先祝贺自己顺利的完成了毕业答辩工作,想起整个过程还是挺让自己感动的。最后还被评为优秀毕业设计,虽然并没有什么luan用,但是,马上毕业了,还是挺让人怀念的。整个资料从第一篇博客说起就说会全部开源的,期间承蒙各位朋友的支持,给与资助,在此感谢了。虽然资料中私人信息删除了一些,但是不免有疏漏,所以有关个人信息还挺各位删除掉,小弟在此谢谢了! ###总结 下面简单介绍下系统使用到的一些资料和系统实现的功能。 开发系统:Windows10 64位 Ubuntu 14.04 32 位 软件版本:Qt 4.8.6 IAR .0 Altium Des
[单片机]
基于ZigBee和<font color='red'>STM32</font>的智能家居控制系统的设计与实现(五)--终结
STM32之八定时器中断
STM32的通用定时器是一个通过可编程预分频器(PSC)驱动的16 位自动装载计数器(CNT)构成。STM32的通用定时器可以被用于:测量输入信号的脉冲长度(输入捕获)或者产生输出波形(输出比较和PWM)等。 使用定时器预分频器和RCC时钟控制器预分频器,脉冲长度和波形周期可以在几个微秒到几个毫秒间调整。STM32的每个通用定时器都是完全独立的,没有互相共享的任何资源。 STM3的通用TIMx (TIM2、TIM3、TIM4和TIM5)定时器功能包括: 1)16位向上、向下、向上/向下自动装载计数器(TIMx_CNT)。 2)16 位可编程(可以实时修改)预分频器(TIMx_PSC),计数器时钟频率的分频系数为1~65535之间
[单片机]
<font color='red'>STM32</font>之八定时器中断

推荐帖子

LPC1114 收到,先分享ARM学习资料
我很高兴申请到了LPC1114,现在学习当中,先将些资料与大家共享!LPC1114收到,先分享ARM学习资料谢谢共享,顺便问一下你用LPC1114做什么项目.学习了,以后多多支持,多多分享好东东~~~学习了,以后多多支持,多多分享好东东~~~下了,多谢楼主分享!谢谢分享谢谢谢谢分享谢谢分享不错不错,收藏了~~谢谢分享谢谢楼主分享啊····谢谢分享~我也申到了谢谢分享
mayi_2008 NXP MCU
新手共同进步——获得Design tool,让Cube Suite+支持R7F0C80212
之前有发表了一篇安装文档,现在想想,有一点点的问题,在此特意声明出来。之前我装的时候把这个更新给关了,后续造成了很多麻烦,所以,希望大家默默等待它更新,就能很好支持R7F0C80212了。当然你没有更新也不要紧,也可以点击Project-updata找到之前的更新界面进行更新,看到图中的Application了吧,经过安装以后,它会出来的。当然,如果updata不顶用的话,比如刷新不出来,那也不要紧的,还有第三套方案,就是到瑞萨官网去下载,这个方法是我采用的方法,用版本2.01也
不足论 瑞萨电子MCU
【PSoC4心得】测量电阻,也就两招!
测量电阻,也就两招?我自己都有点不相信。是这么个事:无意中找到一个关于DAC的例程(IDAC8_PSoC4_Example01),这个DAC是电流输出——IDAC,(这个电流不就可以加在外接电阻上了?)再来个ADC,可以直接测试外接电阻上的电压。结果在LCD显示。要点:给待测电阻——(1)加电流,(2)测电压;剩下的欧姆定律你懂得。“测电压”的ADC用内部的1.024V,精度有保障,目前是最佳选择。“加电流”的IDAC,8位输出电流,固定120uA。(如有需要,可以设法
sacq 单片机
医疗器械对地漏电流、外壳漏电流、患者漏电流
医疗器械对地漏电流、外壳漏电流、患者漏电流正常条件:S1=1,S5=N,S7=1,S12=0,这里S1,S5,S7,S12是什么意思呢?医疗器械对地漏电流、外壳漏电流、患者漏电流搞哪一行的产品,应该把那个行当的国家标准或行业标准研究研究吧EC60601-1漏电流测试2.0对地漏电流的测量电路S1=1是正常模式,S1=0属于单一故障,同时需要将S5(极性LN切换)S10:功能地,S12:将患者连接与测量供电电路的接
QWE4562009 测试/测量
WinCE 如何实现鼠标拖拽移动无标题窗口
WinCE如何实现鼠标拖拽移动无标题窗口在Windows下在子窗口的LbuttonDown处理函数下SendMessage(this-m_hWnd,WM_SYSCOMMAND,SC_MOVE|HTCAPTION,0)就可以了,可在CE下不行,请问用类似的方法应该怎么做该发什么消息啊谢谢WinCE如何实现鼠标拖拽移动无标题窗口谢谢大家了LbuttonDown+MouseMove不行么我想用类似这种方法来实现,因为这个比较简单。SendMessage(this-m_
stlong WindowsCE
求南芯电源管理芯片SC8905 或者SC08906 的芯片设置工具( I2Ctool )
求SC8905或者SC08906的芯片I2C设置工具,一台无人机电池管理芯片是SC8906电池饿死被锁,没找到任何的解锁软件,或者南芯电源管理芯片的设置软件及设置说明,这一点Ti做的比较好,提供了专门的芯片管理软件。大疆的绝大多数电池管理芯片都是Ti的能进行解锁或者换电芯DIY,如果哪位大侠有南芯的电池芯片设置工具,希望能分享一下,我邮箱是1205345948@qq.com求南芯电源管理芯片SC8906I设置工具及设置说明(I2Ctool)找找南芯的技术支持,管理员有
飞翔3000 国产芯片交流
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
随便看看

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved