水滴流水灯程序
51单片机流水灯程序

51单片机流水灯程序51单片机是一种广泛使用的微控制器,具有丰富的IO端口和定时器资源。
流水灯程序是51单片机入门的基础示例之一,通过多个LED灯按照一定顺序逐个亮起或熄灭,形成流水灯的效果。
下面详细介绍51单片机流水灯程序的编写。
一、硬件连接要实现流水灯效果,需要将多个LED灯连接到51单片机的IO端口上。
一般使用P1端口作为输出端口控制LED灯的亮灭,P2端口作为输出口控制LED灯亮起的顺序。
具体连接方式如下:•将LED灯的阳极通过限流电阻连接到VCC。
•将每个LED灯的阴极通过限流电阻连接到P1端口。
•将P2端口的每个引脚依次连接到每个LED灯的阴极。
二、程序实现#include <reg52.h> //包含51单片机头文件#define LED P1 //定义LED为P1端口#define ORDER P2 //定义顺序控制为P2端口void delay(unsigned int t); //延时函数声明void main(){unsigned char i;while(1) //循环控制流水灯效果{for(i=0; i<8; i++) //控制8个LED灯{LED = 0x01<<i; //将第i个LED灯置亮delay(10000); //延时一段时间,使LED灯亮起后延时熄灭LED = 0x01>>(i+1); //将第i个LED灯置灭}}}void delay(unsigned int t) //延时函数定义{unsigned int i, j;for(i=0; i<t; i++){for(j=0; j<1275; j++);}}该程序首先定义了LED和ORDER两个变量,分别对应P1和P2端口的输出口。
在主函数中,使用一个while循环控制流水灯效果。
在循环内部,使用一个for循环控制8个LED灯的状态。
在每次循环中,先将第i个LED灯置亮,延时一段时间后将其置灭,然后进入下一个循环。
单片机流水灯与呼吸灯结合-滴水灯程序及详细教程(转载)

