我想用51单片机做一个类似于音乐频谱,
音乐频谱有些是8*8,12*12规格的,达到要求点亮每一级上面的LED,但点亮后的LED就只是点亮,而不是随音乐闪动,
我是想达到要求点亮每一级上面的LED,并且LED随音乐闪动,效果应该和舞厅效果差不多吧,
下面是论坛上面的源代码,哪位可以帮我改改不?谢谢
- #include<reg52.h> //stc15系列1T单片机
- #define ADC_CHANNEL 0x01 //AD转换通道P1.0
- #define ADC_POWER 0x80 //ADC电源控制位
- #define ADC_SPEED 0x60 //90个时钟周期
- #define ADC_START 0x08 //ADC启动控制位
- #define ADC_FLAG 0x10 //ADC完成标志位
- #define SAMPLE_NUM 64 //取64点FFT算法
- #define NUM_2_LOG 6 //2的6次方
- #define FFT_OUT_MIN 1 //FFT运算最小值
- #define LED_C1_8 P2 //LED1~8列
- #define LED_C9_16 P3 //LED9~16列
- #define LED_R1_8 P0 //LED1~8行
- /***************************引脚定义*****************************/
- sbit LED_R1 = P0^0; //LED1~8行
- sbit LED_R2 = P0^1;
- sbit LED_R3 = P0^2;
- sbit LED_R4 = P0^3;
- sbit LED_R5 = P0^4;
- sbit LED_R6 = P0^5;
- sbit LED_R7 = P0^6;
- sbit LED_R8 = P0^7;
- sbit LED_R9 = P1^6; //LED第9行
- sbit LED_R10 = P1^7; //LED第10行
- sbit SWITCH = P2^5;
- /*----------------------------变量表----------------------------*/
- unsigned char code BIT_RESORT[SAMPLE_NUM] = { 0, 32, 16, 48, 8, 40, 24, 56,4, 36, 20, 52, 12, 44, 28, 60, //比特逆序重排
- 2, 34, 18, 50, 10, 42, 26, 58, 6, 38, 22, 54, 14, 46, 30, 62,
- 1, 33, 17, 49, 9, 41, 25, 57,5, 37, 21, 53, 13, 45, 29, 61,
- 3, 35, 19, 51, 11, 43, 27, 59,7, 39, 23, 55, 15, 47, 31, 63};
- char code SIN_TAB[SAMPLE_NUM] = { 0 ,12 ,25 ,37 ,49 ,60 ,71 ,81 ,90 ,98 ,106 ,112 ,117 ,122 ,125 ,126 , //正弦表
- 127 ,126 ,125 ,122 ,117 ,112 ,106 ,98 ,90 ,81 ,71 ,60 ,49 ,37 ,25 ,12 ,
- 0 ,-12 ,-25 ,-37 ,-49 ,-60 ,-71 ,-81 ,-90 ,-98 ,-106 ,-112 ,-117 ,-122 ,-125 ,-126 ,
- -127 ,-126 ,-125 ,-122 ,-117 ,-112 ,-106 ,-98 ,-90 ,-81 ,-71 ,-60 ,-49 ,-37 ,-25 ,-12 };
- char code COS_TAB[SAMPLE_NUM] = {127 ,126 ,125 ,122 ,117 ,112 ,106 ,98 ,90 ,81 ,71 ,60 ,49 ,37 ,25 ,12 , //余弦表
- 0 ,-12 ,-25 ,-37 ,-49 ,-60 ,-71 ,-81 ,-90 ,-98 ,-106 ,-112 ,-117 ,-122 ,-125 ,-126 ,
- -127 ,-126 ,-125 ,-122 ,-117 ,-112 ,-106 ,-98 ,-90 ,-81 ,-71 ,-60 ,-49 ,-37 ,-25 ,-12 ,
- 0 ,12 ,25 ,37 ,49 ,60 ,71 ,81 ,90 ,98 ,106 ,112 ,117 ,122 ,125 ,126 };
- unsigned char LED_NUM[] = {0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff}; //led显示数目
- unsigned char AMP, AMP_TAB[16]; //频谱幅值,幅值表
- unsigned char DISP_NUM; //显示次数
- unsigned char KEEP, KEEP_NUM; //自动增益选择
- int xdata FFT_REAL[SAMPLE_NUM]; //FFT运算结果实部
- int xdata FFT_IMAGE[SAMPLE_NUM]; //FFT运算结果虚部
- bit SWITCH_ON;
- /**************************************************************
- *名 称:delay
- *功 能:微秒级延时
- **************************************************************/
- void Delay(unsigned int i)
- {
- while(i--);
- }
- /**************************************************************
- *名 称:Delay_ms
- *功 能:毫秒级延时
- **************************************************************/
- void Delay_ms(unsigned int x)
- {
- unsigned int i, j;
- for(i = 0; i < x; i++)
- for(j = 0; j < 500; j++);
- }
- /**************************************************************
- *名 称:IOInit
- *功 能:IO端口初始化
- **************************************************************/
- void IOInit(void)
- {
- P1M0 = 0x00; //高阻输入
- P1M1 = 0x01;
- P1ASF = 0x01; //设为AD转换
- }
- /**************************************************************
- *名 称:Timer0Init
- *功 能:定时器0初始化100us定时
- **************************************************************/
- void TimerInit(void) //100微秒@33.000MHz
- {
- AUXR = 0XC0; //定时器0-1T,定时器1-12T
- TMOD = 0X00; //定时器0/1-方式0-16位自动重装
- TL0 = 0X16; //定时器0-定时170us-显示幅值
- TH0 = 0Xea;
- TL1 = 0X1C; //定时器1-定时1ms-检测开关状态
- TH1 = 0XF3;
- TR0=1;
- TR1 = 1;
- }
- /**********************************************************
- *名 称:Display
- *功 能:显示幅值
- **********************************************************/
- void Display(void)
- {
- DISP_NUM++;
- if(DISP_NUM == 17)
- DISP_NUM = 1;
- LED_R1_8 = 0X00; LED_R9 = 0; LED_R10 = 0; LED_R11 = 0; LED_R12 = 0; //显示前先关闭
- switch(DISP_NUM) //逐列显示
- {
- case 1: AMP = AMP_TAB[0]; LED_C1_8 = 0X01; LED_C9_16 = 0x00; break;
- case 2: AMP = AMP_TAB[1]; LED_C1_8 = 0X02; LED_C9_16 = 0x00; break;
- case 3: AMP = AMP_TAB[2]; LED_C1_8 = 0X04; LED_C9_16 = 0x00; break;
- case 4: AMP = AMP_TAB[3]; LED_C1_8 = 0X08; LED_C9_16 = 0x00; break;
- case 5: AMP = AMP_TAB[4]; LED_C1_8 = 0X10; LED_C9_16 = 0x00; break;
- case 6: AMP = AMP_TAB[5]; LED_C1_8 = 0X20; LED_C9_16 = 0x00; break;
- case 7: AMP = AMP_TAB[6]; LED_C1_8 = 0X40; LED_C9_16 = 0x00; break;
- case 8: AMP = AMP_TAB[7]; LED_C1_8 = 0X80; LED_C9_16 = 0x00; break;
- case 9: AMP = AMP_TAB[8]; LED_C1_8 = 0X00; LED_C9_16 = 0x01; break;
- case 10: AMP = AMP_TAB[9]; LED_C1_8 = 0X00; LED_C9_16 = 0x02; break;
- case 11: AMP = AMP_TAB[10]; LED_C1_8 = 0X00; LED_C9_16 = 0x04; break;
- case 12: AMP = AMP_TAB[11]; LED_C1_8 = 0X00; LED_C9_16 = 0x08; break;
- case 13: AMP = AMP_TAB[12]; LED_C1_8 = 0X00; LED_C9_16 = 0x10; break;
- case 14: AMP = AMP_TAB[13]; LED_C1_8 = 0X00; LED_C9_16 = 0x20; break;
- case 15: AMP = AMP_TAB[14]; LED_C1_8 = 0X00; LED_C9_16 = 0x40; break;
- case 16: AMP = AMP_TAB[15]; LED_C1_8 = 0X00; LED_C9_16 = 0x80; break;
- }
- if(AMP <= 8)
- {
- LED_R1_8 = LED_NUM[AMP];
- LED_R9 = 0;
- LED_R10 = 0;
- LED_R11 = 0;
- LED_R12 = 0;
- }
- if(AMP == 9)
- {
- LED_R1_8 = 0XFF;
- LED_R9 = 1;
- LED_R10 = 0;
- LED_R11 = 0;
- LED_R12 = 0;
- }
- if(AMP == 10)
- {
- LED_R1_8 = 0XFF;
- LED_R9 = 1;
- LED_R10 = 1;
- LED_R11 = 0;
- LED_R12 = 0;
- }
- if(AMP == 11)
- {
- LED_R1_8 = 0XFF;
- LED_R9 = 1;
- LED_R10 = 1;
- LED_R11 = 1;
- LED_R12 = 0;
- }
- if(AMP == 12)
- {
- LED_R1_8 = 0XFF;
- LED_R9 = 1;
- LED_R10 = 1;
- LED_R11 = 1;
- LED_R12 = 1;
- }
- }
- /************************************************
- *名 称:ReadADC
- *功 能:读取AD转换结果
- ************************************************/
- unsigned char ReadADC(void)
- {
- ADC_CONTR = ADC_POWER + ADC_START; //启动转换
- Delay(50);
- while(!(ADC_CONTR & ADC_FLAG)); //等待转换结束
- ADC_CONTR = ADC_POWER;
- return (ADC_RES << 2 + ADC_RESL);
- }
- /************************************************
- *名 称:sqrt
- *功 能:算平方根
- ************************************************/
- short sqrt( unsigned long M) //不懂啊
- {
- unsigned int N, i;
- unsigned long tmp, ttp;
- if( M == 0 )
- return 0;
- N = 0;
- tmp = ( M >> 30 );
- M <<= 2;
- if( tmp > 1 )
- {
- N ++;
- tmp -= N;
- }
- for( i=15; i>0; i-- )
- {
- N <<= 1;
- tmp <<= 2;
- tmp += (M >> 30);
- ttp = N;
- ttp = (ttp<<1)+1;
- M <<= 2;
- if( tmp >= ttp )
- {
- tmp -= ttp;
- N ++;
- }
- }
- return N;
- }
- /************************************************
- *名 称:FFT
- *功 能:快速傅里叶变换求取频谱
- ************************************************/
- void FFT(void) //基2时分蝶式算法
- {
- // unsigned char i, j, r, m1, m2, m3, m4, k1, k2; //分别为:级号,蝶群号,运算蝶号,蝶群总数,蝶群长度,运算蝶数,蝶群址,蝶址
- // unsigned char p;
- // unsigned char MAX = 0;
- // short u, v;
- // unsigned long ulReal, ulImage;
- register unsigned char i,bb,j,k,p,MAX;
- register short TR,TI,temp;
- unsigned long ulReal;
- unsigned long ulImage;
- for(i = 0; i < SAMPLE_NUM; i++) //采样
- {
- FFT_REAL[BIT_RESORT[i]] = ReadADC() << KEEP;
- FFT_IMAGE[i] = 0;
- }
- KEEP_NUM = FFT_REAL[2] >> 4;
- if((7 < KEEP_NUM) && (KEEP_NUM <= 8))
- KEEP = 1;
- else if((4 < KEEP_NUM) && (KEEP_NUM <= 6))
- KEEP = 2;
- else if((2 < KEEP_NUM) && (KEEP_NUM <= 4))
- KEEP = 3;
- else
- KEEP = 5;
- for( i=1; i<=NUM_2_LOG; i++)
- {
- bb=1;
- bb <<= (i-1);
- for( j=0; j<=bb-1; j++)
- {
- p=1;
- p <<= (NUM_2_LOG-i);
- p = p*j;
- for( k=j; k<SAMPLE_NUM; k=k+2*bb)
- {
- TR = FFT_REAL[k]; TI = FFT_IMAGE[k]; temp = FFT_REAL[k+bb];
- FFT_REAL[k] = FFT_REAL[k] + ((FFT_REAL[k+bb]*COS_TAB[p])>>7) + ((FFT_IMAGE[k+bb]*SIN_TAB[p])>>7);
- FFT_IMAGE[k] = FFT_IMAGE[k] - ((FFT_REAL[k+bb]*SIN_TAB[p])>>7) + ((FFT_IMAGE[k+bb]*COS_TAB[p])>>7);
- FFT_REAL[k+bb] = TR - ((FFT_REAL[k+bb]*COS_TAB[p])>>7) - ((FFT_IMAGE[k+bb]*SIN_TAB[p])>>7);
- FFT_IMAGE[k+bb] = TI + ((temp*SIN_TAB[p])>>7) - ((FFT_IMAGE[k+bb]*COS_TAB[p])>>7);
- FFT_REAL[k] >>= 1;
- FFT_IMAGE[k] >>= 1;
- FFT_REAL[k+bb] >>= 1;
- FFT_IMAGE[k+bb] >>= 1;
- }
- }
- }
- for(i = 0; i < 16; i++)
- {
- ulReal = FFT_REAL[i + 1];
- ulReal *= ulReal;
- ulImage = FFT_IMAGE[i + 1];
- ulImage *= ulImage;
- AMP_TAB[i] = sqrt(ulImage + ulReal);
- if(AMP_TAB[i] < FFT_OUT_MIN)
- AMP_TAB[i] = 0;
- else
- AMP_TAB[i] -= FFT_OUT_MIN;
- if(AMP_TAB[i] > MAX)
- MAX = AMP_TAB[i];
- }
- if(MAX > 12)
- {
- MAX /= 12;
- for(i = 0; i < 16; i++)
- AMP_TAB[i] /= MAX;
- }
- }
- /************************************************
- *名 称:main
- *功 能:主函数
- ************************************************/
- void main()
- {
- IOInit(); //初始化
- TimerInit();
- DISP_NUM = 0;
- KEEP = 0;
- KEEP_NUM = 0;
- EA = 1; //开中断
- ET1 = 1;
- while(1)
- {
- if(SWITCH_ON == 0)
- {
- ET0 = 0;
- }
- if(SWITCH_ON == 1)
- {
- ET0 = 1;
- FFT();
- }
- }
- }
- /************************************************
- *名 称:Timer0Interrupt
- *功 能:定时器0中断服务程序-显示
- ************************************************/
- void Timer0Interrupt() interrupt 1
- {
- Display();
- Delay(300);
- }
- /************************************************
- *名 称:Timer1Interrupt
- *功 能:定时器1中断服务程序-检测开关状态
- ************************************************/
- void Timer1Interrupt() interrupt 3
- {
- if(SWITCH == 1)
- SWITCH_ON = 1;
- if(SWITCH == 0)
- SWITCH_ON = 0;
- }
复制代码 |