基于STM32F103 蜂鸣器 播放音乐

本人小白一个,在暑假期间利用休息时间自学32,在此篇中,若有不对指出,还请各位大佬多多指点,小弟感激不尽。

我想要实现的是通过stm32f103mini板,播放制定的音乐。蜂鸣器的发声原理如果有不理解的,请自行百度。要想播放音乐,就要掌握两个关键,一个是节拍,就是类似于钢琴,吉他之类的节拍。另一个就是音调,音调是通过PWM输出引脚输出PWM的高低来控制。而播放音乐就是在每一个固定的节拍中播放对应的音调,当很多个音调连接起来,就成了一串优美的音乐了。

话不多说,先上干货。

beep.h

#ifndef __BEEP_H
#define __BEEP_H     
#include "sys.h"
//////////////////////////////////////////////////////////////////////////////////     
#define RCC_BEEP_CLK     RCC_APB2Periph_GPIOB                                  
#define BEEP_Pin     GPIO_Pin_1
#define BEEP_GPIO    GPIOB//这些定义都是为了简化调用而已。

////////////////////////////////////////////////////////////////////////////////// 

#define BEEP PBout(1)    // BEEP  接口定义


// 定义低音音名,单位HZ
#define L1 262
#define L2 294
#define L3 330
#define L4 349
#define L5 392
#define L6 440
#define L7 494

// 定义中音音名
#define M1 523
#define M2 587
#define M3 659
#define M4 698
#define M5 784
#define M6 880
#define M7 988

//定义高音音名
#define H1 1047
#define H2 1175
#define H3 1319
#define H4 1397
#define H5 1568
#define H6 1760
#define H7 1976

// 
#define TT 2000

typedef struct
{
  short mName; //元素1,音名,取值是上边的三种音名,低中高(1~7),0表是休止符
  short mTime; //元素2,时值,取值范围是全音符,半分音符等等
}tNote;//定义一个结构体,里边包含两个元素。


extern u8 beep_switch;//
//extern u16 beep_time;

 

void BEEP_PWM_Init(u16 arr,u16 psc);
void buzzerSound(unsigned short usFreq)    ;
void musicPlay(void) ;
void buzzerQuiet(void);

#endif

 

 

 

 

 beep.c

#include "beep.h"
#include "delay.h"
//////////////////////////////////////////////////////////////////////////////////     
        
u8 beep_switch=0;
//u16 beep_time=0;
 



 

///*
//定义曲目《最炫民族风》