单片机流水灯与呼吸灯结合-滴水灯程序及详细教程(转载)TWAS手把手教你做呼吸灯-基于51单片机学习板内容比较简单,发这个贴主要是针对新手!什么是呼吸灯?顾名思义,灯光在微电脑控制之下完成由亮到暗的逐渐变化,感觉像是在呼吸。
用专业的话来说是通过控制PWM的占空比来完成对LED亮度的控制什么是PWM和占空比?脉冲宽度调制(Pulse Width Modulation,简称PWM),是利用微处理器的数字输出来对模拟电路进行控制的一种技术。
占空比:高电平在一个周期之内所占的时间比率。
呼吸灯原理当一颗LED在高速闪烁,闪烁的频率已经超过了人眼的感知的范围,那么我们看到这颗LED就是一直亮的,也就是视觉暂留现象(余晖效应)。
如果我们控制一次闪烁中亮和灭的时间(修改占空比),就可以控制亮度。
代码实现:/******************************************************** 程序名称:main.c* 程序功能:实现呼吸灯的主程序文件* 程序作者:TWAS* 创建时间:2015-1-22* 修改时间:* 程序版本:V0.1*******************************************************//* 包含的头文件 */#include <reg52.h>/* 寻址变量定义 */sbit LED_Drive = P3^5; /* 定义驱动LED的IO口,LED为共阳 *//******************************************************* 函数名称:main* 函数功能:主函数* 入口参数:NULL* 出口参数:NULL*******************************************************/int main(){unsigned char i;/* 初始化 */LED_Drive = 1;/* 主循环 */while(1){for(i = 0; i < 200; i++){/* 外边的for循环共循环200次,前面10次点亮LED,后面180次熄灭LED* 通过修改if后面的值,就可以改变占空比*/if(i < 10){LED_Drive = 0;}else{LED_Drive = 1;}}}return 0;}/******************************************* 程序结束*****************************************/可以明显看出我们所控制的LED比电源灯暗许多,既然我们会控制亮度,想实现呼吸灯也就变的简单了代码实现:(为了节约空间和界面简洁,只贴出主要实现的部分)int main(){unsigned char i;unsigned char ucNum = 0; /* 新增两个变量,ucNum 控制占空比*/bit bAdd = 1; /* bAdd选择是增大占空比还是减小占空比 *//* 初始化 */LED_Drive = 1;/* 主循环 */while(1){for(i = 0; i < 200; i++){/* 外边的for循环共循环200次,前面10次点亮LED,后面180次熄灭LED* 通过修改if后面的值,就可以改变占空比*/if(i < ucNum){LED_Drive = 0;}else{LED_Drive = 1;}}/* 选择是增大占空比还是减小占空比 */if (1 == bAdd){ucNum++;}else{ucNum--;}/* 当Num等于200也就是最大值时,bAdd置0,Num开始减小*/if (200 == ucNum){bAdd = 0;}/* 当Num等于200也就是最大值时,bAdd置1,Num开始增大*/else if (0 == ucNum){bAdd = 1;}}return 0;}由于图片看不到效果,这个地方就不贴图了,根据测试,我们的所需要的功能实现了!但是这时候有的人就有疑问了,这是很普通的LED,那如果是特殊一点的呢?比如我所用的学习板上面,16颗LED是用595驱动的,那呼吸灯又该如何实现呢?其实很简单,我们把驱动LED的函数封装一下,直接替换,其它不变就行了!代码实现:(为了节约空间和界面简洁,只贴出主要实现的部分)for(i = 0; i < 200; i++){/* 外边的for循环共循环200次,前面10次点亮LED,后面180次熄灭LED* 通过修改if后面的值,就可以改变占空比*/if(i < ucNum){DriveLED(0x0003); /* LED驱动,点亮D1和D2 */}else{DriveLED(0x0002); /* LED驱动,熄灭D1点亮D2 */}}当我把程序改成这样的时候,出了一点问题,不能呼吸,变成闪烁了!等等,先把LED驱动部分发一下:/******************************************************* 函数名称:SendData* 函数功能:74HC595数据的发送* 入口参数:unsigned int uiDataOne, unsigned int uiDataTwo * 出口参数:void*******************************************************/void SendData(unsigned char ucDataOne, unsigned char ucDataTwo){unsigned int i = 0;/* 将片选信号置为低电平 */HC595RCK = 0;/* 输入第一个数据:uiDataOne */for (i = 0; i < 8; i++){/* 给出脉冲信号,首先将CLK置为0 */HC595CLK = 0;if (0 != (ucDataOne & 0x80)){HC595DATA = 1;}else{HC595DATA = 0;}/* 给出脉冲信号,首先将CLK置为1 */HC595CLK = 1;/* 准备第二个数据 */ucDataOne = ucDataOne << 1;}/* 输入第二个数据:uiDataTwo */for (i = 0; i < 8; i++)/* 给出脉冲信号,首先将CLK置为0 */HC595CLK = 0;if (0 != (ucDataTwo & 0x80)){HC595DATA = 1;}else{HC595DATA = 0;}/* 给出脉冲信号,首先将CLK置为1 */HC595CLK = 1;/* 准备第二个数据 */ucDataTwo = ucDataTwo << 1;}/* 将片选信号置为高电平 */HC595RCK = 1;}/******************************************************** * 函数名称:DriveLED* 函数功能:595驱动程序是分两个数据发的,* 本函数把它合并成一个数据* 入口参数:uiData:16颗LED需要显示的数据* 出口参数:NULL*******************************************************/ void DriveLED(unsigned int uiData)SendData(uiData >> 8,uiData);}继续刚刚的问题,呼吸灯变成闪烁了,怎么回事呢?在程序逻辑上是没有问题的,我们只是更改了LED的驱动部分,看来就是LED驱动的问题了!先来Debug看一下,执行DriveLED这个函数,时间是接近400微妙,循环200次,就是差不多80毫秒,那么LED的闪烁频率为12.5HZ(都是大概的值,没有精确计算),还不足以形成视觉暂留现象。
流水灯电路图和程序

