[应用方案] 单片机做的音乐频谱

[复制链接]
1438|18
 楼主| saservice 发表于 2023-8-27 19:00 | 显示全部楼层 |阅读模式
  1.          

  2. #include <intrins.h>      //51基本运算(包括_nop_空函数)
  3. #include <math.h>

  4. #include "src\Define.h"


  5. ///////全局变量///////
  6. uchar data DelayTime=9;          //<=8效果最好;
  7. uchar data INTTime=0x40;  //0x40;       
  8. uchar data gain=6;
  9. uchar data Menu=2;
  10. uchar idata refreshflag[40];
  11. uchar  data LEDBuf[35];          //15列;从左到右;亮的位为真(1);
  12. uint32  data TouchKey=0;
  13. uchar data CBeep=0;
  14. //////////////////////


  15. void Delays(uint t)
  16. {  
  17.         uint j;
  18.         while(--t)
  19.                 for(j=0;j<5;j++);   
  20. }
  21. void Delaysms(uint t)
  22. {  
  23.         uint j;
  24.         while(--t)
  25.                 for(j=0;j<15;j++);   
  26. }



  27. #include "src\ADC.c"
  28. #include "src\Font.c"
  29. #include "src\fft.h"



  30. void PWM_init (void)          //PWM初始化函数         //PWM模式,接P1.3接口(PWM0),强上拉.
  31. {                  
  32.         CMOD=0x00;    //设置PCA定时器          0x00~0x03;
  33.         CL=0xEF;
  34.         CH=0xEF;
  35.         CCAPM0=0x42; //PWM0设置PCA工作方式为PWM方式(0100 0010)
  36.         CCAP0L=0xEF; //设置PWM0初始值与CCAP0H相同
  37.         CCAP0H=0xFF; // PWM0初始时为0

  38.         CR=1;        //启动PCA定时器
  39. }

  40. void PWM0_set (uchar set)           //PWM0占空比设置函数        (0x00~0xFF)
  41. {
  42.         CCAP0L= set; //设置值写入CCAP0L
  43.         CCAP0H= set; //设置值写入CCAP0H
  44. }


  45. void IOINIT(void)                                                          //I/O强上拉模式;
  46. {
  47.         P4SW = 0xff;                                  //启动I/O:P4;
  48.         P4M1 = B(00000000); P4M0 = B(10000000);P47=0;//震动马达;
  49.         P0M1 = 0x00;            P0M0 = 0xff;       P0=0; //点阵列(Y)(L:OFF; H,H+:ON,ON+;)
  50.         P1M1 = B(01000011); P1M0 = B(00110100);P1=B(10110111); //(P17@(高阻,IN)&P16@(高阻,IN);TouchKey) ... P14@(传统IO,Beep,IN) P13@(强推,OUT)呼吸灯 ... P11@(高阻,IN)AD2;P10@(高阻,IN)AD1;      
  51.         P2M1 = B(00000000); P2M0 = B(11111111);P2=0; //点阵行(X0(Left))(L:OFF; H,H+:ON,ON+;)  
  52.         P3M1 = B(00000000);        P3M0 = B(11111111);P3=0; //点阵行(X1(Right))(L:OFF; H,H+:ON,ON+;)               
  53.         P1ASF =B(00000011);                          //将P10,P11的IO设置为模拟输入功能;     

  54. //  Y(P0)
  55. //  ↑
  56. //H        |
  57. //         |
  58. //        |
  59. //L        |
  60. //         ---------------------→
  61. //        [L:X0(P2):H][L:X1(P3):H]

  62. //TestCode:
  63. //        P0=B(10000000);
  64. //        P2=B(00000001);
  65. //        P3=B(00010000);

  66. }



  67. void BufToLED_Refresh()                     //Refresh&Write Buf to LED ;
  68. {       
  69.          uchar data i;
  70.          uchar data X=1;          
  71.          uchar data Y=1;
  72.          for(X=1,i=2;X;X<<=1,i+=2)              //for(X=1;X!=0;X<<=1) //8bit
  73.          {
  74.                   P2=X;
  75.                 for(Y=1;Y!=0;Y<<=1)                            //Y=Y<<1;
  76.                  {
  77.                         P0=Y&LEDBuf[i];
  78.                         Delays(DelayTime);
  79.                         P0=0;
  80.                 }
  81.                 P2=0;       
  82.          };
  83.          for(X=1;X<B(10000000);X<<=1,i+=2)            //7bit
  84.          {
  85.                   P3=X;
  86.                 for(Y=1;Y!=0;Y<<=1)                            //Y=Y<<1;
  87.                  {
  88.                         P0=Y&LEDBuf[i];
  89.                         Delays(DelayTime);
  90.                         P0=0;
  91.                 }
  92.                 P3=0;       
  93.          };
  94.                
  95. }




  96. void LEDRefresh_INT() interrupt 3 //using 3   
  97. {
  98.         static uint x=0;                  
  99.         static uchar flag=1;

  100.     TL1 = 0x00;      
  101.     TH1 = INTTime;               //0x50~0x80

  102.         if(flag)
  103.         {
  104.                 if(++x==0xFF)                         //MINOUTPUT
  105.                 {
  106.                         flag=0;               
  107.                 }               
  108.         }
  109.         else
  110.         {
  111.                 if(--x==0xCF)                 //MAXOUTPUT
  112.                 {
  113.                         flag=1;                       
  114.                 }
  115.         }                        
  116.         PWM0_set(x);                 //设置PWM占空比

  117.         BufToLED_Refresh();                        
  118. }  


  119. void Timer_INT()
  120. {
  121.         TMOD = 0x11; //高4位控制T/C1
  122.         EA = 1;             //开总中断
  123.         TH1 = 0x00;  //16位计数寄存器T1高8位
  124.         TL1 = 0x00;  //16位计数寄存器T1低8位
  125.         ET1 = 1;     //T/C1中断开
  126.     TR1 = 1;     //T/C1启动

  127. }


  128. void FullScan()
  129. {
  130.         uchar data X=1;          
  131.         uchar data Y=1;

  132.          for(Y=1;Y!=0;Y<<=1)                       //Y=Y<<1;
  133.          {       
  134.                  P0=Y;
  135.                 for(X=1;X;X<<=1)                   //8bit
  136.                 {
  137.                          P2=X;
  138.                         Delays(7);       
  139.                 };

  140.                 P2=0;
  141.                 for(X=1;X<B(10000000);X<<=1)    //7bit
  142.                 {
  143.                          P3=X;
  144.                         Delays(7);
  145.                 };
  146.                 P3=0;
  147.                 P0=0;
  148.          }
  149. }


  150. void Main()
  151. {  
  152.         uint data Count=700;
  153.         uchar data i,Cgain,num=0;

  154.         IOINIT();
  155.         InitADC();                  

  156.         while(--Count)
  157.                 FullScan();

  158.         for(i=0;i<40;i++) refreshflag[i]=0x09;
  159.        
  160.         P14=0;                          //Beep
  161.         Delays(4000);
  162.         P14=1;

  163.         PWM_init();      //PWM初始化
  164.         PWM0_set(0xFB);
  165.        
  166.         Timer_INT();

  167.         for(i=0;i<34;i++)
  168.                 LEDBuf[i]=0x00;
  169.         FontDisp();

  170.         while(520)
  171.         {
  172.                 for(i=0;i<65;i++)
  173.                 {  
  174.                         dd[i].real=(GetADCResult(0)+GetADCResult(1))<<gain;          //读取ad结果并放大;
  175.                 }

  176.                  processfft();//傅立叶变化及处理

  177.                  ///////////////////TouchKey//////////////////////////
  178.                  while(P16==1)                                           //依据:脉冲 干扰持续时间短;
  179.                  {       
  180.                         if(CBeep)P14=0;
  181.                         if(++TouchKey>0x0000FF00)break;       
  182.                  }
  183.                  P14=1;

  184.                  if(P16==1)
  185.                  {
  186.                         if(++Menu==4)Menu=0;

  187.                         P14=0;
  188.                         P47=1;
  189.                         Delays(7000);          
  190.                         P14=1;
  191.                         P47=0;               
  192.                  }       
  193.                         TouchKey=0;
  194.                  //////////////////////////////////////////////

  195.                 if(P17==0)CBeep=!CBeep;

  196.                  if(dd[2].real<32)
  197.                  {
  198.                          if(++Count==300)          //电平值过小,这降低gain,减少噪音的电平显示;
  199.                          {
  200.                                 Count=0;
  201.                                 //if(++Menu==4)Menu=0;                  //切换Menu,显示方式;
  202.                                 gain=6;

  203.                                 P14=0;                          //Beep
  204.                                 Delays(1000);
  205.                                 P14=1;
  206.                          }
  207.                  }
  208.                  else
  209.                  {
  210.                          Count=1;
  211.        
  212.                          if(++num==0xAF)                         //播放时,Auto gain;
  213.                          {
  214.                                 num=0;

  215.                                 P14=0;                                   //Beep
  216.                                 Delays(700);
  217.                                 P14=1;
  218.                                                            //自动增益;Automatic gain;
  219.                                 Cgain=dd[2].real/32;
  220.                                 if(7<Cgain<=8)
  221.                                 {
  222.                                         gain=4;
  223.                                        
  224.                                 }
  225.                                 else if(4<Cgain<=6)
  226.                                 {
  227.                                         gain=5;
  228.                                        
  229.                                 }
  230.                                 else if(2<Cgain<=4)
  231.                                 {
  232.                                         gain=6;
  233.                                 }
  234.                                 else
  235.                                 {
  236.                                         gain=7;
  237.                        
  238.                                 }
  239.        
  240.                          }

  241.                   }                 
  242.         }
  243.         while(1);
  244. }


