1. 程式人生 > >基於STM32F103 蜂鳴器 播放音樂

基於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輸出的一個小引用,難度不大,掌握蜂鳴器播放音樂的原理,那麼會事半功倍,不論是那種板子,都能實現蜂鳴器播放音樂。花一些時間去思考,效率會提高不少。

我曾許下十年,只為最美的遇見。

我是西伯利亞螂,有緣再見。