很久没出新作品给大家了,其实不是不想出,而是开学这段时间太忙,从八月底到九月中旬,一直为新生忙碌着,自己的时间都很少。暑假闲在家里,也因为要体验“离开互联网的日子”而未曾碰触电脑(最近在整理假期离开网络生活的文字,希望大家可以了解另一个我)。所以也不曾出教学视频,觉得很对不住大家。
工作的时候,忙里偷闲,开通了新浪微博和新浪博客,感谢新浪推出的微号功能,让我的域名得以和QQ号码一样。以后工作室的动态会同步到新浪微博,作品和相关资料下载也会同步到新浪博客,希望大家多多关注!
频谱原理图:
新学期新气象,教学视频会保持更新,并加快进度,工作室也做好了新的工作计划,会有更优质的作品奉献给大家。
希望喜欢工作室作品的朋友将我们的作品和精神分享,我们坚持创新,坚持开源!
这次的小作品是频谱显示,8*16的led显示点阵配合stc12系列单片机系统,就可以自己制作廉价的频谱显示了!
原理图请登录百度网盘下载。关于原理图我想说的是,这是原理图,不是封装图,所以大多数IC是看不到Vcc或者Gnd的,但不代表没有,希望初学者留意。
这次的程序不是本人编写,是我师弟的设计,程序是有缺陷的,比如音效的延时,显示的效果等,有耐心的朋友可以自己修改程序,这次的作品在于分享数模转换程序和FFT算法,我也希望网友可以将完善的程序分享到网上,大家共同进步!!!
实物照片:
下面是我的焊接工程,不熟悉电路布局的童鞋可以做为参考
点阵正面
点阵背面
系统板正面

系统板背面
成品