流水灯电路图和程序#include <reg52.h>#include<instrins.h>#define uchar unsigned char#define uint unsigned intuchar code led[]={0xfe,0xfb,0xfd ,0xf7,0xef,0xbf,0xdf,0x7f};delay(uint z){uint x,y;for(x=z;x>0;x--)for(y=110;y>0;y--);}main( ){uint i;while(1){P2=led[];delay(500);_crol_(led,1);}}用arm7做一个流水灯的设计。
悬赏分:100 - 解决时间:2009-9-3 20:03试设计一个闪烁流水灯控制器,该控制器可以控制8个灯顺序亮灭,当按钮K按下1次后,每次顺序点亮一个灯。
而且每个点亮的灯在闪烁3次后,才能灭,周而复始,直到按钮K 二次按下。
(用状态机设计)要用PROTEL99画好电路图。
还要写好程序。
画图的也只能发到我的邮箱里面吧。
邮箱:。
谢谢各位。
提问者:woxinruozai - 五级最佳答案从原理图可以看出,如果我们想让接在P1.0口的LED1亮起来,那么我们只要把P1.0口的电平变为低电平就可以了;相反,如果要接在P1.0口的LED1熄灭,就要把P1.0口的电平变为高电平就可以;同理,接在P1.1~P1.7口的其他7个LED的点亮和熄灭方法方法同LED1。
因此,要实现流水灯功能,我们只要将LED2~LED8依次点亮、熄灭,依始类推,8只LED变会一亮一暗的做流水灯了。
实现8个LED流水灯程序用中文表示为:P1.0低、延时、P1.0高、P1.1低、延时、P1.1高、P1.2低、延时、P1.2高、P1.3低、延时、P1.3高、P1.4低、延时、P1.4高、P1.5低、延时、P1.5高、P1.6低、延时、P1.6高、P1.7低、延时、P1.7高、返回到开始、程序结束。
五种编程方式实现流水灯的单片机C程序

五种编程方式实现流水灯的单片机C程序流水灯是一种常见的灯光效果,常用于装饰和展示。
实现流水灯的程序可以使用多种不同的编程方式,包括传统的顺序编程、状态机编程、中断编程、调度器编程和面向对象编程。
下面分别介绍这五种方式实现流水灯的程序。
1.顺序编程方式:顺序编程是最常见的编程方式,也是最直接的方式。
下面是使用顺序编程方式实现流水灯的C程序:```c#include <reg52.h>void delay(unsigned int t)while(t--)for(int i=0; i<50; i++);}void mainunsigned char led = 0x80; // 初始灯光状态while(1)P0 = led; // 输出灯光状态delay(500); // 延时一段时间led >>= 1; // 右移一位,实现流水灯效果if(led == 0) // 到达最右边后重新开始led = 0x80;}}```2.状态机编程方式:状态机编程是一种基于状态的编程方式,通过定义不同的状态和状态转换来实现流水灯效果。
下面是使用状态机编程方式实现流水灯的C程序:```c#include <reg52.h>typedef enumState1,State2,State3,State4,State5} State;void delay(unsigned int t)while(t--)for(int i=0; i<50; i++);}void mainState state = State1; // 初始状态为State1 while(1)switch(state)case State1:P0=0x80;delay(500);state = State2;break;case State2:P0=0x40;delay(500);state = State3;break;case State3:P0=0x20;delay(500);state = State4;break;case State4:P0=0x10;delay(500);state = State5;break;case State5:P0=0x08;delay(500);state = State1;break;}}```3.中断编程方式:中断编程方式是一种基于中断事件的编程方式,通过在特定的中断事件触发时改变灯光状态来实现流水灯效果。
流水灯程序

