打印
[应用方案]

单片机做的音乐频谱

[复制链接]
995|18
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
saservice|  楼主 | 2023-8-27 19:00 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
         

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

#include "src\Define.h"


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


void Delays(uint t)
{  
        uint j;
        while(--t)
                for(j=0;j<5;j++);   
}
void Delaysms(uint t)
{  
        uint j;
        while(--t)
                for(j=0;j<15;j++);   
}



#include "src\ADC.c"
#include "src\Font.c"
#include "src\fft.h"



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

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

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


void IOINIT(void)                                                          //I/O强上拉模式;
{
        P4SW = 0xff;                                  //启动I/O:P4;
        P4M1 = B(00000000); P4M0 = B(10000000);P47=0;//震动马达;
        P0M1 = 0x00;            P0M0 = 0xff;       P0=0; //点阵列(Y)(L:OFF; H,H+:ON,ON+;)
        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;      
        P2M1 = B(00000000); P2M0 = B(11111111);P2=0; //点阵行(X0(Left))(L:OFF; H,H+:ON,ON+;)  
        P3M1 = B(00000000);        P3M0 = B(11111111);P3=0; //点阵行(X1(Right))(L:OFF; H,H+:ON,ON+;)               
        P1ASF =B(00000011);                          //将P10,P11的IO设置为模拟输入功能;     

//  Y(P0)
//  ↑
//H        |
//         |
//        |
//L        |
//         ---------------------→
//        [L:X0(P2):H][L:X1(P3):H]

//TestCode:
//        P0=B(10000000);
//        P2=B(00000001);
//        P3=B(00010000);

}



void BufToLED_Refresh()                     //Refresh&Write Buf to LED ;
{       
         uchar data i;
         uchar data X=1;          
         uchar data Y=1;
         for(X=1,i=2;X;X<<=1,i+=2)              //for(X=1;X!=0;X<<=1) //8bit
         {
                  P2=X;
                for(Y=1;Y!=0;Y<<=1)                            //Y=Y<<1;
                 {
                        P0=Y&LEDBuf[i];
                        Delays(DelayTime);
                        P0=0;
                }
                P2=0;       
         };
         for(X=1;X<B(10000000);X<<=1,i+=2)            //7bit
         {
                  P3=X;
                for(Y=1;Y!=0;Y<<=1)                            //Y=Y<<1;
                 {
                        P0=Y&LEDBuf[i];
                        Delays(DelayTime);
                        P0=0;
                }
                P3=0;       
         };
               
}




void LEDRefresh_INT() interrupt 3 //using 3   
{
        static uint x=0;                  
        static uchar flag=1;

    TL1 = 0x00;      
    TH1 = INTTime;               //0x50~0x80

        if(flag)
        {
                if(++x==0xFF)                         //MINOUTPUT
                {
                        flag=0;               
                }               
        }
        else
        {
                if(--x==0xCF)                 //MAXOUTPUT
                {
                        flag=1;                       
                }
        }                        
        PWM0_set(x);                 //设置PWM占空比

        BufToLED_Refresh();                        
}  


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

}


void FullScan()
{
        uchar data X=1;          
        uchar data Y=1;

         for(Y=1;Y!=0;Y<<=1)                       //Y=Y<<1;
         {       
                 P0=Y;
                for(X=1;X;X<<=1)                   //8bit
                {
                         P2=X;
                        Delays(7);       
                };

                P2=0;
                for(X=1;X<B(10000000);X<<=1)    //7bit
                {
                         P3=X;
                        Delays(7);
                };
                P3=0;
                P0=0;
         }
}