//定义了一个数组,用来装节拍和对应音调
const tNote MyScore[]=
{
  {L6,TT/4},{L3,TT/8},{L5,TT/8},{L6,TT/4},{L6,TT/8},{M1,TT/8},{M1,TT/4},{M2,TT/8},{M1,TT/8},{L6,TT/2},{M1,TT/4},{M1,TT/8},{L5,TT/8},{M1,TT/8},{M2,TT/8},{M3,TT/8},{M5,TT/8},
  {M5,TT/8},{M3,TT/8},{M2,TT/4},{M3,TT/2},{M6,TT/8},{M6,TT/8},{M6,TT/8},{M5,TT/8},{M3,TT/8},{M3,TT/4},{M1,TT/8},{L6,TT/8},{L6,TT/8},{L6,TT/8},{M3,TT/8},//²ÔãµÄÌìÑÄÊÇÎҵİ®¡£¡£¡£×îѽ×îÒ¡
  {M2,TT/2},{M3,TT/8},{M3,TT/8},{M5,TT/8},{M3,TT/8},{M2,TT/8},{M3,TT/8},{M2,TT/8},{M1,TT/8},{L6,TT/4},{L5,TT/4},{L6,TT/2}, //°Ú£¬Ê²Ã´ÑùµÄ¸èÉù²ÅÊÇ×»³
  {L6,TT/4},{L3,TT/8},{L5,TT/8},{L6,TT/4},{L6,TT/8},{M1,TT/8},{M1,TT/4},{M2,TT/8},{M1,TT/8},{L6,TT/2},{M1,TT/4},{M1,TT/8},{L5,TT/8},{M1,TT/8},{M2,TT/8},{M3,TT/8},{M5,TT/8},
  {M5,TT/8},{M3,TT/8},{M2,TT/4},{M3,TT/2},{M6,TT/8},{M6,TT/8},{M6,TT/8},{M5,TT/8},{M3,TT/8},{M3,TT/4},{M1,TT/8},{L6,TT/8},{L6,TT/8},{L6,TT/8},{M3,TT/8},//²ÔãµÄÌìÑÄÊÇÎҵİ®¡£¡£¡£×îѽ×îÒ¡
  {M2,TT/2},{M3,TT/8},{M3,TT/8},{M5,TT/8},{M3,TT/8},{M2,TT/8},{M3,TT/8},{M2,TT/8},{M1,TT/8},{L6,TT/4},{L5,TT/4},{L6,TT/2}, //°Ú£¬Ê²Ã´ÑùµÄ¸èÉù²ÅÊÇ×»³
  {M3,TT/8},{M3,TT/8},{M5,TT/8},{M3,TT/8},{M3,TT/8},{M5,TT/8},{M5,TT/8},{M6,TT/8},{H1,TT/8},{M6,TT/8},{M5,TT/4},{M6,TT/2},{L6,TT/4},{L6,TT/8},
  {L5,TT/8},{L6,TT/4},{M1,TT/4},{M2,TT/8},{M3,TT/16},{M2,TT/16},{M1,TT/8},{M2,TT/8},{M3,TT/2},{L6,TT/8},{M6,TT/8},{M6,TT/8},{M5,TT/8},{M2,TT/8},{M3,TT/16},{M2,TT/16},
  {M1,TT/8},{M2,TT/8},{M3,TT/2},//ÁôÏÂÀ´
  {M1,TT/8},{L6,TT/8},{L6,TT/8},{M1,TT/8},{M2,TT/4},{L5,TT/8},{L5,TT/8},{M3,TT/8},{M5,TT/8},{M3,TT/8},{M2,TT/8},{M1,TT/2},{L6,TT/8},{M1,TT/8},{M2,TT/8},{M3,TT/8},{M2,TT/8},{M1,TT/8},
  {L5,TT/8},{L3,TT/8},{L6,TT/2},{L6,TT/4},{L6,TT/8},{L5,TT/8},{L6,TT/4},{M1,TT/4},{M2,TT/8},{M3,TT/16},{M2,TT/16},{M1,TT/8},{M2,TT/8},{M3,TT/2},{L6,TT/8},{M6,TT/8},
  {M6,TT/8},{M5,TT/8},{M2,TT/8},{M3,TT/16},{M2,TT/16},
  {M1,TT/8},{M2,TT/8},{M3,TT/2},//ÁôÏÂÀ´
  {M1,TT/8},{L6,TT/8},{L6,TT/8},{M1,TT/8},{M2,TT/4},{L5,TT/8},{L5,TT/8},{M3,TT/8},{M5,TT/8},{M3,TT/8},{M2,TT/8},{M1,TT/4+TT/8},{M1,TT/8},{L6,TT/8},
  {M1,TT/8},{M2,TT/8},{M3,TT/8},{M5,TT/8},{M3,TT/8},{M3,TT/8},{M5,TT/8},{M6,TT/2},{M6,TT/2},{L6,TT/4},{L6,TT/8},{L5,TT/8},{L6,TT/4},
  {L6,TT/8},{M1,TT/8},{M2,TT/8},{M3,TT/16},{M2,TT/16},{M1,TT/8},{M2,TT/8},{M3,TT/2},
  {M6,TT/8},{M5,TT/8},{M3,TT/8},{M2,TT/8},{M5,TT/8},{M3,TT/8},{M2,TT/8},{M1,TT/8},{M1,TT/2},//µÇÉÏÌìÍâÔÆÏöµÄÎę̀
  {L6,TT/4},{L6,TT/8},{L5,TT/8},{L6,TT/4},{M1,TT/4},{M2,TT/8},{M3,TT/16},{M2,TT/16},{M1,TT/8},{M2,TT/8},{M3,TT/2},{L6,TT/8},{M6,TT/8},{M6,TT/8},{M5,TT/8},{M2,TT/8},{M3,TT/16},{M2,TT/16},
  {M1,TT/8},{M2,TT/8},{M3,TT/2},//ÁôÏÂÀ´
  {M1,TT/8},{L6,TT/8},{L6,TT/8},{M1,TT/8},{M2,TT/4},{L5,TT/8},{L5,TT/8},{M3,TT/8},{M5,TT/8},{M3,TT/8},{M2,TT/8},{M1,TT/2},{L6,TT/8},{M1,TT/8},{M2,TT/8},{M3,TT/8},{M2,TT/8},{M1,TT/8},
  {L5,TT/8},{L3,TT/8},{L6,TT/2},{L6,TT/4},{L6,TT/8},{L5,TT/8},{L6,TT/4},{M1,TT/4},{M2,TT/8},{M3,TT/16},{M2,TT/16},{M1,TT/8},{M2,TT/8},{M3,TT/2},{L6,TT/8},{M6,TT/8},
  {M6,TT/8},{M5,TT/8},{M2,TT/8},{M3,TT/16},{M2,TT/16},
  {M1,TT/8},{M2,TT/8},{M3,TT/2},//ÁôÏÂÀ´
  {M1,TT/8},{L6,TT/8},{L6,TT/8},{M1,TT/8},{M2,TT/4},{L5,TT/8},{L5,TT/8},{M3,TT/8},{M5,TT/8},{M3,TT/8},{M2,TT/8},{M1,TT/4+TT/8},{M1,TT/8},{L6,TT/8},
  {M1,TT/8},{M2,TT/8},{M3,TT/8},{M5,TT/8},{M3,TT/8},{M3,TT/8},{M5,TT/8},{M6,TT/2},{M6,TT/2},
  {0,0},
};
//*/

 

