国产免费AV|泡泡玛特欧洲总部将设在伦敦|中文天堂网www新版资源在线|一本久道综合在线中文|国精产品一二三产区的使用方法|香蕉鱼在线观看|www.27eee

 找回密碼
 注冊
搜索

偽和弦音樂聲的產生原理及源碼

[復制鏈接]
樓主
zloop 發表于 2020-1-6 00:05:28 | 只看該作者 |只看大圖 |倒序瀏覽 |閱讀模式
這種聽起來比較悅耳的聲音產生原理也非常簡單。就是利用電容的放電產生一個漸弱的尾音,模擬出擊打風鈴的音色。
電路如下:
偽和弦音樂聲的產生原理及源碼 image.png
BUZ-H負責輸出音頻頻率,BUZ-L負責對C12的充電作控制。
例如,要發出“叮~~~~”的一聲,在BUZ-H輸出2400Hz的方波,BUZ-L輸出72ms的高電平,此段時間內,蜂鳴器將由幅值12V的頻率驅動,發出類似擊打瞬間的聲音,同時對C12充電。72ms后,BUZ-L輸出低電平,這個時候,蜂鳴器將由C12來提供驅動電流,并且隨著電容放電,聲音逐漸減弱,產生類似風鈴尾音的效果。1秒后,關閉BUZ-H的輸出。
這種發聲方式,其實還是單音頻發聲,只是在單音頻的基礎上,用電容的充放電模擬了擊打和尾音,產生比較豐滿悅耳的聽感,所以稱之為“偽和弦”。
各位有興趣的話,可以用多個蜂鳴器同時發出不同音調,組成多音的真和弦,一個音調輸出占用一個定時器。俺以前10多年前蛋疼,搞過幾十個蜂鳴器的(5和弦,蜂鳴器多個并聯),并且并增加一個IO用作電容的放電回路來產生短音,聽感還是不錯的。真有空時回老家翻出來拍個視頻給大家看看。
源碼如下,帶音量控制,帶家電常用的音調組合,還附上一個超級瑪麗的1UP聲音,玩過的朋友肯定會覺得很親切,哈哈。
源碼不是整個工程,我也懶得整理了,生活艱苦,搬磚不易。
用法,在您的工程里面增加兩個文件,一個名為Music.c,一個名為Music.h(頭文件)。現在源碼,使用的是STM32F1xx,主頻72M,使用的定時器是TIM2(任意定時器均可,自己修改),使用硬件PWM輸出。所以您單片機有N個定時器,則可以最多N-1個真和弦(留一個做主時基),做產品,通常一個偽和弦就夠了。Music_Srv()這個函數,沒4ms調用一次,您放中斷也行,放主循環也行(前提是您主循環沒有阻塞的占用)。需要發聲的時候,任意地方放一句 Music_Triger=MUSIC_XXX;  即可,不阻塞,也不用等它播完再調用,隨傳隨叫春。
BUZ-L現在接的是PA1,這個任意IO即可,請自行修改。BUZ-H接的是PA0,這個隨您用不同的TIM而不同,自己修改,例程用的是TIM2。
  1. Music.h源碼:

  2. #ifndef __MUSIC_H_
  3. #define __MUSIC_H_

  4. //BUZ-L定義IO
  5. #define BEEPL_1 GPIOA_DSRR=BIT1
  6. #define BEEPL_0 GPIOA_DRR=BIT1
  7. #define BEEPL_XOR {if(BitTst(GPIOA_ODR,BIT1)) BEEPL_0; else BEEPL_1;}

  8. //音樂聲定義
  9. #define MUSIC_PWR_UP 1
  10. #define MUSIC_TURN_ON 2
  11. #define MUSIC_TURN_OFF 4
  12. #define MUSIC_DING 3
  13. #define MUSIC_UP 5
  14. #define MUSIC_DOWN 6
  15. #define MUSIC_1UP 7

  16. extern volatile  uint8  Music_Triger;    //觸發發聲標志
  17. extern uint8  flg_MusicPlaying;         //非0表示正在發聲


  18. void Music_Srv(void);     //4ms調用一次
  19. void Music_InitIO(void);    //初始化IO
  20. void Music_Init(void);   //初始化Music模塊。

  21. #endif


  22. //*************************************************************************************************************************************
  23. Music.c源碼:
  24. #include "music.h"


  25. #define TIM2_ARR (*((volatile uint16 *)(TIM2_BASE + 0x002c)))
  26. #define TIM2_CR1 (*((volatile uint16 *)(TIM2_BASE + 0)))
  27. #define TIM2_CCR1 (*((volatile uint16 *)(TIM2_BASE + 0x0034)))
  28. #define TIM2_CCER (*((volatile uint16 *)(TIM2_BASE + 0x0020)))
  29. #define TIM2_CNT   (*((volatile uint16 *)(TIM2_BASE + 0x0024)))
  30. #define TIM2_CCR2 (*((volatile uint16 *)(TIM2_BASE + 0x0038)))




  31. // 定義常用頻率,數字多少就是多少Hz
  32. #define _28 2850   
  33. #define _24 2400
  34. #define _22 2250
  35. #define _21 2100
  36. #define _18 1850
  37. #define _16 1650


  38. // 定義duo,rui,mi,fa,so等等
  39. #define _l1 130
  40. #define _l2 146
  41. #define _l3 164
  42. #define _l4 174
  43. #define _l5 196
  44. #define _l6 220
  45. #define _l7 246

  46. #define _1 261
  47. #define _2 293
  48. #define _3 329
  49. #define _4 349
  50. #define _5 392
  51. #define _6 440
  52. #define _7 494

  53. #define _1d1 523
  54. #define _2d1 587
  55. #define _3d1 659
  56. #define _4d1 698
  57. #define _5d1 784
  58. #define _6d1 880
  59. #define _7d1 987

  60. #define _1d2 1046
  61. #define _2d2 1175
  62. #define _3d2 1318
  63. #define _4d2 1397
  64. #define _5d2 1568
  65. #define _6d2 1760
  66. #define _7d2 1976

  67. #define _1d3 (_1d2*2)
  68. #define _2d3 (_2d2*2)
  69. #define _3d3 (_3d2*2)
  70. #define _4d3 (_4d2*2)
  71. #define _5d3 (_5d2*2)
  72. #define _6d3 (_6d2*2)
  73. #define _7d3 (_7d2*2)


  74. //定義不同的樂曲數組,0 結束
  75. const uint16 Music1_FrqTab[]={  //頻率表,對應BUZ-H的輸出頻率,0 結束
  76.         _18,        _18,        _21,        _21,        _24,        _24,        _28,        _28,        0,
  77. };
  78. const uint8 Music1_TimeTab[]={        //BUZ-L輸出時間,偶數高電平,奇數為低電平尾音,x4ms,0 結束
  79.         20,        30,        20,        30,        20,        30,        20,        255,        0,
  80. };


  81. const uint16 Music2_FrqTab[]={
  82.         _21,        _21,        _22,        _22,        _24,        _24,        0
  83. };
  84. const uint8 Music2_TimeTab[] ={                //x4ms
  85.         10,        18,        10,        18,        10,        255,        0,
  86. };


  87. const  uint16 Music3_FrqTab[]={
  88.         _24,        _24,        0,
  89. };
  90. const  uint8 Music3_TimeTab[] ={                //x4ms
  91.         18,        255,        0,
  92. };


  93. const  uint16 Music4_FrqTab[] ={
  94.         _28,        _28,        _24,        _24,        _21,        _21,        0
  95. };
  96. const  uint8 Music4_TimeTab[]={                //x4ms
  97.         10,        18,        10,        18,        10,        255,        0,
  98. };


  99. const  uint16 Music5_FrqTab[] ={
  100.         _16,        _16,        _18,        _18,        _21,        _21,        0
  101. };
  102. const  uint8 Music5_TimeTab[] ={                //x4ms
  103.         6,        16,        6,        16,        6,        255,        0,
  104. };


  105. const  uint16 Music6_FrqTab[] ={
  106.         _21,        _21,        _18,        _18,        _16,        _16,        0
  107. };
  108. const  uint8 Music6_TimeTab[] ={                //x4ms
  109.         6,        16,        6,        16,        6,        255,        0,
  110. };




  111. const uint16 Music7_FrqTab[]={
  112.         1324,1324,1574,1574,2645,2645,        2114,2114,2347,2347,3154,3154,        0,
  113. };
  114. const uint8 Music7_TimeTab[]={                //x4ms
  115.         15,          25,           15,            25,   15,    25,        15,     25        , 15 ,     25  ,  15,  255,        0,
  116. };




  117. uint8 Music_Vol=137;    //音量
  118. volatile uint8  Music_Triger=0;   //觸發播放哪一支,例如播放“叮~~~”,則任意地方調用 Music_Triger=MUSIC_DING;
  119. uint8  flg_MusicPlaying=0;   //非零播放中。

  120. //樂曲表指針
  121. uint16 const  *  music_frq_tab;      
  122. uint8 const  *  music_interval_tab;




  123. TIM_TimeBaseInitTypeDef T2_TimeBaseStruct;
  124. TIM_OCInitTypeDef T2_OCInitStruct;

  125. void Music_SetVolumn(uint8 vol){     //設置音量,并且初始化TIM輸出
  126.         uint32 lTmp;
  127.         lTmp=T2_TimeBaseStruct.TIM_Period;
  128.         lTmp*=vol;
  129.         lTmp/=255;
  130.         T2_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;            
  131.         T2_OCInitStruct.TIM_Pulse = lTmp;
  132.         T2_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;
  133.         T2_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;
  134.         TIM_OC1Init(TIM2, &T2_OCInitStruct);
  135. }


  136. /* ---------------------------------------------------------------
  137.   TIM2 Configuration: Output Compare Toggle Mode:
  138.   TIM2CLK = 72 MHz, Prescaler = 0x9, TIM2 counter clock = 7.2 MHz
  139. --------------------------------------------------------------- */

  140. void Music_SetFrq(uint16 frq){    //  設置頻率并初始化TIM
  141.         uint32 clk;
  142.         clk=7200000;
  143.         clk/=frq;
  144.         clk--;
  145.         /* Time base configuration */
  146.         T2_TimeBaseStruct.TIM_Period = clk;         
  147.         T2_TimeBaseStruct.TIM_Prescaler = 0x9;      
  148.         T2_TimeBaseStruct.TIM_ClockDivision = 0x0;   
  149.         T2_TimeBaseStruct.TIM_CounterMode = TIM_CounterMode_Up;
  150.         TIM_TimeBaseInit(TIM2, &T2_TimeBaseStruct);

  151.         Music_SetVolumn(Music_Vol);
  152.       
  153. }


  154. void Music_ChangeFrq(uint16 frq){    //改變頻率。
  155.         uint32 clk;
  156.         clk=7200000;
  157.         clk/=frq;
  158.         clk--;
  159.         /* Time base configuration */
  160.         TIM2_ARR = clk;     
  161.         clk*=Music_Vol;
  162.         clk/=255;
  163.         TIM2_CCR1=clk;
  164. }


  165. void Music_Frq_Enable(void){
  166.         TIM2_CCER|=BIT0;
  167. }

  168. void Music_Frq_Diable(void){
  169.         TIM2_CCER&=(~BIT0);
  170. }



  171. void Music_Init(void){
  172.         Music_SetFrq(4000);

  173.         TIM_ARRPreloadConfig(TIM2, ENABLE); // 這個記得要開

  174.         //啟用CCR1寄存器的影子寄存器(直到產生更新事件才更改設置)
  175.         TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Enable);

  176.         Music_Frq_Diable();
  177.         TIM_Cmd(TIM2, ENABLE);
  178. }


  179. void Music_InitIO(void){
  180.         GPIO_InitTypeDef tmpGPIO;
  181.       
  182.         tmpGPIO.GPIO_Mode=GPIO_Mode_Out_PP;
  183.         tmpGPIO.GPIO_Speed=GPIO_Speed_50MHz;

  184.         tmpGPIO.GPIO_Pin=GPIO_Pin_1;
  185.         GPIO_Init(GPIOA,&tmpGPIO);

  186.         tmpGPIO.GPIO_Pin=GPIO_Pin_0;
  187.         tmpGPIO.GPIO_Mode=GPIO_Mode_AF_PP;
  188.         GPIO_Init(GPIOA,&tmpGPIO);
  189.       
  190.         BEEPL_1;
  191. }


  192. void Music_Select(void){
  193.         switch(Music_Triger){
  194.                 default:      
  195.                         flg_MusicPlaying=0;
  196.                         return;
  197.                 case MUSIC_PWR_UP:
  198.                         music_frq_tab=Music1_FrqTab;
  199.                         music_interval_tab=Music1_TimeTab;
  200.                         break;
  201.                 case MUSIC_TURN_ON:
  202.                         music_frq_tab=Music2_FrqTab;
  203.                         music_interval_tab=Music2_TimeTab;
  204.                         break;
  205.                 case MUSIC_DING:
  206.                         music_frq_tab=Music3_FrqTab;
  207.                         music_interval_tab=Music3_TimeTab;
  208.                         break;
  209.                 case MUSIC_TURN_OFF:
  210.                         music_frq_tab=Music4_FrqTab;
  211.                         music_interval_tab=Music4_TimeTab;
  212.                         break;
  213.                 case MUSIC_UP:
  214.                         music_frq_tab=Music5_FrqTab;
  215.                         music_interval_tab=Music5_TimeTab;
  216.                         break;
  217.                 case MUSIC_DOWN:
  218.                         music_frq_tab=Music6_FrqTab;
  219.                         music_interval_tab=Music6_TimeTab;
  220.                         break;
  221.                 case MUSIC_1UP:
  222.                         music_frq_tab=Music7_FrqTab;
  223.                         music_interval_tab=Music7_TimeTab;
  224.                         break;
  225.         }
  226.         flg_MusicPlaying=1;
  227. }



  228. void Music_Srv(void){
  229.         static uint8  PlayStep=0;
  230.         static uint8  PlayCt=0;
  231.         uint8 cTmp;

  232.         if(Music_Triger){
  233.                 Music_Select();
  234.                 Music_Triger=0;
  235.                 PlayStep=0;
  236.                 PlayCt=0;
  237.                
  238.                 Music_ChangeFrq(music_frq_tab[PlayStep]);
  239.                 Music_Frq_Enable();

  240.                 BEEPL_1;
  241.         }
  242.         if(flg_MusicPlaying){
  243.                 cTmp=music_interval_tab[PlayStep];
  244.                 PlayCt++;
  245.                 if(PlayCt>=cTmp){
  246.                         PlayCt=0;
  247.                         PlayStep++;
  248.                         Music_ChangeFrq(music_frq_tab[PlayStep]);
  249.                         if(music_interval_tab[PlayStep]==0){
  250.                                 flg_MusicPlaying=0;      
  251.                         }
  252.                         else{
  253.                                 BEEPL_XOR;
  254.                         }
  255.                 }
  256.                
  257.         }
  258.         else{
  259.                 BEEPL_0;
  260.                 Music_Frq_Diable();
  261.         }
  262. }
復制代碼



沙發
ysz 發表于 2020-1-10 13:30:48 | 只看該作者
請問:h文件中的GPIOA_DSRR、GPIOA_DRR、BitTst是什么含義,以及#define BEEPL_XOR {if(BitTst(GPIOA_ODR,BIT1)) BEEPL_0; else BEEPL_1;}該怎么理解。
能否告知,謝謝。
您需要登錄后才可以回帖 登錄 | 注冊

本版積分規則

手機版|小黑屋|ELEOK |網站地圖

GMT+8, 2026-5-26 03:16

Powered by Discuz! X5.0

© 2001-2026 Discuz! Team.

快速回復 返回頂部 返回列表