图1流水灯硬件原理图从原理图中可以看出,假如要让接在PLO 口的LEDI 亮起来,那么只要把 P1.0口的电平变为低电平就可以了;相反,假如要接在PLO 口的LEDl 熄灭,就 要把PLO 口的电平变为高电平洞理,接在P1.1~PL7 口的其他7个LED 的点 亮和熄灭的方法同LED1。
因此,要实现流水灯功能,我们只要将发光二极管 LED1-LED8依次点亮、熄灭,8只LED 灯便会一亮一暗的做流水灯了。
在此 我们还应留意一点,由于人眼的视觉暂留效应以及单片机执行每条指令的时间很 短,我们在掌握二极管亮灭的时候应当延时一段时间,否则我们就看不到“流水” 效果了。
3.软件编程单片机的应用系统由硬件和软件组成,上述硬件原理图搭建完成上电之后, 我们还不能看到流水灯循环点亮的现象,我们还需要告知单片机怎么来进行工PlO POO Pll POl PlJ POi PlJ P03 Pl* PO* P15 PO 5 Pl 3PO 4 P17 λ!SS>C51POT am PJO nττoPnP22 Il pn IO P” P25 I∑∖T> PY P27Xl X :XXD!XD KD ALEP TlPSHT∖n47Kx8VCCLEDl-M —LED)W LED)LED1 W * LEDS人KLEDj WLED7W-44LEDS-M作,即编写程序掌握单片机管脚电平的凹凸变化,来实现发光二极管的一亮一灭。
软件编程是单片机应用系统中的一个重要的组成部分,是单片机学习的重点和难点。
下面我们以最简洁的流水灯掌握功能即实现8个LED灯的循环点亮,来介绍实现流水灯掌握的几种软件编程方法。
3.1位控法这是一种比较笨但又最易理解的方法,采纳挨次程序结构,用位指令掌握Pl 口的每一个位输出凹凸电平,从而来掌握相应LED灯的亮灭。
程序如下:ORG OOOOH ;单片机上电后从0000H地址执行AJMPSTART ;跳转到主程序存放地址处ORG 0030H ;设置主程序开头地址START : MOV SP , #60H ;设置堆栈起始地址为60HCLRPl.0;PLO输出低电平,使LEDl点亮ACALL DELAY ;调用延时子程序SETB P1.0;P1.0输出高电平,使LEDl熄灭CLR Pl.l ;P1.1输出低电平,使LED2点亮ACALL DELAY ;调用延时子程序SETB Pl.l ;P1.1输出高电平,使LED2熄灭CLR P1.2;P1.2输出低电平,使LED3点亮ACALL DELAY ;调用延时子程序SETB P1.2;P1.2输出高电平,使LED3熄灭CLR P1.3 ;P1.3输出低电平,使LED4点亮ACALL DELAY ;调用延时子程序SETB P1.3;P1.3输出高电平,使LED4熄灭CLR Pl.4 ;P1.4输出低电平,使LED5点亮ACALL DELAY ;调用延时子程序SETB P1.4;P1.4输出高电平,使LED5熄灭CLR P1.5;P1.5输出低电平,使LED6点亮ACALL DELAY ;调用延时子程序SETB P1.5;P1.5输出高电平,使LED6熄灭CLR P1.6 ;P1.6输出低电平,使LED7点亮ACALL DELAY ;调用延时子程序CLR P1.7 ;P1.7输出低电平,使LED8点亮ACALL DELAY ;调用延时子程序SETB P1.7pl.7输出高电平,使LED8熄灭ACALL DELAY ;调用延时子程序START ;8个LED流了一遍后返回到标号START处再循环AJMPDELAY :;延时子程序MOV RO , #255 ;延时一段时间Dl : MOV Rl , #255DJNZRl , $DJNZ RO , DlRET ;子程序返回END ;程序结束3.2循环移位法在上个程序中我们是逐个掌握Pl端口的每个位来实现的,因此程序显得有点简单,下面我们采用循环移位指令,采纳循环程序结构进行编程。
高级流水灯_水滴效果

