转载请注明出处: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]<tmp) { refreshflag[pt] = tmp; } else { 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]<tmp) //首先叫他变成第一种。然后叫最上面那个灯进行下降效果。和音乐播放器的效果非常像。 { refreshflag[pt] = tmp; } else { if(refreshflag[pt]>1) { refreshflag[pt]--; } tmp = refreshflag[pt]; } LEDBuf[pt]|=(0x0001<<(tmp-1)); } } }
每次按键改遍num的值,每一个值相应一种显示效果四种效果凝视相当easy理解,我就只是多介绍了。对比着实际效果看代码会更easy理解。效果视频和完整的代码下载在概述里面。
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输出声音
依照下图进行连接,输入的音频信号
官方的图片照这连就OK了,喇叭选择的是8Ω,0.5W的。
效果一般。但还过得去。
參考: STC官方手冊
百度百科