精华内容
下载资源
问答
  • 使用STM32控制无源蜂鸣器发声播放音乐(STM32_07)
    万次阅读 多人点赞
    2018-05-10 11:10:12

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

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

    人耳能听到的频率范围在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;", ".\Lib\inc;",".\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)

    {

             SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);

             fac_us = SYSCLK / 8;

             fac_ms = (u16)fac_us*1000;

    }

     

    void delay_us(u32 nus)

    {

             u32 temp;

             SysTick->LOAD = nus * fac_us;

             SysTick->VAL = 0;

             SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;

             do{

                       temp = SysTick->CTRL;

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

             SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;

             SysTick->VAL = 0;

    }

    void delay_ms(u16 nms)

    {

             u32 temp;

             SysTick->LOAD = nms * fac_ms;

             SysTick->VAL = 0;

             SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;

             do{

                       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)

    {

             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)

    {

             u32 n;

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

             {

                       n = 500000/((u32)frq);

                       PBeep = 0;

                       delay_us(n);

                       PBeep = 1;

                       delay_us(n);

             }else

                       delay_us(1000);

    }

     

    void play(void)

    {

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

             uc16 tone[] = {247,262,294,330,349,392,440,494,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,

                                                                               6,6,5,6,5,3,6,5,13,13,

     

                                                                               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,

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

     

                                                                               13,8,9,10,10,9,8,10,9,8,6,

                                                                               13,6,8,9,9,8,6,9,8,6,5,

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

                                                                               6,10,9,9,8,6,5,6,8

             };     

             u8 time[] = {       2,4,2,2,2,2,2,8,4, 4, //时间

                                                                               2,4,2,2,2,2,2,8,4, 4,

                                                                               2,4,2,4,2,2,4,2,2,8,

                                                                               2,4,2,2,2,2,2,8,4 ,4,

            

                                                                               2,4,2,2,2,2,2,8,4, 4,

                                                                               2,4,2,2,2,2,2,8,4, 4,

                                                                               2,4,2,4,2,2,4,2,2,8,

                                                                               2,4,2,2,2,2,2,8,

            

                                                                               4, 2,2,2, 4, 2,2,2, 2,2,8,

                                                                               4, 2,2,2,4,2,2,2,2,2,8,

                                                                               4, 2,2,2,4,2,2,5,2,6,2,4,

                                                                               2,2 ,2,4,2,4,2,2,12

             };     

             u32 yanshi;

             u16 i,e;

             yanshi = 10;

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

                       for(e=0;e<((u16)time[i])*tone[music[i]]/yanshi;e++){

                                Sound((u32)tone[music[i]]);

                       }      

             }

    }

    程序中定义了端口使能和方式配置函数BEEP_Init,输出音频函数Sound和播放音乐函数play。

    ④ 将"beep.c"文件加入到项目的"User"组中;在"C/C++"选项卡中的"Include Paths"中添加包含路径:"\User\Beep;"。

    10、在项目中新建"main.c"文件,保存在"User "文件夹中,文件内容为:

    #include "beep.h"

    #include "SysTick.h"

    int main()

    {

             SysTick_Init(72);

             BEEP_Init();

             while(1)

             {

                       play();

             }

    }

    "main.c"文件中包含main函数反复调用play函数播放歌曲。

    11、编译、连接、下载程序。

    代码下载地址:下载源码 

    更多相关内容
  • STM32驱动蜂鸣器,实现播放歌曲功能,蜂鸣器数据接收端接GPIOC.5即可直接使用。
  • STM32驱动压电式蜂鸣器发出和弦音,电路图在我博客中查找,代码已完全验证拿过来可直接使用。蜂鸣器接单片机IO口比较特殊,请注意,需要一路硬件PWM口
  • 本实验通过代码控制开发板上的DS0和蜂鸣器,DS0闪烁,提示程序运行,而蜂鸣器则周期性的发出“嘀”的声音,间隔为0.3秒。
  • 本项目为RT-Thread学习项目,参考于RT-Thread官网Demo示例 硬件基于STM32F407ZGT6正点原子探索者开发板+无源蜂鸣器模块 RTOS软件基于RT-Thread 4.0.5版本 编译器为官方的提供的RT-Thread Studio 会使用到STM32CubeMX...

    本项目为RT-Thread学习项目,参考于RT-Thread官网Demo示例 硬件基于STM32F407ZGT6正点原子探索者开发板+无源蜂鸣器模块 RTOS软件基于RT-Thread 4.0.5版本 编译器为官方的提供的RT-Thread Studio 会使用到STM32CubeMX 配置产生PWM波 会使用MobaXterm串口终端软件查看串口终端数据

    官网Demo示例网址:RT-Thread 文档中心

    官网Demo示例用到的源文件Github地址:GitHub - Guozhanxin/RTT-BeepPlayer-pkg: 基于 RTT 的 BeepPlayer 的软件包

    如有侵权联系删除

    目录

    第一步 新建工程

    第二步 添加LED的驱动

    第三步 添加按键驱动

    第四步 STM32CubeMX配置输出PWM

    1、打开选择芯片

    2、配置定时器

    3、配置时钟

    4、配置工程并输出

    5、下载验证

    第五步 移植到RT-Thread工程并产生PWM波

    1、在RT-Thread工程工程里开启PWM的驱动

    2、移植STM32CubeMX生成的PWM文件

    3、 在drv_pwm.c文件下修改两处

    4、开启相关宏定义

    5、验证是否开启PWM成功

    第六步 添加音乐编码与解码文件

    第七步 播放器的实现

    第八步 给播放器添加按键控制


    第一步 新建工程

    打开文件->新建RT-Thread项目 ​先安装一下STM32F407的芯片资源包

    然后基于芯片选择创建项目,根据实际选择控制台串口和调试器 ​

    编译构建一下

    到borad.h下修改时钟源为HSE

    再编译下载,我这里是连接的jlink

    打开串口终端就可以看见每隔1秒再终端输出Hello RT-Thread!

    到此表示RT-Thread基于STM32F407的基础项目工程移植成功

    第二步 添加LED的驱动

    将官网Demo示例中led文件夹下的led.c和led.h两个文件复制到你自己的工程文件的applications里,构建一下文件就自动添加进来了

    将官网Demo示例中samples文件夹下的main_1.c内容复制替换自己的main.c里的内容

    并在main.c里添加#include "led.h"头文件

    删除原本led.h的LED驱动管脚的定义

    在led.c里添加新的LED管脚的驱动映射#define LED0_PIN GET_PIN(F, 9),并添加#include <drv_common.h>头文件

    构建下载就可以看到LED以500ms一次切换显示

    第三步 添加按键驱动

    将官网Demo示例中code/button文件夹下的button.c和button.h两个文件复制到你自己的工程文件的applications里

    将官网Demo示例中samples文件夹下的main_2.c内容复制替换自己的main.c里的内容

    并在main.c里添加#include "button.h"头文件

    修改KEY_PIN 的管脚映射,并在主函数里添#include <drv_common.h>头文件

    构建下载后按键可以在控制台串口看见回调函数再被调用

    第四步 STM32CubeMX配置输出PWM

    1、打开选择芯片

    打开STM32CubeMX,选择STM32F407的芯片资源建立工程进行配置

    2、配置定时器

     

    3、配置时钟

    选择外部时钟

    4、配置工程并输出

    5、下载验证

    用keil打开刚刚的工程并开启TIM1,下载到板子测试

    编辑下载验证,用逻辑分析仪测试结果为PA8输出频率为2KHz,占空比为50%的PWM波

    第五步 移植到RT-Thread工程并产生PWM波

    在board.h里按照步骤开启RT-Thread的驱动

    1、在RT-Thread工程工程里开启PWM的驱动

    2、移植STM32CubeMX生成的PWM文件

    将STM32CubeMX生成的工程里的void HAL_TIM_MspPostInit(TIM_HandleTypeDef* timHandle)函数体复制到drv_pwm.c的文件里

    3、 在drv_pwm.c文件下修改两处

    使能定时器时钟

    定义 PWM1_CONFIG

    4、开启相关宏定义

    5、验证是否开启PWM成功

    将官网Demo示例中samples文件夹下的main_3.c内容复制替换自己的main.c里的内容

    构建下载后用逻辑分析仪可以看见一段一段不同频率的PWM波,注意不是循环播放,防止逻辑分析仪捕捉不到,捕捉的同时让单片机复位

    然后将事前准备好的无源蜂鸣器模块接上,可以听见蜂鸣器发出不同的声音

    第六步 添加音乐编码与解码文件

    将官网Demo示例中code/decode文件夹下的decode.c和decode.h两个文件复制到你自己的工程文件的applications里

    将官网Demo示例中samples文件夹下的main_4.c内容复制替换自己的main.c里的内容

    并在main.c里添加#include "decode.h"头文件

    如果构建出现以下情况,则在rtthread.h里添加#include <stdint.h>头文件即可

    构建成功后下载到开发板,连接蜂鸣器就会听到蜂鸣器在播放两只老虎的音乐

    用RT-Thread Studio自带的串口终端显示汉字会乱码,这里我用另外一个终端软件MobaXterm,也可以看到串口打印出正在播放:两只老虎

    第七步 播放器的实现

    将官网Demo示例中code/player文件夹下的player.c和player.h两个文件复制到你自己的工程文件的applications里

    将官网Demo示例中samples文件夹下的song_data.h文件复制到你自己的工程文件的applications里

    将官网Demo示例中samples文件夹下的main_5.c内容复制替换自己的main.c里的内容

    并在main.c里添加#include "decode.h"头文件,#include "song_data.h"头文件

    构建下载可以听到蜂鸣器在循环播放音乐

    在串口终端也能看到音乐播放器的列表,与正在播放的音乐

    第八步 给播放器添加按键控制

    将官网Demo示例中code/key文件夹下的key.c和key.h两个文件复制到你自己的工程文件的applications里

    将官网Demo示例中samples文件夹下的main_6.c内容复制替换自己的main.c里的内容

    并在main.c里添加#include "key.h"头文件

    重新映射管脚

    构建下载就可以通过按键切换上一首、下一首、播放与暂停功能

    至此,基于RT-Thread+STM32F407的蜂鸣器音乐播放器便学习完毕,详情请关注官网

    RT-Thread 文档中心

    展开全文
  • 利用GPIO控制无源蜂鸣器发声,播放音乐。使用SysTick延时,使用位带操作寻址IO口引脚。
  • STM32 控制蜂鸣器播放音乐的原理和实例 本文通过将乐谱里的每个音符的声音频率和声音时长保存在两个数组里面。 1.使用通用定时器TIM4实现无中断的微秒级延时函数,控制每个音符的发声时长。 2.使用系统滴答时钟...

    STM32 控制蜂鸣器播放音乐的原理和实例

    本文通过将乐谱里的每个音符的声音频率和声音时长保存在两个数组里面。
    1.使用通用定时器TIM4实现无中断的微秒级延时函数,控制每个音符的发声时长。
    2.使用系统滴答时钟Systick实现带有中断的输出控制,在中断函数里实现蜂鸣器端口输出电平反转,并且根据当前播放音符的频率重新设置中断产生时间。

    一、播放的原理

    播放的乐谱:
    在这里插入图片描述

    1.1 C音调乐谱对应的音频(Hz):

    在这里插入图片描述
    根据乐谱的基础知识可知,低音的下面加点,高音的上面加点,普通的不加点。

    //用枚举定义,记录所有的音频。
    	   enum  Low_frequency{l_dao=262,l_re=286,l_mi=311,l_fa=349,l_sao=392,l_la=440,l_xi=494};
           enum  Normal_frequency{dao=523,re=587,mi=659,fa=698,sao=784,la=880,xi=987};
           enum  High_frequency{h_dao=1046,h_re=1174,h_mi=1318,h_fa=1396,h_sao=1567,h_la=1760,h_xi=1975};
    

    1.2 乐谱对应的节拍-音长:

    本次乐谱的节拍为每分钟72拍,可以算出每个节拍的时长:

    然后看乐谱的第一小节:
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述
    最后将整个乐谱的音频和音长记录在两个数组里。

    二、播放音乐的具体实现

    2.1 无中断的毫秒延时函数

    //TIM_4初始化函数
    void TIM_4(void)
    {
        TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    		RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4,ENABLE);
    	
        TIM_TimeBaseStructure.TIM_Period = 1;	
        TIM_TimeBaseStructure.TIM_Prescaler=(72-1);
    	  TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Down;
    	  TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;
    
        TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);
    }
    
    //延时n个us
    void delay_us(unsigned int nus)
    {
    	TIM4->CNT=nus-1;
    	TIM4->CR1|=TIM_CR1_CEN;
    	while((TIM4->SR & TIM_FLAG_Update) != SET)
    		;
    	TIM4->CR1&=(~TIM_CR1_CEN);
    	TIM4->SR &=~(TIM_FLAG_Update);
    }
    //延时n个毫秒
    void delay_ms(unsigned int nms)
    {
    	int count;
    	for(count=0;count<nms;count++)
    	delay_us(1000);
    }
    
    

    2.2 Systick的中断初始化和中断函数

    中断初始化:

    void SysTick_Init(int n)
    {
    /* SystemFrequency /1000 1ms 中断一次
    * SystemFrequency / 100000 10us 中断一次
    * SystemFrequency / 1000000 1us 中断一次
    */
    if (SysTick_Config(SystemCoreClock/1000000*n)) {
    /* Capture error */
    	  while(1)
    			;
    	}
    }
    
    

    中断函数:

    //stm32f10x_it.c,官方库函数文件里的中断函数
      //以下是需要添加的代码
      #define Buzzer_TOGGLE		 {GPIOC->ODR ^=GPIO_Pin_0;}  //PC0是连接蜂鸣器的引脚
      extern int C;
      void SysTick_Init(int n);
      //在 SysTick_Handler函数里面添加的代码
      void SysTick_Handler(void)
    {
    	Buzzer_TOGGLE;
        SysTick_Init(C);
    }
    

    2.3 main.c文件的代码

    #include "stm32f10x.h"
    
    #define Buzzer_TOGGLE		 {GPIOC->ODR ^=GPIO_Pin_0;}//PC0连接的是蜂鸣器,可以根据自己的实际情况修改端口
    int C;
    
    void key_init(void);
    void TIM_4(void);
    void Buzzer_init(void);//PC0连接的是蜂鸣器,可以根据自己的实际情况修改端口
    void SysTick_Init(int n);
    void delay_us(unsigned int nus);
    void delay_ms(unsigned int nms);
    
    
    /**
      * @brief  主函数
      * @param  无  
      * @retval 无
      */
    int main(void)
    {
    	   enum  Low_frequency{l_dao=262,l_re=286,l_mi=311,l_fa=349,l_sao=392,l_la=440,l_xi=494};
           enum  Normal_frequency{dao=523,re=587,mi=659,fa=698,sao=784,la=880,xi=987};
           enum  High_frequency{h_dao=1046,h_re=1174,h_mi=1318,h_fa=1396,h_sao=1567,h_la=1760,h_xi=1975};
            int j;
    		int i_f;
                //以下是《渴望》片头曲的一段简谱“好人一生平安”
                      unsigned int  f[]={re,mi,re,dao,l_la,dao,l_la,//每行对应一小节音调
                                  l_sao,l_mi,l_sao,l_la,dao,
                                      l_la,dao,sao,la,mi,sao,
                                      re,
                                      mi,re,mi,sao,mi,
                                      l_sao,l_mi,l_sao,l_la,dao,
                                  l_la,l_la,dao,l_la,l_sao,l_re,l_mi,
                                        l_sao,
                                        re,re,sao,la,sao,
                                        fa,mi,sao,mi,
                                        la,sao,mi,re,mi,l_la,dao,
                                        re,
                                        mi,re,mi,sao,mi,
                                        l_sao,l_mi,l_sao,l_la,dao,
                                        l_la,dao,re,l_la,dao,re,mi,
                                        re,
                                        l_la,dao,re,l_la,dao,re,mi,
                                        re,
                                        0xff};//以0xff作为音调的结束标志
                //以下是简谱中每个音调的节拍
                //“4”对应4个延时单位,“2”对应两个延时单位,“1”对应1个延时单位
                unsigned char  JP[]={4,1,1,4,1,1,2,//每行对应一小节音调的节拍
                                2,2,2,2,8,
                                    4,2,3,1,2,2,
                                    10,
                                    4,2,2,4,4,
                                    2,2,2,2,4,
                                2,2,2,2,2,2,2,
                                    10,
                                    4,4,4,2,2,
                                    4,2,4,4,
                                    4,2,2,2,2,2,2,
                                    10,
                                    4,2,2,4,4,
                                    2,2,2,2,6,
                                    4,2,2,4,1,1,4,
                                    10,
                                    4,2,2,4,1,1,4,
                                    10};
    
    	// key_init();//按键1的初始化函数,可以不用。
    	 TIM_4();
        // while(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)==0)//等待按键按下,执行播放音乐
          // delay_ms(5);
    		 
    	 Buzzer_init();
    
      while(1)
      {
    		i_f=0;
    		while(f[i_f]!=0xff)
    		{
            C=(1000*1000/2)/f[i_f]; //ms->us:1000,s->ms:1000,方波半周期翻转:1/2
    		SysTick_Init(C);       //翻转时长更新,重新配置翻转时长
    		for(j=0;j<JP[i_f];j++)
    	     delay_ms(208);
    	    i_f++;
    		}
      }
    }
    
    
    void key_init(void)
    {
    	GPIO_InitTypeDef keyInit;
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
    	
    	keyInit.GPIO_Pin=GPIO_Pin_0;
    	keyInit.GPIO_Mode=GPIO_Mode_IN_FLOATING;
    	GPIO_Init(GPIOA,&keyInit);
    }
    
    void TIM_4(void)
    {
        TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    		RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4,ENABLE);
    	
        TIM_TimeBaseStructure.TIM_Period = 1;	
        TIM_TimeBaseStructure.TIM_Prescaler=(72-1);
    	  TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Down;
    	  TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;
    
        TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);
    }
    
    void Buzzer_init(void)
    {
    		GPIO_InitTypeDef GPIO_InitStructure;
    		RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOC, ENABLE);
    		GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;	
    		GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;     
    		GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 
    	
    		GPIO_Init(GPIOC, &GPIO_InitStructure);	
    }
    
    void SysTick_Init(int n)
    {
    /* SystemFrequency /1000 1ms 中断一次
    * SystemFrequency / 100000 10us 中断一次
    * SystemFrequency / 1000000 1us 中断一次
    */
    if (SysTick_Config(SystemCoreClock/1000000*n)) {
    /* Capture error */
    	  while(1)
    			;
    	}
    }
    
    void delay_us(unsigned int nus)
    {
    	TIM4->CNT=nus-1;
    	TIM4->CR1|=TIM_CR1_CEN;
    	while((TIM4->SR & TIM_FLAG_Update) != SET)
    		;
    	TIM4->CR1&=(~TIM_CR1_CEN);
    	TIM4->SR &=~(TIM_FLAG_Update);
    }
    
    void delay_ms(unsigned int nms)
    {
    	int count;
    	for(count=0;count<nms;count++)
    	delay_us(1000);
    }
    /*********************************************END OF FILE**********************/
    
    

    最后,就可以听到蜂鸣器播放的音乐了。。。。。。

    三、参考书籍

    《单片机C语言应用100例》,王东锋等,6.3.4 实例47:用定时器T0的模式0控制播放《好人一生平安》

    展开全文
  • 本章教程为大家介绍STM32F407的GPIO应用之无源蜂鸣器蜂鸣器也是GPIO控制的经典测试例程,可以让大家对STM32F407应用有个简单的整体认识。 目录 第20章 STM32F407的GPIO应用之无源蜂鸣器 20.1 初学者重要提示 ...

    最新教程下载:http://www.armbbs.cn/forum.php?mod=viewthread&tid=93255

    第20章       STM32F407的GPIO应用之无源蜂鸣器

    本章教程为大家介绍STM32F407的GPIO应用之无源蜂鸣器,蜂鸣器也是GPIO控制的经典测试例程,可以让大家对STM32F407应用有个简单的整体认识。

    目录

    第20章       STM32F407的GPIO应用之无源蜂鸣器

    20.1 初学者重要提示

    20.2 蜂鸣器硬件设计

    20.2.1 蜂鸣器分类

    20.2.2 硬件设计

    20.3 蜂鸣器软件驱动设计

    20.4 蜂鸣器板级支持包(bsp_beep.c)

    20.4.1 宏定义设置

    20.4.2 蜂鸣器结构体变量

    20.4.3 函数BEEP_InitHard

    20.4.4 函数BEEP_Start

    20.4.5 函数BEEP_Pro

    20.5 蜂鸣器驱动移植和使用

    20.6 实验例程设计框架

    20.7 实验例程说明(MDK)

    20.8 实验例程说明(IAR)

    20.9 总结


     

    20.1 初学者重要提示

    1.   学习本章节前,务必保证已经学习了第13,14和15章。
    2.   注意有源蜂鸣器和无源蜂鸣器的区别,本章教程的17.2.1小节有专门说明。
    3.   开发板是采用的无源蜂鸣器,需要PWM驱动,而截至本章节还没有讲到PWM,会在第XX章节专门为大家讲解(更新到相应章节时再添),程序中是通过一个宏定义控制使能和关闭,所以对于初学者来说,当前阶段仅需了解到使能和关闭方法即可,后面学习到PWM章节了,再深入了解。
    4.   无源蜂鸣器的控制采用的非阻塞方式,实际项目中比较实用。

    20.2 蜂鸣器硬件设计

    蜂鸣器的硬件设计如下:

    通过这个硬件设计,有如下两点需要学习:

    20.2.1 蜂鸣器分类

    蜂鸣器主要有电磁式和电压式两种,而且都有无源蜂鸣器和有源蜂鸣器两类。开发板使用的是电磁式无源蜂鸣器,而有源和无源的区别是有源蜂鸣器内部自带振荡器,给个电压就能发声,但频率是固定的,只能发出一种声音,而无源蜂鸣器频率可控,给个方波才可以发声,并且根据不同频率发出不同的声音效果。

      拓展知识

    关于有源蜂鸣器和无源蜂鸣器区别:

    http://www.armbbs.cn/forum.php?mod=viewthread&tid=89764

    20.2.2 硬件设计

    关于硬件驱动,这里主要有三点需要大家认识到:

    •   S8050TL1是NPN型三极管,这里是当开关使用,PA8输出高电平的时候三极管导通,输出低电平,三极管关闭。
    •   电阻R70起到限流的作用。
    •   电阻R47在这里有特别的作用,首先要普及一个知识点,这里使用的是电磁式蜂鸣器,属于感性负载,切断这种负载必须要注意,如果电流消失,电感两端的电压将急剧上升,这种感应冲击足以损坏逻辑门电路或者其它形式的负载驱动电路,为了保护这个电路,可以用一个二极管或者电阻吸收感应冲击。

     

      拓展知识

    STM32的GPIO控制三极管驱动各种负载的安全措施和注意事项:

    http://www.armbbs.cn/forum.php?mod=viewthread&tid=89776

    20.3 蜂鸣器软件驱动设计

    软件驱动对有源蜂鸣器和无源蜂鸣器都做了支持,默认情况下用的是无源蜂鸣器。我们使用蜂鸣器的话,大部分情况下可以配置鸣叫次数、鸣叫的时间和停止的时间。本驱动设计就是基于这种应用方式实现,基本可以满足大部分应用情况。

    设计这个软件驱动的关键之处是如何避免采用阻塞式的实现方式,比如要实现鸣叫1秒,停止1秒,循环5次,如果是阻塞方式等待1秒执行完毕,那就时间太长了。鉴于这种情况,程序里面实现了一种非阻塞的方式,通过滴答定时器中断每10ms调用一次蜂鸣器处理函数来实现鸣叫次数、鸣叫的时间和停止的时间的更新。

    20.4 蜂鸣器板级支持包(bsp_beep.c)

    蜂鸣器驱动文件bsp_beep.c主要实现了如下几个API:

    •   BEEP_InitHard
    •   BEEP_Start
    •   BEEP_Stop
    •   BEEP_Pause
    •   BEEP_Resume
    •   BEEP_KeyTone
    •   BEEP_Pro

     

    这里我们重点讲解函数BEEP_InitHard、BEEP_Sart和BEEP_Pro。

    函数BEEP_Stop、BEEP_Pause和BEEP_Resume测试效果不够好,推荐直接使用BEEP_Sart即可,设置鸣叫时间、停止鸣叫时间和循环次数。而BEEP_KeyTone是基于BEEP_Start实现的,直接调用的BEEP_Start(5, 1, 1);    /* 鸣叫50ms,停10ms, 1次 */

    20.4.1 宏定义设置

    此文件的开头有一个宏定义选择,用户可以选择使用有源蜂鸣器或者无源蜂鸣器。

    //#define BEEP_HAVE_POWER        /* 定义此行表示有源蜂鸣器,直接通过GPIO驱动, 无需PWM */
    
    #ifdef    BEEP_HAVE_POWER        /* 有源蜂鸣器 */
    
        /* PA8 */
        #define GPIO_RCC_BEEP   RCC_AHB1Periph_GPIOA
        #define GPIO_PORT_BEEP    GPIOA
        #define GPIO_PIN_BEEP    GPIO_Pin_8
    
        #define BEEP_ENABLE()    GPIO_PORT_BEEP->BSRRL = GPIO_PIN_BEEP            /* 使能蜂鸣器鸣叫 */
        #define BEEP_DISABLE()    GPIO_PORT_BEEP->BSRRH = GPIO_PIN_BEEP            /* 禁止蜂鸣器鸣叫 */
    #else        /* 无源蜂鸣器 */
        /* PA8 ---> TIM1_CH1 */
    
        /* 1500表示频率1.5KHz,5000表示50.00%的占空比 */
        #define BEEP_ENABLE()    bsp_SetTIMOutPWM(GPIOA, GPIO_Pin_8, TIM1, 1, 1500, 5000);
    
        /* 禁止蜂鸣器鸣叫 */
        #define BEEP_DISABLE()    bsp_SetTIMOutPWM(GPIOA, GPIO_Pin_8, TIM1, 1, 1500, 0);
    #endif
    •   使能了宏定义BEEP_HAVE_POWER就可以选择使用有源蜂鸣器,默认是无源的。
    •   使用无源蜂鸣器时,需要用到定时器的PWM功能,这个功能会在XX章节专门讲解(制作到相应章节时再补充),这里仅需只知道配置了一个PWM来驱动蜂鸣器即可。

    20.4.2 蜂鸣器结构体变量

    为了方便蜂鸣器的控制,专门封装了一个结构体变量:

    typedef struct _BEEP_T
    {
        uint8_t ucEnalbe;
        uint8_t ucState;
        uint16_t usBeepTime;
        uint16_t usStopTime;
        uint16_t usCycle;
        uint16_t usCount;
        uint16_t usCycleCount;
        uint8_t ucMute;            
    }BEEP_T;
    •   成员ucEnalbe:用于使能或者禁止蜂鸣器。
    •   成员ucState:状态变量,用于蜂鸣器鸣叫和停止的区分。
    •   成员usBeepTime:鸣叫时间,单位10ms。
    •   成员usStopTime:停止鸣叫时间,单位10ms。
    •   成员usCycle:鸣叫和停止的循环次数。
    •   成员usCount:用于鸣叫和停止时的计数。
    •   成员usCycleCount:用于循环次数计数。
    •   成员ucMute:用于静音。

    20.4.3 函数BEEP_InitHard

    函数原型:

    /*
    *********************************************************************************************************
    *    函 数 名: BEEP_InitHard
    *    功能说明: 初始化蜂鸣器硬件
    *    形    参: 无
    *    返 回 值: 无
    *********************************************************************************************************
    */
    void BEEP_InitHard(void)
    {
    #ifdef    BEEP_HAVE_POWER        /* 有源蜂鸣器 */
        GPIO_InitTypeDef GPIO_InitStructure;
    
        /* 打开GPIOF的时钟 */
        RCC_AHB1PeriphClockCmd(GPIO_RCC_BEEP, ENABLE);
    
        BEEP_DISABLE();
    
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;        /* 设为输出口 */
        GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;        /* 设为推挽模式 */
        GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;    /* 上下拉电阻不使能 */
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;    /* IO口最大速度 */
    
        GPIO_InitStructure.GPIO_Pin = GPIO_PIN_BEEP;
        GPIO_Init(GPIO_PORT_BEEP, &GPIO_InitStructure);
    #endif
        
        g_tBeep.ucMute = 0;    /* 关闭静音 */
    }

    函数描述:

    此函数主要用于蜂鸣器的初始化,代码比较好理解。条件编译实现了一个无源蜂鸣器的初始化,配置引脚为推挽输出模式。由于V6开发板使用的无源蜂鸣器,所有没有开启宏定义BEEP_HAVE_POWER。

    使用举例:

    底层驱动初始化直接在bsp.c文件的函数bsp_Init里面调用即可。

    20.4.4 函数BEEP_Start

    函数原型:

    /*
    *********************************************************************************************************
    *    函 数 名: BEEP_Start
    *    功能说明: 启动蜂鸣音。
    *    形    参: _usBeepTime : 蜂鸣时间,单位10ms; 0 表示不鸣叫
    *              _usStopTime : 停止时间,单位10ms; 0 表示持续鸣叫
    *              _usCycle : 鸣叫次数, 0 表示持续鸣叫
    *    返 回 值: 无
    *********************************************************************************************************
    */
    void BEEP_Start(uint16_t _usBeepTime, uint16_t _usStopTime, uint16_t _usCycle)
    {
        if (_usBeepTime == 0 || g_tBeep.ucMute == 1)
        {
            return;
        }
    
        g_tBeep.usBeepTime = _usBeepTime;
        g_tBeep.usStopTime = _usStopTime;
        g_tBeep.usCycle = _usCycle;
        g_tBeep.usCount = 0;
        g_tBeep.usCycleCount = 0;
        g_tBeep.ucState = 0;
        g_tBeep.ucEnalbe = 1;    /* 设置完全局参数后再使能发声标志 */
    
        BEEP_ENABLE();        /* 开始发声 */
    }

    函数描述:

    此函数主要用于蜂鸣器的初始化,代码比较好理解。条件编译实现了一个无源蜂鸣器的初始化,配置引脚为推挽输出模式。由于V6开发板使用的无源蜂鸣器,所有没有开启宏定义BEEP_HAVE_POWER。

    函数参数:

    •   第1个参数_usBeepTime用于设置蜂鸣时间,单位10ms,配置为0 表示不鸣叫。
    •   第2个参数_usStopTime用于设置蜂鸣时间,单位10ms,配置为0 表示不鸣叫。
    •   第3个参数_ _usCycle用于鸣叫次数,配置为0 表示持续鸣叫。

    使用举例:

    调用此函数前,务必优先调用函数BEEP_InitHard进行初始化。比如要实现鸣叫50ms,停10ms, 1次,就是BEEP_Start(5, 1, 1);

    20.4.5 函数BEEP_Pro

    函数原型:

    /*
    *********************************************************************************************************
    *    函 数 名: BEEP_Pro
    *    功能说明: 每隔10ms调用1次该函数,用于控制蜂鸣器发声。该函数在 bsp_timer.c 中被调用。
    *    形    参: 无
    *    返 回 值: 无
    *********************************************************************************************************
    */
    void BEEP_Pro(void)
    {
        if ((g_tBeep.ucEnalbe == 0) || (g_tBeep.usStopTime == 0) || (g_tBeep.ucMute == 1))
        {
            return;
        }
    
        if (g_tBeep.ucState == 0)
        {
            if (g_tBeep.usStopTime > 0)    /* 间断发声 */
            {
                if (++g_tBeep.usCount >= g_tBeep.usBeepTime)
                {
                    BEEP_DISABLE();        /* 停止发声 */
                    g_tBeep.usCount = 0;
                    g_tBeep.ucState = 1;
                }
            }
            else
            {
                ;    /* 不做任何处理,连续发声 */
            }
        }
        else if (g_tBeep.ucState == 1)
        {
            if (++g_tBeep.usCount >= g_tBeep.usStopTime)
            {
                /* 连续发声时,直到调用stop停止为止 */
                if (g_tBeep.usCycle > 0)
                {
                    if (++g_tBeep.usCycleCount >= g_tBeep.usCycle)
                    {
                        /* 循环次数到,停止发声 */
                        g_tBeep.ucEnalbe = 0;
                    }
    
                    if (g_tBeep.ucEnalbe == 0)
                    {
                        g_tBeep.usStopTime = 0;
                        return;
                    }
                }
    
                g_tBeep.usCount = 0;
                g_tBeep.ucState = 0;
    
                BEEP_ENABLE();            /* 开始发声 */
            }
        }
    }

    函数描述:

    此函数是蜂鸣器的主处理函数,用于实现鸣叫时间、停止鸣叫时间和循环次数的处理。

    使用举例:

    调用此函数前,务必优先调用函数BEEP_InitHard进行初始化。

    另外,此函数需要周期性调用,每10ms调用一次。

    •   如果是裸机使用,将此函数放在bsp.c文件的bsp_RunPer10ms函数里面即可,这个函数是由滴答定时器调用的,也就是说,大家要使用蜂鸣器,定时器的初始化函数bsp_InitTimer一定要调用。
    •   如果是RTOS使用,需要开启一个10ms为周期的任务调用函数BEEP_Pro。

    20.5 蜂鸣器驱动移植和使用

    按键移植步骤如下:

    •   第1步:复制bsp_beep.c,bsp_beep.h,bsp_tim_pwm.c和bsp_tim_pwm.h到自己的工程目录,并添加到工程里面。
    •   第2步:根据自己使用的蜂鸣器驱动引脚和频率,修改下面的宏定义即可
    #ifdef    BEEP_HAVE_POWER        /* 有源蜂鸣器 */
    
        /* PA8 */
        #define GPIO_RCC_BEEP   RCC_AHB1Periph_GPIOA
        #define GPIO_PORT_BEEP    GPIOA
        #define GPIO_PIN_BEEP    GPIO_PIN_8
    
        #define BEEP_ENABLE()    GPIO_PORT_BEEP->BSRRL = GPIO_PIN_BEEP            /* 使能蜂鸣器鸣叫 */
        #define BEEP_DISABLE()    GPIO_PORT_BEEP->BSRRH = GPIO_PIN_BEEP            /* 禁止蜂鸣器鸣叫 */
    #else        /* 无源蜂鸣器 */
        /* PA0 ---> TIM5_CH1 */
    
        /* 1500表示频率1.5KHz,5000表示50.00%的占空比 */
        #define BEEP_ENABLE()    bsp_SetTIMOutPWM(GPIOA, GPIO_PIN_0, TIM5, 1, 1500, 5000);
    
        /* 禁止蜂鸣器鸣叫 */
        #define BEEP_DISABLE()    bsp_SetTIMOutPWM(GPIOA, GPIO_PIN_0, TIM5, 1, 1500, 0);
    #endif
    •   第3步:这几个驱动文件主要用到HAL库的GPIO和TIM驱动文件,简单省事些可以添加所有HAL库.C源文件进来。
    •   第4步,应用方法看本章节配套例子即可。

    特别注意,别忘了每10ms调用一次按键检测函数BEEP_Pro()。

    20.6 实验例程设计框架

    通过程序设计框架,让大家先对配套例程有一个全面的认识,然后再理解细节,本次实验例程的设计框架如下:

      第1阶段,上电启动阶段:

    • 这部分在第14章进行了详细说明。

      第2阶段,进入main函数:

    •   第1部分,硬件初始化,主要是HAL库,系统时钟,滴答定时器,蜂鸣器等。
    •   第2部分,应用程序设计部分,实现了一个蜂鸣器应用。
    •   第3部分,蜂鸣器程序每10ms在滴答定时中断执行一次。

    20.7 实验例程说明(MDK)

    配套例子:

    V5-004_无源蜂鸣器

    实验目的:

    1. 学习无源蜂鸣器的控制实现。

    实验内容:

    1. 启动一个自动重装软件定时器,每100ms翻转一次LED2。

    实验操作:

    1. K1键按下,按键提示音(固定频率1.5KHz)。
    2. K2键按下,急促鸣叫10次。
    3. K3键按下,长鸣3次。

    上电后串口打印的信息:

    波特率 115200,数据位 8,奇偶校验位无,停止位 1

    程序设计:

      系统栈大小分配:

      硬件外设初始化

    硬件外设的初始化是在 bsp.c 文件实现:

    /*
    *********************************************************************************************************
    *    函 数 名: bsp_Init
    *    功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次
    *    形    参:无
    *    返 回 值: 无
    *********************************************************************************************************
    */
    void bsp_Init(void)
    {
        /* 
           STM32H429 HAL 库初始化,此时系统用的还是F407自带的16MHz,HSI时钟:
           - 调用函数HAL_InitTick,初始化滴答时钟中断1ms。
           - 设置NVIV优先级分组为4。
         */
        HAL_Init();
    
        /* 
           配置系统时钟到168MHz
           - 切换使用HSE。
           - 此函数会更新全局变量SystemCoreClock,并重新配置HAL_InitTick。
        */
        SystemClock_Config();
    
        /* 
           Event Recorder:
           - 可用于代码执行时间测量,MDK5.25及其以上版本才支持,IAR不支持。
           - 默认不开启,如果要使能此选项,务必看V5开发板用户手册第8章
        */    
    #if Enable_EventRecorder == 1  
        /* 初始化EventRecorder并开启 */
        EventRecorderInitialize(EventRecordAll, 1U);
        EventRecorderStart();
    #endif
        
        bsp_InitKey();        /* 按键初始化,要放在滴答定时器之前,因为按钮检测是通过滴答定时器扫描 */
        bsp_InitTimer();      /* 初始化滴答定时器 */
        bsp_InitUart();    /* 初始化串口 */
        bsp_InitExtIO();  /* 初始化扩展IO */
        bsp_InitLed();        /* 初始化LED */    
        BEEP_InitHard();  /* 初始化蜂鸣器 */
    }

      每10ms调用一次蜂鸣器处理:

    蜂鸣器处理是在滴答定时器中断里面实现,每10ms执行一次检测。

    /*
    *********************************************************************************************************
    *    函 数 名: bsp_RunPer10ms
    *    功能说明: 该函数每隔10ms被Systick中断调用1次。详见 bsp_timer.c的定时中断服务程序。一些处理时间要求
    *              不严格的任务可以放在此函数。比如:按键扫描、蜂鸣器鸣叫控制等。
    *    形    参: 无
    *    返 回 值: 无
    *********************************************************************************************************
    */
    void bsp_RunPer10ms(void)
    {
        bsp_KeyScan10ms();
        BEEP_Pro();
    }

      主功能:

    主功能的实现主要分为两部分:

    •   启动一个自动重装软件定时器,每100ms翻转一次LED2。
    •   通过按键做蜂鸣器演示。
    /*
    *********************************************************************************************************
    *    函 数 名: main
    *    功能说明: c程序入口
    *    形    参: 无
    *    返 回 值: 错误代码(无需处理)
    *********************************************************************************************************
    */
    int main(void)
    {
        uint8_t ucKeyCode;    
        uint32_t freq = 1500;
    
        bsp_Init();        /* 硬件初始化 */
        
        PrintfLogo();    /* 打印例程名称和版本等信息 */
        PrintfHelp();    /* 打印操作提示 */
    
        bsp_StartAutoTimer(0, 100); /* 启动1个100ms的自动重装的定时器 */
        
        printf("蜂鸣器频率 = %dHz\r\n", freq);
        
        /* 主程序大循环 */
        while (1)
        {
            bsp_Idle();        /* CPU空闲时执行的函数,在 bsp.c */
            
            /* 判断定时器超时时间 */
            if (bsp_CheckTimer(0))    
            {
                /* 每隔100ms 进来一次 */  
                bsp_LedToggle(2);            
            }
                        
            /* 处理按键事件 */
            ucKeyCode = bsp_GetKey();
            if (ucKeyCode > 0)
            {
                /* 有键按下 */
                switch (ucKeyCode)
                {
                    case KEY_DOWN_K1:          /* K1按键按下,提示音 */
                        BEEP_KeyTone();
                        printf("1按键按下,提示音(固定频率1.5KHz)\r\n");            
                        break;        
                    
                    case KEY_DOWN_K2:          /* K2按键按下,急促鸣叫10次*/
                        BEEP_Start(5, 5, 10); /* 鸣叫50ms,停止50ms,10次*/
                        printf("K2按键按下,急促鸣叫10次\r\n");                
                        break;    
    
                    case KEY_DOWN_K3:           /* K3按键按下,长鸣3次*/
                        BEEP_Start(50, 50, 3); /* 鸣叫500ms,停止500ms,3次*/
                        printf("K3按键按下,长鸣3次\r\n");
                        break;    
    
                    default:
                        break;
                }
            }
        }
    }

    20.8 实验例程说明(IAR)

    配套例子:

    V5-004_无源蜂鸣器

    实验目的:

    1. 学习无源蜂鸣器的控制实现。

    实验内容:

    1. 启动一个自动重装软件定时器,每100ms翻转一次LED2。

    实验操作:

    1. K1键按下,按键提示音(固定频率1.5KHz)。
    2. K2键按下,急促鸣叫10次。
    3. K3键按下,长鸣3次。

    上电后串口打印的信息:

    波特率 115200,数据位 8,奇偶校验位无,停止位 1

    程序设计:

      系统栈大小分配:

      硬件外设初始化

    硬件外设的初始化是在 bsp.c 文件实现:

    /*
    *********************************************************************************************************
    *    函 数 名: bsp_Init
    *    功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次
    *    形    参:无
    *    返 回 值: 无
    *********************************************************************************************************
    */
    void bsp_Init(void)
    {
        /* 
           STM32H429 HAL 库初始化,此时系统用的还是F07自带的16MHz,HSI时钟:
           - 调用函数HAL_InitTick,初始化滴答时钟中断1ms。
           - 设置NVIV优先级分组为4。
         */
        HAL_Init();
    
        /* 
           配置系统时钟到168MHz
           - 切换使用HSE。
           - 此函数会更新全局变量SystemCoreClock,并重新配置HAL_InitTick。
        */
        SystemClock_Config();
    
        /* 
           Event Recorder:
           - 可用于代码执行时间测量,MDK5.25及其以上版本才支持,IAR不支持。
           - 默认不开启,如果要使能此选项,务必看V5开发板用户手册第8章
        */    
    #if Enable_EventRecorder == 1  
        /* 初始化EventRecorder并开启 */
        EventRecorderInitialize(EventRecordAll, 1U);
        EventRecorderStart();
    #endif
        
        bsp_InitKey();        /* 按键初始化,要放在滴答定时器之前,因为按钮检测是通过滴答定时器扫描 */
        bsp_InitTimer();      /* 初始化滴答定时器 */
        bsp_InitUart();    /* 初始化串口 */
        bsp_InitExtIO();  /* 初始化扩展IO */
        bsp_InitLed();        /* 初始化LED */    
        BEEP_InitHard();  /* 初始化蜂鸣器 */
    }

      每10ms调用一次蜂鸣器处理:

    蜂鸣器处理是在滴答定时器中断里面实现,每10ms执行一次检测。

    /*
    *********************************************************************************************************
    *    函 数 名: bsp_RunPer10ms
    *    功能说明: 该函数每隔10ms被Systick中断调用1次。详见 bsp_timer.c的定时中断服务程序。一些处理时间要求
    *              不严格的任务可以放在此函数。比如:按键扫描、蜂鸣器鸣叫控制等。
    *    形    参: 无
    *    返 回 值: 无
    *********************************************************************************************************
    */
    void bsp_RunPer10ms(void)
    {
        bsp_KeyScan10ms();
        BEEP_Pro();
    }

      主功能:

    主功能的实现主要分为两部分:

    •   启动一个自动重装软件定时器,每100ms翻转一次LED2。
    •   通过按键做蜂鸣器演示。
    /*
    *********************************************************************************************************
    *    函 数 名: main
    *    功能说明: c程序入口
    *    形    参: 无
    *    返 回 值: 错误代码(无需处理)
    *********************************************************************************************************
    */
    int main(void)
    {
        uint8_t ucKeyCode;    
        uint32_t freq = 1500;
    
        bsp_Init();        /* 硬件初始化 */
        
        PrintfLogo();    /* 打印例程名称和版本等信息 */
        PrintfHelp();    /* 打印操作提示 */
    
        bsp_StartAutoTimer(0, 100); /* 启动1个100ms的自动重装的定时器 */
        
        printf("蜂鸣器频率 = %dHz\r\n", freq);
        
        /* 主程序大循环 */
        while (1)
        {
            bsp_Idle();        /* CPU空闲时执行的函数,在 bsp.c */
            
            /* 判断定时器超时时间 */
            if (bsp_CheckTimer(0))    
            {
                /* 每隔100ms 进来一次 */  
                bsp_LedToggle(2);            
            }
                        
            /* 处理按键事件 */
            ucKeyCode = bsp_GetKey();
            if (ucKeyCode > 0)
            {
                /* 有键按下 */
                switch (ucKeyCode)
                {
                    case KEY_DOWN_K1:          /* K1按键按下,提示音 */
                        BEEP_KeyTone();
                        printf("1按键按下,提示音(固定频率1.5KHz)\r\n");            
                        break;        
                    
                    case KEY_DOWN_K2:          /* K2按键按下,急促鸣叫10次*/
                        BEEP_Start(5, 5, 10); /* 鸣叫50ms,停止50ms,10次*/
                        printf("K2按键按下,急促鸣叫10次\r\n");                
                        break;    
    
                    case KEY_DOWN_K3:           /* K3按键按下,长鸣3次*/
                        BEEP_Start(50, 50, 3); /* 鸣叫500ms,停止500ms,3次*/
                        printf("K3按键按下,长鸣3次\r\n");
                        break;    
    
                    default:
                        break;
                }
            }
        }
    }

    20.9 总结

    本章节为大家介绍的无源蜂鸣器方案还是比较实用的,采用的非阻塞方式,实际项目中可以放心使用。

     

    展开全文
  • STM32F4——GPIO基本知识GPIO基本认识STM32F4共7组I/O,每组I/O有16个I/O口。每组IO的通过10个32位寄存器控制,分别控制I/O的配置、功能和数据等内容。其中部分寄存器32位全部使用,每两位控制一个I/O口,部分寄存器...
  • 1.STM32产生PWM波驱动无源蜂鸣器使其发声1)查看原理图,找到对应引脚(我这里时PA1)2)打开CubeMax,输入自己芯片的类型确定后,配置好系统时钟RCC,我这里是80Mhz,找到相应引脚PA1设置为GPIO_Output模式(用来切换引脚...
  • 使用有源蜂鸣器,只能发出固定的”滴滴“声,当然不能满足于此呀。使用无源蜂鸣器,只要输出不同频率的PWM波,即可发出不同的音符。不同的音符组合起来就是一个曲子了。1 乐谱简析1.1 音阶音阶是音乐必不可少的要素...
  • 本章教程为大家介绍STM32F429的GPIO应用之无源蜂鸣器蜂鸣器也是GPIO控制的经典测试例程,可以让大家对STM32F429应用有个简单的整体认识。 目录 第20章 STM32F429的GPIO应用之无源蜂鸣器 20.1 初学者重要提示 ...
  • 本篇主要讲述在STM32单片机开发板上通过STM32CubeIDE配置相关管脚和参数,来操作无源蜂鸣器播放歌曲《北京欢迎你》的步骤和原理。 软硬件需求 硬件:STM32系列单片机开发板一块(附带开发板的原理图)、串口下载线、...
  • stm32实现控制无源蜂鸣器,通过代码的编写,自己弄一点不一样的创意 (“演唱”小星星“) 学习内容: 1、 蜂鸣器工作原理 介绍蜂鸣器蜂鸣器主要分为压电式蜂鸣器和电磁式蜂鸣器两种类型: 1.压电式蜂鸣器:压电式...
  • 首先我们先了解STM32L系列的产品,STM32L与STM32F系列相比,STM32L精简一些外设,性能上没有变化,只是STM32L更适合于低功耗平台,同时它也具有STM32F系列的特点。好了不扯太多了(其实多了我也不知道),回到正题,...
  • //输出0,关闭蜂鸣器输出 } void beep_pwm_Init(u16 arr,u16 psc) { GPIO_InitTypeDef GPIO_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; RCC_APB...
  • 在正点原子精英板上实现蜂鸣器每间隔200ms响一次,同时用LED0进行指示(蜂鸣器响同时LED0点亮)。 二、硬件电路分析 LED0部分电路可以参考以下这篇博文: 【STM32F103实验(一)】跑马灯_傻萌的路飞的博客-CSDN...
  • STM32L4 PWM蜂鸣器

    千次阅读 2019-03-11 22:08:54
    STM32F1系列的产品,除了互联型产品外,工位8个定时器 TIM6、TIM7是基本定时器,TIM2、3、4、5是通用定时器,TIM1、TIM8是高级定时器 基本定时器 1.时钟源 定时器时钟TIMxCLK,即内部时钟CK_INT,经APB1预...
  • 第20章 STM32H7的GPIO应用之无源蜂鸣器本章教程为大家介绍STM32H7的GPIO应用之无源蜂鸣器蜂鸣器也是GPIO控制的经典测试例程,可以让大家对STM32H7应用有个简单的整体认识。20.1 初学者重要提示20.2 蜂鸣器硬件设计...
  • 蜂鸣器连接的是STM32F407的PF8管脚,使用PWM波控制,使之产生声音从高到低循环往复的效果。 PWM是一种对模拟信号电平进行数字编码的方法,该方法使用高分辨率计数器,调制方波的占空比来对一个具体模拟信号的电平...
  • STM32蜂鸣器驱动程序

    千次阅读 2021-04-13 21:07:21
    文章目录蜂鸣器硬件电路添加文件进入工程了解buzzer.c和buzzer.h修改main.c复制BUZZER_BEEP1.c修改参数尝试更多频率 杨桃32学习笔记,本文图片文字皆为转述 蜂鸣器硬件电路 有源蜂鸣器: 内置频率发生电路 通电就...
  • 而不是9 #define BEEP_TIM_AFx 2 // 复用功能编号, F429的DataSheet第180页 #define BEEP_TIMx TIM4 // TIM4外设端口 #define BEEP_TIM_CHx 4 // 通道编号 #define BEEP_TIM_CCRx CCR4 // 比较编号 #define BEEP_...
  • 通过串口接收到的不定长数据判断,如果是两个字节就进行蜂鸣器控制,通过第二个字节来控制蜂鸣器的频率,控制频率的方法是新开一个定时器,设置定时时间为串口接收到的第二个字节控制的时间,如果串口接收到第二个...
  • stm32蜂鸣器教程

    2020-03-06 12:35:12
    #要求:无源蜂鸣器(有源蜂鸣器不可以更改频率) 需要先了解乐谱 首先:我们需要知道各种音调的频率(部分定义如下): c文件 #include "music_task.h" #include "bsp_buzzer.h" #include "cmsis_os.h" #include "mx_...
  • STM32F4应用笔记(二)利用蜂鸣器播放天空之城

    万次阅读 多人点赞 2017-03-05 11:13:43
    音乐的产生主要是通过单片机的I/O口输出高低不同的脉冲信号来控制蜂鸣器发音,要想产生音频脉冲信号,需要算出某音频的周期(1/频率),然后将此周期除以2,即为半周期的时间。利用单片机定时器计时这个半周期的时
  • 本人第一次发文,很多都不懂,...板子是使用粤嵌科技的STM32F407ZE。 文章讲下述内容 1 项目文件结构 2 功能 3 源码: 4 从功能解析代码 5 使用说明 6. 可能遇到的问题 7. 播放音乐参考代码: 1 项目文件结构 ma...
  • 编写蜂鸣器程序,实现 FS-STM32F407 开发平台上的蜂鸣器按一定频率发出滴滴的响声。调试编译好 程序后,将程序下载到 FS-STM32F407 开发板,按复位键观察实验现象。 时钟配置: main.c 文件作如下修改: ...
  • 人耳能听到的频率范围在20Hz–20kHz之间,通过STM32的GPIO引脚快速切换高低电平输出就能实现无源蜂鸣器的发声,切换的频率不同,发出的音调就不一样。需要外部提供2~5khz左右的方波。 二、"哆瑞咪发…"的实现 每个...

空空如也

空空如也

1 2 3 4 5 ... 12
收藏数 237
精华内容 94
热门标签
关键字:

stm32f407蜂鸣器发出音乐