标题:
单片机音乐闪灯(类似于音乐频谱)制作问题
[打印本页]
作者:
c20160526
时间:
2017-11-9 08:05
标题:
单片机音乐闪灯(类似于音乐频谱)制作问题
我想用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;
}
复制代码
欢迎光临 (http://www.51hei.com/bbs/)
Powered by Discuz! X3.1