高级流水灯水滴效果.docx
- 文档编号:12635018
- 上传时间:2023-04-21
- 格式:DOCX
- 页数:19
- 大小:267.64KB
高级流水灯水滴效果.docx
《高级流水灯水滴效果.docx》由会员分享,可在线阅读,更多相关《高级流水灯水滴效果.docx(19页珍藏版)》请在冰豆网上搜索。
高级流水灯水滴效果
简介
学习嵌入式第一个例子通常都是控制一个LED亮灭,然后是花样繁多的流水灯,但不管灯的花样如何变化,单个LED的亮度没有变化,只有亮、灭两个状态,本章我们实现如何控制LED的亮度。
1什么是PWM
脉冲宽度调制(PulseWidthModulation,简称PWM),是利用微处理器的数字输出来对模拟电路进行控制的一种技术。
在本章的应用中可以认为PWM就是一种方波。
比如图1:
(原文件名:
120611_0.png)图1方波
是周期为10ms,占空比为60%的PWM。
占空比:
高电平在一个周期之内所占的时间比率。
2硬件设计
在例说51单片机的第三章,我们讲过如何控制开发板上LED的亮灭。
首先译码器输出端LEDS6为低,T10导通,给8个LED供电,然后通过缓冲器8个输出端BD0~BD7的控制LED的亮灭(低亮高灭)。
(原文件名:
120611_1.png)图2LED硬件连接
如果BD口输出高低不断变化,则LED会闪烁;如果这种高低电平变化非常快,由于人的视觉暂留现象,LED就会出现不同的亮度。
3软件设计
3.1PWM能否控制亮度
下面我们就用实践验证PWM是否能够控制LED的亮度,测试代码如下:
程序清单L1:
验证PWM能否控制LED的亮度
#include
#include"my_type.h"
#include"hw_config.h"
voidmain(void)
{
u8i=0;//使能独立LED的供电,即LEDS6输出低电平
LEDEN=0;
ADDR0=0;
ADDR1=1;
ADDR2=1;
ADDR3=1;//第一个LED亮
P0=0xFE;
while
(1)
{
for(i=0;i<250;i++)
{
if(i<10)
{
P0&=0xFD;//第二个灯亮
}
else
{
P0|=0x02;//第二个灯灭
}
}
}
}
L1(22-32):
这段代码实现P0.1输出占空比为96%的方波,而P0.0恒为低。
P0.1输出如图3所示(受纸张限制,图中高低电平长度比例和实际有偏差)。
(原文件名:
120611_2.png)图3
下载验证:
从开发板上可以看到运行效果,D1比D2亮。
(这里说明一点:
当P0输出低电平时,LED亮,所以,PWM的占空比越小越亮)。
3.2产生8个亮度级别
3.1节的例子证实了我们的设想,PWM可控制LED的亮度,下面我们设计几组占空比不同的PWM,看看对LED亮度的控制效果。
代码如下:
程序清单L2:
不同占空比对LED亮度的控制
#include
#include"hw_config.h"
#include"my_type.h"//亮度级别表
codeu8LightLevel[8]={0,1,2,4,8,16,32,64};
voidmain(void)
{
u8i=0;
u8j=0;
u8k=0;
u8temp=0;//使能独立LED的供电,即LEDS6输出低电平
LEDEN=0;
ADDR0=0;
ADDR1=1;
ADDR2=1;
ADDR3=1;//开始全灭
P0=0xFF;
while
(1)//P0端口输出8组占空比不同的PWM
{
for(i=0;i<64;i++)
{
for(j=0;j<8;j++)
{
if(LightLevel[j]<=i)
{
temp|=(1< } else { temp&=~(1< } } P0=temp; } } } L2(29-45).此段程序是让P0口输出8组占空比不同的PWM,如图4: (原文件名: 120611_3.png)图4 下载验证: 从开发板上可以看到运行效果,从D1到D8的亮度逐渐增大。 3.3水滴下落效果 根据PWM可控制LED亮度的原理,我们用8个LED实现水滴下落的效果。 第一步,水滴逐渐变大,用D1从暗变亮模拟;第二步,水滴下落,带有拖尾效果,LED逐个亮,移动速度加快,且越靠前的LED亮度越大。 程序清单L3水滴流水灯 #include #include"hw_config.h" #include"my_type.h"//亮度级别表 codeu8LightLevel[8]={0,1,2,4,8,16,32,64};//水滴时间,实现加速效果 codeu8LightTime[16]={16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1}; voidmain(void) { u8i,j,k; u8temp,count; u8state;//使能独立LED的供电,即LEDS6输出低电平 LEDEN=0; ADDR0=0; ADDR1=1; ADDR2=1; ADDR3=1; while (1)//开始全灭 { P0=0xFF;//---------------水滴逐渐变大(第一个LED亮度逐渐变大)--------- for(i=0;i<64;i++)//一个亮度级别发送64个脉冲 { for(j=0;j<64;j++) { P0=0xFE;//以i为亮度级别,随着i的增大,占空比增大 for(k=0;k<64;k++) { if(k>i) { P0=0xFF; //----------------------水滴降落过程--------------------- } } } } for(state=0;state<16;state++)//每一状态维持LightTime[state]个脉冲 { for(count=0;count<=LightTime[state];count++) {//temp记录8个LED的状态,0代表亮,1代表灭 temp=0x00;//一个脉冲长度j从0到63 for(j=0;j<64;j++) //根据亮度表,依次确定8个LED当前状态,亮或灭 { for(k=0;k<8;k++)//以j为亮度级别,每个LED亮度不一样 { if(LightLevel[k]==j) { temp|=(1< } } if(state<=7) { P0=~((~temp)>>(7-state)); } else { P0=~((~temp)<<(state-7)); } } } } } } L2(31-46).实现水滴变大效果,这段代码的作用可用图形表达,如图5: (原文件名: 120611_4.png)图5 控制D1由暗变亮,用了64个亮度级别,每个级别发送64个脉冲。 L2(49-81).实现水滴下落。 代码就不逐行解释了,大家可根据注释自己分析,主要说一下实现的方法。 定义LED有8个亮度级别,若用开发板上的8个LED表示,如图6: (原文件名: 120611_5.png)图6 图中的红色面积代表亮度程度。 实现流水效果的方法就是: 让所有的亮度依次经过在所有LED,如图7: (原文件名: 120611_6.png)图7 状态的持续时间从0-15逐渐减小,以模拟水滴加速。 下载验证: 下载到开发板上,可以看到水滴下落效果。 3.4定时器产生PWM 前面3个例子中,我们用循环语句虽然能产生占空比不同的PWM,但PWM的周期不好控制,对此,我们学习如何用定时器产生特定周期PWM。 关于8051定时器的使用方法,大家可以参考例说51单片机的4章和5章。 我们用定时器0产生PWM,代码如下: 程序清单L4定时器0产生PWM #include #include"hw_config.h" #include"my_type.h"//亮度级别表 codeu8LightLevel[8]={1,2,4,8,16,28,50,64};//函数声明 voidtimer0_init(void); voidmain(void)//使能独立LED的供电,即LEDS6输出低电平 { LEDEN=0; ADDR0=0; ADDR1=1; ADDR2=1; ADDR3=1; timer0_init(); while (1){}} /********************************************************** 函数名称: timer0_init功能: 初始化定时器0 **********************************************************/ voidtimer0_init(void) { TMOD=0x01;//运行模式1 TH0=0xFF;//10us中断 TL0=0xFA; EA=1;//开启中断 ET0=1; TR0=1;//启动定时器 } /************************************************************ 函数名称: timer0_overflow功能: 定时器0溢出中断 ************************************************************/ voidtimer0_overflow(void)interruptTIMER0_OVERFLOW { u8i,temp=0; staticu8count=0; count++; count%=64; for(i=0;i<8;i++) { if(LightLevel[i]<=count) { temp|=(1< } else { temp&=~(1< } } P0=temp; TR0=0; TH0=0xFF;//重新赋值 TL0=0xF7; TR0=1; } L4(32).初始化定时器0,没10us产生一次中断。 L4(55-65).控制输出8组不同占空比的PWM。 这段代码功能和程序清单2中的功能一致。 下载验证: 下载到开发板上,可以看到D1到D8亮度逐渐增大。 3.5亮度不同的点阵 学习了用定时器产生PWM,我们可以控制更多的LED,比如LED点阵的亮度。 下面的例子实现LED点阵每行的亮度都不同。 程序清单5亮度不同的点阵 #include #include"hw_config.h" #include"my_type.h" codeu8LightLevel[8]={1,2,4,8,16,32,50,64};//亮度级别表 voidtimer0_init(void);//函数声明 voidmain(void) { LEDEN=0;//使能控制点阵的译码器 ADDR3=0; timer0_init(); while (1){}} /***************************************************************** 函数名称: timer0_init功能: 初始化定时器0 *****************************************************************/ voidtimer0_init(void) { TMOD=0x01;//运行模式1 TH0=0xFF;//中断时间10us TL0=0xF7; EA=1;//开启中断 ET0=1; TR0=1;//启动定时器 } /***************************************************************** 函数名称: timer0_overflow功能: 定时器0溢出中断 *****************************************************************/ voidtimer0_overflow(void)interruptTIMER0_OVERFLOW { u8i; u8p1_value=0; staticu8state=0;//点阵状态(扫描行数) staticu8count=0; TR0=0; count++; if(count==64) { state++; state%=8; count=0; } if(count { P0=0x00; } else{P0=0xFF;} p1_value=P1&0xf8; p1_value|=state; P1=p1_value; TH0=0xFF;//重新赋值 TL0=0xFA; TR0=1; } L5(28).初始化定时器,每10us中断一次。 L5(51-57).每中断64次,点阵扫描移动到下一行,用state记录当前行数。 L5(59-66).扫描每一行输出的PWM都不一样,使用的方式和处理独立LED一致。 L5(68-70).输出点阵对应的位码。 下载验证: 下载到开发板上,可以看到运行效果,点阵第一行最暗,越往下越亮。 3.6点阵模拟音乐频谱分析效果 在很多音乐播放软件上,都有频谱分析的图形,如图8: (原文件名: 120611_7.png)图8 我们用也可以模拟相似的图形,代码如下: 程序清单6: 点阵模拟音乐频谱分析 #include #include"hw_config.h" #include"my_type.h" //频谱波形表 codeu8Wave[16][8]= { {0xFF,0xFF,0xFF,0xFF,0xFE,0xBB,0xFE,0xAA}, {0xFF,0xFF,0xFF,0xFE,0xFB,0xAE,0xFA,0xAA}, {0xFF,0xFF,0xFF,0xFE,0xEB,0xBE,0xEA,0xAA}, {0xFF,0xFF,0xFE,0xFB,0xAF,0xFE,0xAA,0xAA}, {0xFF,0xFE,0xFB,0xBE,0xEA,0xBA,0xAA,0xAA}, {0xFF,0xFE,0xBB,0xEE,0xBA,0xBA,0xAA,0xAA}, {0xFE,0xBB,0xEE,0xBA,0xAA,0xAA,0xAA,0xAA}, {0xBA,0xEF,0xBE,0xAA,0xAA,0xAA,0xAA,0xAA}, {0xEE,0xBB,0xFE,0xAA,0xAA,0xAA,0xAA,0xAA}, {0xEE,0xBB,0xFE,0xEA,0xAA,0xAA,0xAA,0xAA}, {0xFE,0xEB,0xBE,0xFE,0xAA,0xAA,0xAA,0xAA}, {0xFF,0xEE,0xBB,0xFF,0xAE,0xAA,0xAA,0xAA}, {0xFF,0xFE,0xAF,0xFB,0xEE,0xAA,0xAA,0xAA}, {0xFF,0xFF,0xFE,0xBB,0xEF,0xBA,0xAA,0xAA}, {0xFF,0xFF,0xFF,0xFE,0xAB,0xFF,0xEE,0xAA}, {0xFF,0xFF,0xFF,0xFF,0xFE,0xEB,0xBE,0xAA} }; codeu8LightLevel[8]={1,2,4,8,16,32,50,64};//亮度级别表 voidtimer0_init(void);//函数声明 voidmain(void) { LEDEN=0;//使能控制点阵的译码器 ADDR3=0; timer0_init(); while (1){}} /***************************************************************** 函数名称: timer0_init功能: 初始化定时器0 *****************************************************************/ voidtimer0_init(void) { TMOD=0x01;//运行模式1 TH0=0xFF;//10us中断 TL0=0xFA; EA=1;//开启中断 ET0=1; TR0=1;//启动定时器 } /***************************************************************** 函数名称: timer0_overflow功能: 定时器0溢出中断 *****************************************************************/ voidtimer0_overflow(void)interruptTIMER0_OVERFLOW { u8i; u8p1_value=0; staticu8state=0;//点阵状态(扫描行数) staticu8count=0; staticu8wave_state=0;//波形状态 staticu16wave_count=0; TR0=0;//每中断1000次,改变波形状态 wave_count++; if(wave_count==1000) { wave_count=0;//每中断64次,改变扫描的行 wave_state++; wave_state%=16; } count++; if(count==64) { state++;//输出位码 state%=8; count=0; } if(count { P0=Wave[wave_state][state]; } else{P0=0xFF;} p1_value=P1&0xf8; p1_value|=state; P1=p1_value;//定时器重新赋值 TH0=0xFF; TL0=0xF7; TR0=1; } L6(6).波形表,共16个状态,每个状态下有8个数据,即一个点阵界面。 扫描点阵时循环发送,实现动态效果。 L6(77-83).每中断1000次,更换一个状态。 L6(86-101).和L5的功能一致,只是点阵段码输出的数据变成了波形表。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 高级 流水 水滴 效果