void Main()
{  
        uint data Count=700;
        uchar data i,Cgain,num=0;

        IOINIT();
        InitADC();                  

        while(--Count)
                FullScan();

        for(i=0;i<40;i++) refreshflag[i]=0x09;
       
        P14=0;                          //Beep
        Delays(4000);
        P14=1;

        PWM_init();      //PWM初始化
        PWM0_set(0xFB);
       
        Timer_INT();

        for(i=0;i<34;i++)
                LEDBuf[i]=0x00;
        FontDisp();

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

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

                 ///////////////////TouchKey//////////////////////////
                 while(P16==1)                                           //依据:脉冲 干扰持续时间短;
                 {       
                        if(CBeep)P14=0;
                        if(++TouchKey>0x0000FF00)break;       
                 }
                 P14=1;

                 if(P16==1)
                 {
                        if(++Menu==4)Menu=0;

                        P14=0;
                        P47=1;
                        Delays(7000);          
                        P14=1;
                        P47=0;               
                 }       
                        TouchKey=0;
                 //////////////////////////////////////////////

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

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

                                P14=0;                          //Beep
                                Delays(1000);
                                P14=1;
                         }
                 }
                 else
                 {
                         Count=1;
       
                         if(++num==0xAF)                         //播放时,Auto gain;
                         {
                                num=0;

                                P14=0;                                   //Beep
                                Delays(700);
                                P14=1;
                                                           //自动增益;Automatic gain;
                                Cgain=dd[2].real/32;
                                if(7<Cgain<=8)
                                {
                                        gain=4;
                                       
                                }
                                else if(4<Cgain<=6)
                                {
                                        gain=5;
                                       
                                }
                                else if(2<Cgain<=4)
                                {
                                        gain=6;
                                }
                                else
                                {
                                        gain=7;
                       
                                }
       
                         }

                  }                 
        }
        while(1);
}


使用特权

评论回复
沙发
sdlls| | 2023-9-12 15:45 | 只看该作者
音乐频谱需要占用一定的存储空间              

使用特权

评论回复
板凳
youtome| | 2023-9-12 17:03 | 只看该作者
处理音乐频谱需要消耗一定的时间              

使用特权

评论回复
地板
louliana| | 2023-9-12 19:50 | 只看该作者
实现对音频信号的处理和频谱图的绘制。程序设计需要考虑采样频率、信号处理算法、LED灯带的控制等。

使用特权

评论回复
5
tifmill| | 2023-9-12 21:14 | 只看该作者
单片机具有足够的处理能力和存储能力来播放音乐。如果单片机的性能较低,可能会导致音乐播放不流畅或者出现卡顿等问题。

使用特权

评论回复
6
kkzz| | 2023-9-12 22:33 | 只看该作者
根据音乐频谱的复杂度和精度要求,选择合适的单片机型号和规格。

使用特权

评论回复
7
abotomson| | 2023-9-13 09:18 | 只看该作者
可能需要进行数据平滑、归一化等处理,以便更好地呈现音频频谱。

使用特权

评论回复
8
pl202| | 2023-9-13 09:50 | 只看该作者
音乐频谱的实现需要设计合理的电路,包括音频信号的采集、信号处理和频谱图的显示电路等。

使用特权

评论回复
9
jtracy3| | 2023-9-13 13:53 | 只看该作者
单片机做的音乐频谱需要注意频率范围、采样频率、量化位数、存储空间、处理速度和输出方式等方面

使用特权

评论回复
10
yeates333| | 2023-9-13 16:12 | 只看该作者
需要确保单片机的时钟频率和音乐频率一致。

使用特权

评论回复
11
zerorobert| | 2023-9-13 20:15 | 只看该作者
需要通过ADC(模数转换器)将其转换为数字信号供单片机处理。选择适当的采样率和ADC分辨率可以确保准确捕捉音频信号的细节和频谱信息。

使用特权

评论回复
12
qiufengsd| | 2023-9-13 22:24 | 只看该作者
选择合适的采样频率,以获得更好的音质。

使用特权

评论回复
13
lzbf| | 2023-9-14 22:18 | 只看该作者
在音频信号的采集和处理过程中,可能会受到噪音的干扰

使用特权

评论回复
14
elsaflower| | 2023-9-17 12:09 | 只看该作者
需要根据处理速度的要求来选择合适的处理方法。

使用特权

评论回复
15
averyleigh| | 2023-9-17 13:08 | 只看该作者
在获取频谱数据后,需要进行适当的数据处理和显示

使用特权

评论回复
16
febgxu| | 2023-9-17 16:20 | 只看该作者
确定音乐频率范围,以避免处理过程中出现问题。

使用特权

评论回复
17
bartonalfred| | 2023-9-17 18:20 | 只看该作者
在单片机中实现FFT算法可能需要一定的计算资源和算法优化, 实时处理音频信号时具有足够的性能。

使用特权

评论回复
18
yorkbarney| | 2023-9-17 19:06 | 只看该作者
需要使用高质量的麦克风或音频输入接口作为音频信号的输入设备。

使用特权

评论回复
19
elsaflower| | 2023-9-17 19:15 | 只看该作者
为了减少噪音的影响,可以使用滤波器对音频信号进行滤波处理,以提高频谱的准确性和清晰度。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

43

主题

1303

帖子

2

粉丝