LED音乐频谱之输出数据处理

转载请注明出处:http://blog.csdn.net/ruoyunliufeng/article/details/38023539

一.PWM调节

     1.初始化

void  DACInit()
{
	CCON=0;	            //PAC初始化
	CL=0;				// PAC16位计数器低8位
	CH=0;				// PAC16位计数器高8位
	CMOD=0x00;			 //选择  系统时钟/12为计数脉冲,则PWM的频率f=sysclk/256/12
	CCAP0H=0X80;		 //占空比控制,0x80为百分之50	10000000所以在与PAC低八位比较时有CL>CCAPnL 一半的情况所以占空比为百分之50
        PCA_PWM0=0x00;         //使EPC0H   EPC0L为0,具体定义可看头文件
	CCAPM0=0X42;		 //允许P13作为PWM输出
	CR=1;				  //启动PCA计数器
}


     2.按键调光

		if(key1==0)				//独立按键	 ,PWM调节
			{
					delayms(35);
			        if(key1==0)
					  {		
					  		a++;
							CCAP0H=pwm[a];		//占空比调节
			                CCAP0L=pwm[a];
							while(!key1);
							if(a==4)
							{
								a=0;
							} 
		
					  }
			 }


           各个模块的输出占空比是独立变化的,与使用的捕获寄存器[EPCnL,CCAPnL]有关。当寄存器CL的值小于[EPCnL,CCAPnL]时,输出为低;当寄存器CL的值等于或大于[EPCnL,CCAPnL]时,输出为高。当CL的值由FF变为00溢出时,[EPCnH,CCAPnH]的内容装载到[EPCnL,CCAPnL]中。这样就可实现无干扰地更新PWM。要使能PWM模式,模块CCAPMn寄存器的PWMn和ECOMn位必须置位。

sfr  CCAPM0          //PCA模块0模式寄存器    Bit7    Bit6          Bit5        Bit4       Bit3          Bit2           Bit1    Bit0
                                //位描述                                -       ECOM0   CAPP0   CAPN0   MAT0    TOG0    PWM0    ECCF0
                                //初始值=x000,0000      x       0       0       0       0       0       0       0


二.位运算