//PWM初始化
 

void BEEP_PWM_Init(u16 arr,u16 psc)
{  
    GPIO_InitTypeDef GPIO_InitStructure;
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    TIM_OCInitTypeDef  TIM_OCInitStructure;
    

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
     RCC_APB2PeriphClockCmd(RCC_BEEP_CLK  | RCC_APB2Periph_AFIO, ENABLE);  //ʹÄÜGPIOÍâÉèºÍAFIO¸´Óù¦ÄÜÄ£¿éʱÖÓʹÄÜ
    
    //GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE); //TIM3部分重映射TIM3_CH4->PB0                                                                       
  
    GPIO_InitStructure.GPIO_Pin = BEEP_Pin; //TIM3_CH4
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //复用输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(BEEP_GPIO, &GPIO_InitStructure);
    
    TIM_TimeBaseStructure.TIM_Period = arr;  
    TIM_TimeBaseStructure.TIM_Prescaler =psc; //
    TIM_TimeBaseStructure.TIM_ClockDivision = 0; //
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //
 TIM_TimeBaseInit(TIM3,&TIM_TimeBaseStructure); 
         
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //Ñ¡Ôñ¶¨Ê±Æ÷ģʽ:TIMÂö³å¿í¶Èµ÷ÖÆÄ£Ê½2
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //±È½ÏÊä³öʹÄÜ
    TIM_OCInitStructure.TIM_Pulse = 0; //ÉèÖôý×°Èë²¶»ñ±È½Ï¼Ä´æÆ÷µÄÂö³åÖµ
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;//TIM_OCPolarity_High;//TIM_OCPolarity_Low; //Êä³ö¼«ÐÔ:TIMÊä³ö±È½Ï¼«ÐÔµÍ
    TIM_OC4Init(TIM3, &TIM_OCInitStructure);  //¸ù¾ÝTIM_OCInitStructÖÐÖ¸¶¨µÄ²ÎÊý³õʼ»¯ÍâÉèTIMx
    TIM_OC4PreloadConfig(TIM3, TIM_OCPreload_Enable);  //ʹÄÜTIMxÔÚCCR2ÉϵÄÔ¤×°ÔØ¼Ä´æÆ÷
    
    TIM_CCxCmd(TIM3,TIM_Channel_4 ,ENABLE);//Êä³ö¿ªÆô
    TIM_ARRPreloadConfig(TIM3, ENABLE); //ʹÄÜTIMxÔÚARRÉϵÄÔ¤×°ÔØ¼Ä´æÆ÷
    TIM_Cmd(TIM3, ENABLE);  //ʹÄÜTIMxÍâÉè
}