高级流水灯--水滴效果(渐变带拖尾效果)实现和讲解[复制链接]spark5115主题好友124积分注册会员莫元111•发消息电梯直达1楼发表于 2011-12-6 09:03:44|只看该作者|倒序浏览简介学习嵌入式第一个例子通常都是控制一个LED亮灭,然后是花样繁多的流水灯,但不管灯的花样如何变化,单个LED的亮度没有变化,只有亮、灭两个状态,本章我们实现如何控制LED的亮度。
1 什么是PWM脉冲宽度调制(Pulse Width Modulation,简称PWM),是利用微处理器的数字输出来对模拟电路进行控制的一种技术。
在本章的应用中可以认为PWM就是一种方波。
比如图1:(原文件名:120611_0.png)图1 方波是周期为10ms,占空比为60%的PWM。
占空比:高电平在一个周期之内所占的时间比率。
2 硬件设计在例说51单片机的第三章,我们讲过如何控制开发板上LED的亮灭。
首先译码器输出端LEDS6为低,T10导通,给8个LED供电,然后通过缓冲器8个输出端BD0~BD7的控制LED的亮灭(低亮高灭)。
(原文件名:120611_1.png)图2 LED硬件连接如果BD口输出高低不断变化,则LED会闪烁;如果这种高低电平变化非常快,由于人的视觉暂留现象,LED就会出现不同的亮度。
3 软件设计3.1 PWM能否控制亮度下面我们就用实践验证PWM是否能够控制LED的亮度,测试代码如下:程序清单L1:验证PWM能否控制LED的亮度1 #include <reg52.h>2 #include "my_type.h"3 #include "hw_config.h"456 void main(void)7 {8 u8 i = 0;910 //使能独立LED的供电,即LEDS6输出低电平11 LEDEN = 0;12 ADDR0 = 0;13 ADDR1 = 1;14 ADDR2 = 1;15 ADDR3 = 1;1617 //第一个LED亮18 P0 = 0xFE;1920 while(1)21 {22 for(i=0; i<250; i++)23 {24 if(i<10)25 {26 P0 &= 0xFD; //第二个灯亮27 }28 else29 {30 P0 |= 0x02; //第二个灯灭31 }32 }33 }34 }L1(22-32):这段代码实现P0.1输出占空比为96%的方波,而P0.0恒为低。
高级流水灯--水滴效果渐变带拖尾效果实现和讲解

下载验证:从开发板上可以看到运行效果,从 D1 到 D8 的亮度逐渐增大。 3.3 水滴下落效果 根据 PWM 可控制 LED 亮度的原理,我们用 8 个 LED 实现水滴下落的效果。第一步,水滴 逐渐变大,用 D1 从暗变亮模拟;第二步,水滴下落,带有拖尾效果,LED 逐个亮,移动速 度加快,且越靠前的 LED 亮度越大。 程序清单 L3 水滴流水灯 1 #include <reg52.h> 2 #include "hw_config.h" 3 #include "my_type.h"
如果 BD 口输出高低不断变化,则 LED 会闪烁;如果这种高低电平变化非常快,由于人的 视觉暂留现象,LED 就会出现不同的亮度。 3 软件设计 3.1 PWM 能否控制亮度 下面我们就用实践验证 PWM 是否能够控制 LED 的亮度,测试代码如下: 程序清单 L1: 验证 PWM 能否控制 LED 的亮度 1 #include <reg52.h> 2 #include "my_type.h" 3 #include "hw_config.h" 4 5 6 void main(void) 7{ 8 u8 i = 0; 9 10 //使能独立 LED 的供电,即 LEDS6 输出低电平 11 LEDEN = 0; 12 ADDR0 = 0; 13 ADDR1 = 1; 14 ADDR2 = 1; 15 ADDR3 = 1; 16 17 //第一个 LED 亮 18 P0 = 0xFE; 19 20 while(1) 21 { 22 for(i=0; i<250; i++) 23 { 24 if(i<10) 25 { 26 P0 &= 0xFD; //第二个灯亮 27 } 28 else 29 { 30 P0 |= 0x02; //第二个灯灭 31 } 32 } 33 } 34 } L1(22-32):这段代码实现 P0.1 输出占空比为 96%的方波,而 P0.0 恒为低。 P0.1 输出如图 3 所示(受纸张限制,图中高低电平长度比例和实际有偏差) 。
多种方法写出的51单片机流水灯C语言程序