在这里要说的是,焊接并不算复杂,无非就是点阵的焊接耗时耗力,要是有点焊接功夫,小半天也足够了,焊接的时候千万不要弄断管脚,弯折的管脚做跳线最好不过(图3)。系统板的布局我建议大家紧凑一些,我自己焊接的时候是考虑到这板子以后可能加个时间显示什么的,所以预留了一些空间,这样以后再做点阵显示的时候就方便多了
源程序:
- #include<stc12c5a.h>
- #include<intrins.h>
- //#include"basic.h"
- typedef unsigned char uint8;
- typedef unsigned int uint16;
- #define ADC_FLAG (1<<4) /*ADC_中断标志*/
- /*放大128倍后的sin整数表(128)*/
- code char SIN_TAB[128]={0,6,12,18,24,30,36,42,48,54,59,65,70,75,80,85,89,94,98,102,
- 105,108,112,114,117,119,121,123,124,125,126,126,126,126,126,
- 125,124,123,121,119,117,114,112,108,105,102,98,94,89,85,80,75,
- 70,65,59,54,48,42,36,30,24,18,12,6,0,-6,-12,-18,-24,-30,-36,-42,
- -48,-54,-59,-65,-70,-75,-80,-85,-89,-94,-98,-102,-105,-108,-112,
- -114,-117,-119,-121,-123,-124,-125,-126,-126,-126,-126,-126,-125,
- -124,-123,-121,-119,-117,-114,-112,-108,-105,-102,-98,-94,-89,-85,
- -80,-75,-70,-65,-59,-54,-48,-42,-36,-30,-24,-18,-12,-6
- };
- /*放大128倍后的cos整数表(128)*/
- code char COS_TAB[128]={127,126,126,125,124,123,121,119,117,114,112,108,105,102,98,94,
- 89,85,80,75,70,65,59,54,48,42,36,30,24,18,12,6,0,-6,-12,-18,-24,
- -30,-36,-42,-48,-54,-59,-65,-70,-75,-80,-85,-89,-94,-98,-102,
- -105,-108,-112,-114,-117,-119,-121,-123,-124,-125,-126,-126,-126,
- -126,-126,-125,-124,-123,-121,-119,-117,-114,-112,-108,-105,-102,
- -98,-94,-89,-85,-80,-75,-70,-65,-59,-54,-48,-42,-36,-30,-24,-18,
- -12,-6,0,6,12,18,24,30,36,42,48,54,59,65,70,75,80,85,89,94,98,102,
- 105,108,112,114,117,119,121,123,124,125,126,126
- };
- /*采样存储序列表*/
- code char LIST_TAB[128] = {0,64,32,96,16,80,48,112,8,72,40,104,24,88,56,120,4,68,36,100,20,84,52,116,
- 12,76,44,108,28,92,60,124,2,66,34,98,18,82,50,114,10,74,42,106,26,90,58,
- 122,6,70,38,102,22,86,54,118,14,78,46,110,30,94,62,126,1,65,33,97,17,81,49,
- 113,9,73,41,105,25,89,57,121,5,69,37,101,21,85,53,117,13,77,45,109,29,93,61,
- 125,3,67,35,99,19,83,51,115,11,75,43,107,27,91,59,123,7,71,39,103,23,87,55,
- 119,15,79,47,111,31,95,63,127
- };
- /*分级量化表*/
- uint8 QTY_TAB[] = {0x01,0x03,0x07,0x0f,0x1f,0x3f,0x7f,0xff};
- uint8 ADC_Count=0;
- uint8 i,j,k,b,p,anum;
- uint16 xdata Fft_Real[128];
- uint16 xdata Fft_Image[128]; // fft的虚部
- uint8 xdata LED_TAB[16]; //记录红色柱状
- /********************************************************************
- * 名称 : FFT
- * 功能 : 碟型运算转换
- * 输入 : 无
- * 输出 : 读出的值
- ***********************************************************************/
- void FFT()//基2fft
- {
- uint16 Temp_Real,Temp_Imag,temp; // 中间临时变量
- uint16 TEMP1 = 0,max=0;
- for( i=1; i<=7; i++) /* for(1) */
- {
- b=1;
- b <<=(i-1); //碟式运算,用于计算隔多少行计算例如 第一极 1和2行计算
- for( j=0; j<=b-1; j++) /* for (2) */
- {
- p=1;
- p <<= (7-i);
- p = p*j;
- for( k=j; k<128; k=k+2*b) /* for (3) */
- {
- Temp_Real=Fft_Real[k];
- Temp_Imag=Fft_Image[k];
- temp=Fft_Real[k+b];
- Fft_Real[k]=Fft_Real[k]+((Fft_Real[k+b]*COS_TAB[p])>>7)+((Fft_Image[k+b]*SIN_TAB[p])>>7);
- Fft_Image[k]=Fft_Image[k]-((Fft_Real[k+b]*SIN_TAB[p])>>7)+((Fft_Image[k+b]*COS_TAB[p])>>7);
- Fft_Real[k+b]=Temp_Real-((Fft_Real[k+b]*COS_TAB[p])>>7)-((Fft_Image[k+b]*SIN_TAB[p])>>7);
- Fft_Image[k+b]=Temp_Imag+((temp*SIN_TAB[p])>>7)-((Fft_Image[k+b]*COS_TAB[p])>>7); // 移位.防止溢出. 结果已经是本值的 1/64
- Fft_Real[k] >>= 1;
- Fft_Image[k] >>= 1;
- Fft_Real[k+b] >>= 1;
- Fft_Image[k+b] >>= 1;
- }
- }
- }
-
- for(j=0;j<16;j++)//16分频
- {
- TEMP1=((((Fft_Real[j+1]* Fft_Real[j+1]))+((Fft_Image[j+1]*Fft_Image[j+1])))>>1);//求各频段幅值
- if(TEMP1<1)TEMP1=0;
- LED_TAB[j]=TEMP1;
- if(LED_TAB[j]>max)max=LED_TAB[j];
- }
- if(max > 16)//分级量化
- {
- max/=16;
- for(j=0;j<16;j++)LED_TAB[j]/=max;
- }
- }
- /********************************************************************
- * 名称 : GPIO_init
- * 功能 : GPIO初始化
- * 输入 : 无
- * 输出 : 读出的值
- ***********************************************************************/
- void GPIO_init()
- {
- P0M0 = 1; P0M1 = 0; P0 = 0XFF; /*列*/
- P2M0 = 1; P2M1 = 0; P2 = 0XFF;
- P3M0 = 1; P3M1 = 0; P3 = 0XFF; /*行*/
- }
- /********************************************************************
- * 名称 : timer_Init
- * 功能 : 内部寄存器初始化
- * 输入 : 无
- * 输出 : 无
- ***********************************************************************/
- void timer_Init()
- {
- TMOD = 0X12;
- TH0 = 0xb0;
- TL0 = 0xb0;
- ET0 = 1; //定时器0 打开
- TR0 = 0; //关闭定时器
- TH1 = 0xfd;
- TL1 = 0Xa8;
- ET1 = 1;
- TR1 = 1;
- EA = 1;
- }
- /********************************************************************
- * 名称 : adc_Init
- * 功能 : 内部寄存器初始化
- * 输入 : 无
- * 输出 : 无
- ***********************************************************************/
- void adc_Init()
- {
- ADC_CONTR = 0x80; //ADC电源打开
- _nop_();_nop_();_nop_();_nop_();
- P1ASF = 0x01; //0000,0001, 将 P1.0 置成模拟口
- AUXR1 &=0xFB; //1111,1011, 令 ADRJ=0
- ADC_RES = 0x00; //清零寄存器
- ADC_RESL = 0x00;
- EADC = 1; //AD中断打开
- EA = 1; //总中断打开
- }
- /********************************************************************
- * 名称 : main
- * 功能 : 主程序
- * 输入 : 无
- * 输出 : 无
- ***********************************************************************/
- void main()
- {
- uint8 i = 0;
- GPIO_init();
- timer_Init();
- adc_Init();
- while(1)
- {
- ADC_Count = 0;
- EADC = 1;
- TR0 = 1;
- while(ADC_Count < 128); //满足128点
- for(i=0; i<128; i++) //清除虚部
- {
- Fft_Image[i] = 0;
- }
- FFT(); //FFT运算并转换为各频段幅值
- }
- }
- /********************************************************************
- * 名称 : ADC_Finish
- * 功能 : ADC转换完成中断服务
- * 输入 : 无
- * 输出 : 无
- ***********************************************************************/
- void ADC_Finish() interrupt 5
- {
- Fft_Real[LIST_TAB[ADC_Count]] = (int)(((ADC_RES)<<1)+(ADC_RESL>>1)*2)>>3; /*按LIST_TAB表顺序,进行存储采样值*/
- if(ADC_Count <= 127)
- {
- ADC_Count++; /*自动增量控制*/
- ADC_CONTR &= !ADC_FLAG;
- }
- else
- {
- EADC = 0;
- TR0 = 0;
- }
- }
- /********************************************************************
- * 名称 : interrupt_timer1
- * 功能 : 显示屏幕刷新中断服务
- * 输入 : 无
- * 输出 : 无
- ***********************************************************************/
- void interrupt_timer1() interrupt 3
- {
- static uint8 rec = 0;
- TH1 = 0xfd;
- TL1 = 0Xa8;
- switch(rec) //往点阵屏填充一列的数据
- {
- case 0: P0 = QTY_TAB[LED_TAB[0]]; P2 = 0;break;
- case 1: P0 = QTY_TAB[LED_TAB[1]]; P2 = 1;break;
- case 2: P0 = QTY_TAB[LED_TAB[2]]; P2 = 2;break;
- case 3: P0 = QTY_TAB[LED_TAB[3]]; P2 = 3;break;
- case 4: P0 = QTY_TAB[LED_TAB[4]]; P2 = 4;break;
- case 5: P0 = QTY_TAB[LED_TAB[5]]; P2 = 5;break;
- case 6: P0 = QTY_TAB[LED_TAB[6]]; P2 = 6;break;
- case 7: P0 = QTY_TAB[LED_TAB[7]]; P2 = 7;break;
- case 8: P0 = QTY_TAB[LED_TAB[8]]; P2 = 8;break;
- case 9: P0 = QTY_TAB[LED_TAB[9]]; P2 = 9;break;
- case 10: P0 = QTY_TAB[LED_TAB[10]]; P2 = 10;break;
- case 11: P0 = QTY_TAB[LED_TAB[11]]; P2 = 11;break;
- case 12: P0 = QTY_TAB[LED_TAB[12]]; P2 = 12;break;
- case 13: P0 = QTY_TAB[LED_TAB[13]]; P2 = 13;break;
- case 14: P0 = QTY_TAB[LED_TAB[14]]; P2 = 14;break;
- case 15: P0 = QTY_TAB[LED_TAB[15]]; P2 = 15;break;
- default:break;
- }
- rec++;
- if(rec > 15)
- {
- rec = 0;
- }
- }
- /********************************************************************
- * 名称 : Ad_Control
- * 功能 : 控制采样率
- * 输入 : 无
- * 输出 : 无
- ***********************************************************************/
- void Ad_Control() interrupt 1
- {
- ADC_CONTR = 0xe8; //开始AD采集
- _nop_();_nop_();_nop_();_nop_();
- }
复制代码
|