//蜂鸣器停止发声
void buzzerQuiet(void)    
{    
    TIM_SetCompare4(TIM3,0); //À®°È
    TIM_CCxCmd(TIM3,TIM_Channel_4 ,DISABLE);//

}
/////////////////////////////////////////////////////////     
//·äÃùÆ÷·¢³öÖ¸¶¨ÆµÂʵÄÉùÒô
//usFreqÊÇ·¢ÉùƵÂÊ£¬È¡Öµ (ϵͳʱÖÓ/65536)+1 ¡« 20000£¬µ¥Î»£ºHz
void buzzerSound(unsigned short usFreq)     
{
  unsigned long  ulVal;
  if((usFreq<=8000000/65536UL)||(usFreq>20000))//65536µÄÖµÊǶ¨Ê±Æ÷ÖØ×°ÔØ¼Ä´æÆ÷µÄ×î´óÖµ
  {
    buzzerQuiet();// 
  }
  else
  {
      ulVal=8000000/usFreq;//
      TIM3->ARR =ulVal ;    //定时器重装载寄存器周期的值
      TIM_SetCompare4(TIM3,ulVal /2);//音调高低
      TIM_CCxCmd(TIM3,TIM_Channel_4 ,ENABLE);//开启时钟
  }  
}

// 
void musicPlay(void) 
{     
static u8 i=0;    
    
      if(MyScore[i].mTime != 0) 
        {
            buzzerSound(MyScore[i].mName); 
            delay_ms(MyScore[i].mTime);
            i++;
            buzzerQuiet(); // 防止在中间发出杂音,以及留出音乐的停顿
            delay_ms(10);// 10 ms 
        }
 

   总的来说,感觉就PWM输出的一个小引用,难度不大,掌握蜂鸣器播放音乐的原理,那么会事半功倍,不论是那种板子,都能实现蜂鸣器播放音乐。花一些时间去思考,效率会提高不少。

我曾许下十年,只为最美的遇见。

我是西伯利亚螂,有缘再见。
 

 

 

#include "stm32f10x.h" #include "GPIOLIKE51.h" #define uint unsigned int #define uchar unsigned char #define CLOCK 72/8 //时钟=72M //函数声明 void GPIO_Configuration(void); /**************************************************************************** * 名 称:delay_us(u32 nus) * 功 能:微秒延时函数 * 入口参数:u32 us * 出口参数:无 * 说 明: * 调用方法:无 ****************************************************************************/ //void delay_us(u32 us) //{ // u32 temp; // SysTick->LOAD = 9*us; // SysTick->VAL=0X00;//清空计数器 // SysTick->CTRL=0X01;//使能,减到零是无动作,采用外部时钟 // do // { // temp=SysTick->CTRL;//读取当前倒计数值 // }while((temp&0x01;)&&(!(temp&(1<CTRL=0x00; //关闭计数器 // SysTick->VAL =0X00; //清空计数器 //} /**************************************************************************** * 名 称:delay_ms(u16 ms) * 功 能:毫秒延时函数 * 入口参数:u16 nms * 出口参数:无 * 说 明: * 调用方法:无 ****************************************************************************/ void delay_ms(u16 ms) { u32 temp; SysTick->LOAD = 9000*ms; SysTick->VAL=0X00;//清空计数器 SysTick->CTRL=0X01;//使能,减到零是无动作,采用外部时钟 do { temp=SysTick->CTRL;//读取当前倒计数值 }while((temp&0x01;)&&(!(temp&(1<CTRL=0x00; //关闭计数器 SysTick->VAL =0X00; //清空计数器 } //============================================================================= //文件名称:main //功能概要:主函数 //参数说明:无 //函数返回:int //============================================================================= int main(void) { GPIO_Configuration(); while (1) { // GPIO_SetBits(GPIOB,GPIO_Pin_9); // delay_ms(500);// 100=0.1S GPIO_ResetBits(GPIOB,GPIO_Pin_9); delay_ms(500); } } //============================================================================= //文件名称:GPIO_Configuration //功能概要:GPIO初始化 //参数说明:无 //函数返回:无 //============================================================================= void GPIO_Configuration(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE&#4
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值