多种方法写出的51单片机流水灯C语言程序流水灯最原始下面是一个最基本的流水灯程序,使用了51单片机的寄存器编程方法。
include "reg51.h"sbit p0=P1^0;sbit p1=P1^1;sbit p2=P1^2;sbit p3=P1^3;sbit p4=P1^4;sbit p5=P1^5;sbit p6=P1^6;sbit p7=P1^7;void mdelay(unsigned int t){unsigned char n;for(;t>0;t--)for(n=0;n<125;n++)void main()while(1)P1=0;p0=1;mdelay(1000);p0=0;p1=1;mdelay(1000);p1=0;p2=1;流水灯位左移在流水灯的基础上,我们可以通过左移位的方式来实现流水灯的效果。
void main()unsigned char led = 0x01.// 初始化led为xxxxxxxxwhile(1)P1 = ~led。
// 取反输出,因为我们的电路是低电平亮灯mdelay(1000);led <<= 1.// 左移一位if(led == 0) // 如果led变为0了,说明已经左移到最后一位了,需要重新开始led = 0x01;流水灯移位函数为了方便实现流水灯的位移,我们可以封装一个移位函数。
void shift_left(unsigned char *led。
unsigned char n)for(unsigned char i=0.i<n。
i++)led <<= 1;if(*led == 0)led = 0x01;void main()unsigned char led = 0x01;while(1)P1 = ~led;mdelay(1000);shift_left(&led。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
高级流水灯--水滴效果(渐变带拖尾效果)实现和讲解一说就是错( 楼主 ) 2012-11-21 18:23:14只看该作者 11347 |204 倒序浏览简介学习嵌入式第一个例子通常都是控制一个LED亮灭,然后是花样繁多的流水灯,但不管灯的花样如何变化,单个LED的亮度没有变化,只有亮、灭两个状态,本章我们实现如何控制LED的亮度。
1 什么是PWM脉冲宽度调制(Pulse Width Modulation,简称PWM),是利用微处理器的数字输出来对模拟电路进行控制的一种技术。
在本章的应用中可以认为PWM就是一种方波。
比如图1:(原文件名:120611_0.png)图1 方波是周期为10ms,占空比为60%的PWM。
占空比:高电平在一个周期之内所占的时间比率。
2 硬件设计在例说51单片机的第三章,我们讲过如何控制开发板上LED的亮灭。
首先译码器输出端LEDS6为低,T10导通,给8个LED供电,然后通过缓冲器8个输出端BD0~BD7的控制LED的亮灭(低亮高灭)。
(原文件名:120611_1.png)图2 LED硬件连接如果BD口输出高低不断变化,则LED会闪烁;如果这种高低电平变化非常快,由于人的视觉暂留现象,LED就会出现不同的亮度。
3 软件设计3.1 PWM能否控制亮度下面我们就用实践验证PWM是否能够控制LED的亮度,测试代码如下:程序清单L1:验证PWM能否控制LED的亮度1 #include2 #include "my_type.h"3 #include "hw_config.h"456 void main(void)7 {8 u8 i = 0;910 //使能独立LED的供电,即LEDS6输出低电平11 LEDEN = 0;12 ADDR0 = 0;13 ADDR1 = 1;14 ADDR2 = 1;15 ADDR3 = 1;1617 //第一个LED亮18 P0 = 0xFE;1920 while(1)21 {22 for(i=0; i<250; i++)23 {24 if(i<10)25 {26 P 0 &= 0xFD; //第二个灯亮27 }28 else29 {30 P 0 |= 0x02; //第二个灯灭31 }32 }33 }34 }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亮度的控制1 #include2 #include "hw_config.h"3 #include "my_type.h"456 //亮度级别表7 code u8 LightLevel[8]={0,1,2,4,8,16,32,64};89 void main(void)10 {11 u8 i = 0;12 u8 j = 0;13 u8 k = 0;14 u8 temp = 0;1516 //使能独立LED的供电,即LEDS6输出低电平17 LEDEN = 0;18 ADDR0 = 0;19 ADDR1 = 1;20 ADDR2 = 1;21 ADDR3 = 1;2223 //开始全灭24 P0 = 0xFF;2526 while(1)27 {28 //P0端口输出8组占空比不同的PWM29 for(i=0; i<64; i++)30 {31 for(j=0; j<8; j++)32 {33 i f(LightLevel[j] <= i)34 {35temp |= (1<<j);36 }37 e lse38 {39temp &= ~(1<<j);40 }41 }4243 P0 = temp;44 }45 }46 }L2(29-45).此段程序是让P0口输出8组占空比不同的PWM,如图4:(原文件名:120611_3.png)图4下载验证:从开发板上可以看到运行效果,从D1到D8的亮度逐渐增大。
3.3 水滴下落效果根据PWM可控制LED亮度的原理,我们用8个LED实现水滴下落的效果。
第一步,水滴逐渐变大,用D1从暗变亮模拟;第二步,水滴下落,带有拖尾效果,LED 逐个亮,移动速度加快,且越靠前的LED亮度越大。
程序清单L3 水滴流水灯1 #include2 #include "hw_config.h"3 #include "my_type.h"45 //亮度级别表6 code u8 LightLevel[8]={0,1,2,4,8,16,32,64};78 //水滴时间,实现加速效果9 code u8LightTime[16]={16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1};101112 void main(void)13 {14 u8 i,j,k;15 u8 temp,count;16 u8 state;1718 //使能独立LED的供电,即LEDS6输出低电平19 LEDEN = 0;20 ADDR0 = 0;21 ADDR1 = 1;22 ADDR2 = 1;23 ADDR3 = 1;2425 while(1)26 {27 //开始全灭28 P0 = 0xFF;2930 //---------------水滴逐渐变大(第一个LED亮度逐渐变大)---------31 for(i=0; i<64; i++)32 {33 //一个亮度级别发送64个脉冲34 for(j=0;j<64; j++)35 {36 P 0 = 0xFE;37 / /以i为亮度级别,随着i的增大,占空比增大38 f or(k=0; k<64; k++)39 {40if(k > i)41{42P0 = 0xFF;43}44 }45 }46 }4748 //----------------------水滴降落过程---------------------49 for(state=0; state<16; state++)50 {51 //每一状态维持LightTime[state]个脉冲52 for(count=0; count<=LightTime[state]; count++)53 {54 / /temp记录8个LED的状态,0代表亮,1代表灭55 t emp = 0x00;5657 / /一个脉冲长度j从0到6358 f or(j=0; j<64; j++)59 {60//根据亮度表,依次确定8个LED当前状态,亮或灭61for(k=0; k<8; k++)62{63//以j为亮度级别,每个LED亮度不一样64if(LightLevel[k] == j)65{66temp |= (1 << k);67}68}6970if(state <= 7)71{72P0 = ~((~temp) >> (7-state));73}74else75{76P0 = ~((~temp) << (state-7));77}78 }79 }80 }81 }82 }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产生PWM1 #include2 #include "hw_config.h"3 #include "my_type.h"456 //亮度级别表7 code u8 LightLevel[8]={1,2,4,8,16,28,50,64};89 //函数声明10 void timer0_init(void);1112 void main(void)13 {14 //使能独立LED的供电,即LEDS6输出低电平15 LEDEN = 0;16 ADDR0 = 0;17 ADDR1 = 1;18 ADDR2 = 1;19 ADDR3 = 1;2021 timer0_init();2223 while(1)24 {25 }26 }2728 /**************************************************** ******29 函数名称:timer0_init30 功能:初始化定时器031 ***************************************************** *****/32 void timer0_init(void)33 {34 TMOD = 0x01; //运行模式135 TH0 = 0xFF; //10us中断36 TL0 = 0xFA;37 EA = 1; //开启中断38 ET0 = 1;39 TR0 = 1; //启动定时器4041 }4243 /**************************************************** ********44 函数名称:timer0_overflow45 功能:定时器0溢出中断46 ***************************************************** *******/47 void timer0_overflow(void) interrupt TIMER0_OVERFLOW48 {49 u8 i,temp = 0;50 static u8 count = 0;5152 count++;53 count %= 64;5455 for(i=0; i<8; i++)56 {57 if(LightLevel <= count)58 {59 temp |=(1<<i);60 }61 else62 {63 temp &=~(1<<i);64 }65 }6667 P0 = temp;6869 TR0 = 0;70 TH0 = 0xFF; //重新赋值71 TL0 = 0xF7;72 TR0 = 1;73 }L4(32).初始化定时器0,没10us产生一次中断。