if(ACT_Key == 0)												// 动作检测,切换效果
	{
		num++;
		if(num>4)
		{
			num = 1;
		}
		delay500ms();
	}


 switch(num)
	{								  // 选择显示模式
		case	1:	{	
						for(pt=0;pt<15;pt++)	 					   // 	style 1
					    {       									    // 第一个点是直流分量所以不能用。style 1	第一种是直接显示的,适合节奏比较强的音乐
							LEDBuf[pt]=0xffff;
							tmp = dd[pt+2].real;					//2 6 8 10....32由于计算的是64个点	0到N是计算0到2PI。所以只需要看计算0到二分之N所以是0到32有因为一共是16列所以偶数 
							tmp = (tmp/8)+1;							//将变换后的功率转换为LED灯的幅值。看里面有多少个16假如为32的话就是0xff做移2位变成11111100然后取反就为00000011(还进行了加一处理此处为算加一的目的是让第一行时钟亮)一次进行16次变成新的LED数组
							LEDBuf[pt]<<=tmp;	
							LEDBuf[pt]=~(LEDBuf[pt]); 
						}
						
						break;
					}
		case	2:	{
						for(pt=0;pt<15;pt++)	 					   //	style 2
					    {       
							if(refreshflag[pt]<(dd[pt].real/8)+1)		// 第二种是带下落效果的,跟第一种差不太多。           
							{	
															 //加入了 refreshflag[pt]来进行下降  
								LEDBuf[pt]=0xffff;
								tmp = dd[pt+2].real;
								tmp = (tmp/8)+1;
								refreshflag[pt] = tmp;		 
								tmp = refreshflag[pt];
								LEDBuf[pt]<<=tmp;	
								LEDBuf[pt]=~(LEDBuf[pt]);
							}
							else
							{
							 	if(refreshflag[pt]>1)
								{
									
									refreshflag[pt]--;                         
								}
								LEDBuf[pt]=0xffff;
								tmp = refreshflag[pt];
								LEDBuf[pt]<<=tmp;
								
								LEDBuf[pt]=~(LEDBuf[pt]);
			                //	delayms(25);
							}
							
						}
						break;
					}
		case	3:	{														//	style 3
						for(pt=0;pt<15;pt++)	 							//第三种就是在第二种的效果上取最高的点
					    {    
							LEDBuf[pt]=0xffff; 
							tmp = dd[pt+2].real;
							tmp = (tmp/8)+1;
							if(refreshflag[pt]1)
								{
									refreshflag[pt]--;                         
								}
								tmp = refreshflag[pt];			
							}
							LEDBuf[pt]&=(0x0001<<(tmp-1));				   //与第二种区别就是取最高点例如0xff和一个00010000想与	00010000所以只有一个灯亮
						}
						break;
					}

		case	4:	{										   			//		style	4 	  最后一种是第一种和第三种的结合体吧
						for(pt=0;pt<15;pt++)	 
					    {    
							LEDBuf[pt]=0xffff; 
							tmp = dd[pt+2].real;
							tmp = (tmp/8)+1;
							LEDBuf[pt]<<=tmp;	
							LEDBuf[pt]=~(LEDBuf[pt]);
							if(refreshflag[pt]1)
								{
									refreshflag[pt]--;                         
								}
								tmp = refreshflag[pt];			
							}
							LEDBuf[pt]|=(0x0001<<(tmp-1));	
						}
					}
	}



        每次按键改遍num的值,每个值对应一种显示效果四种效果注释相当容易理解,我就不过多介绍了。对照着实际效果看代码会更容易理解,效果视频和完整的代码下载在概述里面。

         1.幅值量化

               代码之中有这样一句tmp = (tmp/8)+1有小伙伴可能没看懂,下面我解释下

                   a.tmp是什么?

                   答:tmp是你要亮灯的个数。

                   b.为什么是8而不是其余的数?

                   答:调试的结果,要综合点阵的行数,声音的大小考虑。如果你换成16,那么你要提高你的输入音量。再说的简单点,这个8乘以行数要小于频谱的最大值(或者基本不超过)。所以说即使是现在,我调高输入源的音量或者降低输入源的音量,频谱也会发生变化。8是一个我兼顾了输出声音的大小(因为这个设计中是可以输出声音的),调试出来的一个值。

                   c.还是不明白为什么要这么写?

                   答:我们要LED量化频谱,你的行数相当于分辨率,最终人眼要看到是是几行,假如你是10行那么你最移的位数是定死的,超过10显示的是全亮(没考虑+1,第一行必须亮的情况,为了美观),那么你必须要控制你这个频谱能够大致显示到屏幕中,所以正常的tmp必须要除一个数来压缩它的频谱。下面我画一张图:

如果不处理直接左移则会出现全屏皆亮的情况,处理之后,则可避免。

三.点阵输出图像

	 for(i=0;i<16;i++)
		{																// 显示
			//LineInput(0x00);
			P2 = ColScan_2[i];
			LineInput(LEDBuf[i]);
			LineInput(0x0000);	  
	
		}

void LineInput(uint dat)                   // 单列数据显示
{
    uchar n;
    _RCLK = 0;
    for(n=0;n<16;n++)
    {
        _SRCLK = 0;
        _SER  = (dat>>n)&0x01;         //将数据的值串入输入SER中,然后并行输出
        _SRCLK = 1;
    }
    _RCLK = 1;
}


四.TDA2822输出声音

     按照下图进行连接,输入的音频信号

LED音乐频谱之输出数据处理_第1张图片



官方的图片照这连就OK了,喇叭选择的是8Ω,0.5W的。效果一般,但还过得去。


参考: STC官方手册

               百度百科

你可能感兴趣的:(单片机,PWM,位运算,单片机,LED,频谱)