sdlls 发表于 2023-9-12 15:45 | 显示全部楼层
音乐频谱需要占用一定的存储空间              
youtome 发表于 2023-9-12 17:03 | 显示全部楼层
处理音乐频谱需要消耗一定的时间              
louliana 发表于 2023-9-12 19:50 | 显示全部楼层
实现对音频信号的处理和频谱图的绘制。程序设计需要考虑采样频率、信号处理算法、LED灯带的控制等。
tifmill 发表于 2023-9-12 21:14 | 显示全部楼层
单片机具有足够的处理能力和存储能力来播放音乐。如果单片机的性能较低,可能会导致音乐播放不流畅或者出现卡顿等问题。
kkzz 发表于 2023-9-12 22:33 | 显示全部楼层
根据音乐频谱的复杂度和精度要求,选择合适的单片机型号和规格。
abotomson 发表于 2023-9-13 09:18 | 显示全部楼层
可能需要进行数据平滑、归一化等处理,以便更好地呈现音频频谱。
pl202 发表于 2023-9-13 09:50 | 显示全部楼层
音乐频谱的实现需要设计合理的电路,包括音频信号的采集、信号处理和频谱图的显示电路等。
jtracy3 发表于 2023-9-13 13:53 | 显示全部楼层
单片机做的音乐频谱需要注意频率范围、采样频率、量化位数、存储空间、处理速度和输出方式等方面
yeates333 发表于 2023-9-13 16:12 | 显示全部楼层
需要确保单片机的时钟频率和音乐频率一致。
zerorobert 发表于 2023-9-13 20:15 | 显示全部楼层
需要通过ADC(模数转换器)将其转换为数字信号供单片机处理。选择适当的采样率和ADC分辨率可以确保准确捕捉音频信号的细节和频谱信息。
qiufengsd 发表于 2023-9-13 22:24 | 显示全部楼层
选择合适的采样频率,以获得更好的音质。
lzbf 发表于 2023-9-14 22:18 | 显示全部楼层
在音频信号的采集和处理过程中,可能会受到噪音的干扰
elsaflower 发表于 2023-9-17 12:09 | 显示全部楼层
需要根据处理速度的要求来选择合适的处理方法。
averyleigh 发表于 2023-9-17 13:08 | 显示全部楼层
在获取频谱数据后,需要进行适当的数据处理和显示
febgxu 发表于 2023-9-17 16:20 | 显示全部楼层
确定音乐频率范围,以避免处理过程中出现问题。
bartonalfred 发表于 2023-9-17 18:20 | 显示全部楼层
在单片机中实现FFT算法可能需要一定的计算资源和算法优化, 实时处理音频信号时具有足够的性能。
yorkbarney 发表于 2023-9-17 19:06 | 显示全部楼层
需要使用高质量的麦克风或音频输入接口作为音频信号的输入设备。
elsaflower 发表于 2023-9-17 19:15 | 显示全部楼层
为了减少噪音的影响,可以使用滤波器对音频信号进行滤波处理,以提高频谱的准确性和清晰度。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

43

主题

1559

帖子

2

粉丝
快速回复 在线客服 返回列表 返回顶部