51单片机LED流水灯拖尾效果.docx

上传人:b****5 文档编号:4523027 上传时间:2022-12-01 格式:DOCX 页数:18 大小:19.47KB
下载 相关 举报
51单片机LED流水灯拖尾效果.docx_第1页
第1页 / 共18页
51单片机LED流水灯拖尾效果.docx_第2页
第2页 / 共18页
51单片机LED流水灯拖尾效果.docx_第3页
第3页 / 共18页
51单片机LED流水灯拖尾效果.docx_第4页
第4页 / 共18页
51单片机LED流水灯拖尾效果.docx_第5页
第5页 / 共18页
点击查看更多>>
下载资源
资源描述

51单片机LED流水灯拖尾效果.docx

《51单片机LED流水灯拖尾效果.docx》由会员分享,可在线阅读,更多相关《51单片机LED流水灯拖尾效果.docx(18页珍藏版)》请在冰豆网上搜索。

51单片机LED流水灯拖尾效果.docx

51单片机LED流水灯拖尾效果

高级流水灯--水滴效果(渐变带拖尾效果)实现和讲解

简介

学习嵌入式第一个例子通常都是控制一个LED亮灭,然后是花样繁多的流水灯,但不管灯的花样如何变化,单个LED的亮度没有变化,只有亮、灭两个状态,本章我们实现如何控制LED的亮度。

1什么是PWM

脉冲宽度调制(PulseWidthModulation,简称PWM),是利用微处理器的数字输出来对模拟电路进行控制的一种技术。

在本章的应用中可以认为PWM就是一种方波。

比如图1:

http:

E

6E.png(原文件名:

120611_

0."png)图1方波

是周期为10ms,占空比为60%的PWM。

占空比:

高电平在一个周期之内所占的时间比率。

2硬件设计

在例说51单片机的第三章,我们讲过如何控制开发板上LED的亮灭。

首先译码器输出端LEDS6为低,T10导通,给8个LED供电,然后通过缓冲器8个输出端BD0~BD7的控制LED的亮灭(低亮高灭)。

http:

9."png(原文件名:

120611_

1."png)图2LED硬件连接

如果BD口输出高低不断变化,则LED会闪烁;如果这种高低电平变化非常快,由于人的视觉暂留现象,LED就会出现不同的亮度。

3软件设计

3.1PWM能否控制亮度

下面我们就用实践验证PWM是否能够控制LED的亮度,测试代码如下:

程序清单L1:

验证PWM能否控制LED的亮度

1#include

52."h>

2#include"my_type.h"

3#include"hw_config.h"45

6voidmain(void)

7{

8u8i=0;910//使能独立LED的供电,即LEDS6输出低电平

11LEDEN=0;

12ADDR0=0;

13ADDR1=1;

14ADDR2=1;

15ADDR3=1;

16

17//第一个LED亮

18P0=0xFE;

19

20while

(1)

21{

22for(i=0;i<250;i++)

23{

24if(i<10)

25{

26P0&=0xFD;//第二个灯亮

27}

28else

29{

30P0|=0x02;//第二个灯灭

31}

32}

33}

34}

L1(22-32):

这段代码实现P

0."1输出占空比为96%的方波,而P

0."0恒为低。

P

0."1输出如图3所示(受纸张限制,图中高低电平长度比例和实际有偏差)。

http:

1."png(原文件名:

120611_

2."png)图3

下载验证:

从开发板上可以看到运行效果,D1比D2亮。

(这里说明一点:

当P0输出低电平时,LED亮,所以,PWM的占空比越小越亮)。

3.2产生8个亮度级别

3.1节的例子证实了我们的设想,PWM可控制LED的亮度,下面我们设计几组占空比不同的PWM,看看对LED亮度的控制效果。

代码如下:

程序清单L2:

不同占空比对LED亮度的控制

1#include

52."h>

2#include"hw_config.h"

3#include"my_type.h"45

6//亮度级别表

7codeu8LightLevel={0,1,2,4,8,16,32,64};89voidmain(void)

10{

11u8i=0;

12u8j=0;

13u8k=0;

14u8temp=0;

15

16//使能独立LED的供电,即LEDS6输出低电平

17LEDEN=0;

18ADDR0=0;

19ADDR1=1;

20ADDR2=1;

21ADDR3=1;

22

23//开始全灭

24P0=0xFF;

25

26while

(1)

27{

28//P0端口输出8组占空比不同的PWM

29for(i=0;i<64;i++)

30{

31for(j=0;j<8;j++)

32{

33if(LightLevel<=i)

34{

35temp|=(1<

36}

37else

38{

39temp&=~(1<

40}

41}

42

43P0=temp;

44}

45}

46}

L2(29-45).此段程序是让P0口输出8组占空比不同的PWM,如图4:

http:

3."png)图4

下载验证:

从开发板上可以看到运行效果,从D1到D8的亮度逐渐增大。

3.3水滴下落效果

根据PWM可控制LED亮度的原理,我们用8个LED实现水滴下落的效果。

第一步,水滴逐渐变大,用D1从暗变亮模拟;第二步,水滴下落,带有拖尾效果,LED逐个亮,移动速度加快,且越靠前的LED亮度越大。

程序清单L3水滴流水灯

1#include

52."h>

2#include"hw_config.h"

3#include"my_type.h"45//亮度级别表

6codeu8LightLevel={0,1,2,4,8,16,32,64};78//水滴时间,实现加速效果

9codeu8LightTime={16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1};

10

11

12voidmain(void)

13{

14u8i,j,k;

15u8temp,count;

16u8state;

17

18//使能独立LED的供电,即LEDS6输出低电平

19LEDEN=0;

20ADDR0=0;

21ADDR1=1;

22ADDR2=1;

23ADDR3=1;

24

25while

(1)

26{

27//开始全灭

28P0=0xFF;

29

30//---------------水滴逐渐变大(第一个LED亮度逐渐变大)---------

31for(i=0;i<64;i++)

32{

33//一个亮度级别发送64个脉冲

34for(j=0;j<64;j++)

35{

36P0=0xFE;

37//以i为亮度级别,随着i的增大,占空比增大

38for(k=0;k<64;k++)

39{

40if(k>i)

41{

42P0=0xFF;

43}

44}

45}

46}

47

48//----------------------水滴降落过程---------------------

49for(state=0;state<16;state++)

50{

51//每一状态维持LightTime个脉冲

52for(count=0;count<=LightTime;count++)

53{

54//temp记录8个LED的状态,0代表亮,1代表灭

55temp=0x00;

56

57//一个脉冲长度j从0到63

58for(j=0;j<64;j++)

59{

60//根据亮度表,依次确定8个LED当前状态,亮或灭

61for(k=0;k<8;k++)

62{

63//以j为亮度级别,每个LED亮度不一样

64if(LightLevel==j)

65{

66temp|=(1<

67}

68}

69

70if(state<=7)

71{

72P0=~((~temp)>>(7-state));

73}

74else

75{

76P0=~((~temp)<<(state-7));

77}

78}

79}

80}

81}

82}

L2(31-46).实现水滴变大效果,这段代码的作用可用图形表达,如图5:

http:

4."png)图5

控制D1由暗变亮,用了64个亮度级别,每个级别发送64个脉冲。

L2(49-81).实现水滴下落。

代码就不逐行解释了,大家可根据注释自己分析,主要说一下实现的方法。

定义LED有8个亮度级别,若用开发板上的8个LED表示,如图6:

http:

5."png)图6

图中的红色面积代表亮度程度。

实现流水效果的方法就是:

让所有的亮度依次经过在所有LED,如图7:

http:

6."png)图7

状态的持续时间从0-15逐渐减小,以模拟水滴加速。

下载验证:

下载到开发板上,可以看到水滴下落效果。

3.4定时器产生PWM

前面3个例子中,我们用循环语句虽然能产生占空比不同的PWM,但PWM的周期不好控制,对此,我们学习如何用定时器产生特定周期PWM。

关于8051定时器的使用方法,大家可以参考例说51单片机的4章和5章。

我们用定时器0产生PWM,代码如下:

程序清单L4定时器0产生PWM

1#include

52."h>

2#include"hw_config.h"

3#include"my_type.h"45

6//亮度级别表

7codeu8LightLevel={1,2,4,8,16,28,50,64};89//函数声明

10voidtimer0_init(void);

11

12voidmain(void)

13{

14//使能独立LED的供电,即LEDS6输出低电平

15LEDEN=0;

16ADDR0=0;

17ADDR1=1;

18ADDR2=1;

19ADDR3=1;

20

21timer0_init();

22

23while

(1)

24{

25}

26}

27

28/**********************************************************

29函数名称:

timer0_init

30功能:

初始化定时器0

31**********************************************************/

32voidtimer0_init(void)

33{

34TMOD=0x01;//运行模式1

35TH0=0xFF;//10us中断

36TL0=0xFA;

37EA=1;//开启中断

38ET0=1;

39TR0=1;//启动定时器

40

41}

42

43/************************************************************44函数名称:

timer0_overflow

45功能:

定时器0溢出中断

46************************************************************/47voidtimer0_overflow(void)interruptTIMER0_OVERFLOW

48{

49u8i,temp=0;

50staticu8count=0;

51

52count++;

53count%=64;

54

55for(i=0;i<8;i++)

56{

57if(LightLevel<=count)

58{

59temp|=(1<

60}

61else

62{

63temp&=~(1<

64}

65}

66

67P0=temp;

68

69TR0=0;

70TH0=0xFF;//重新赋值

71TL0=0xF7;

72TR0=1;

73}

L4

(32).初始化定时器0,没10us产生一次中断。

L4(55-65).控制输出8组不同占空比的PWM。

这段代码功能和程序清单2中的功能一致。

下载验证:

下载到开发板上,可以看到D1到D8亮度逐渐增大。

3.5亮度不同的点阵

学习了用定时器产生PWM,我们可以控制更多的LED,比如LED点阵的亮度。

下面的例子实现LED点阵每行的亮度都不同。

程序清单5亮度不同的点阵

1#include

52."h>

2#include"hw_config.h"

3#include"my_type.h"45

6//亮度级别表

7codeu8LightLevel={1,2,4,8,16,32,50,64};89//函数声明

10voidtimer0_init(void);

11

12voidmain(void)

13{

14//使能控制点阵的译码器

15LEDEN=0;

16ADDR3=0;

17

18timer0_init();

19

20while

(1)

21{}

22}

23

24/*****************************************************************25函数名称:

timer0_init

26功能:

初始化定时器0

27*****************************************************************/28voidtimer0_init(void)

29{

30TMOD=0x01;//运行模式1

31TH0=0xFF;//中断时间10us

32TL0=0xF7

33EA=1;//开启中断

34ET0=1;

35TR0=1;//启动定时器

36}

37

38/*****************************************************************39函数名称:

timer0_overflow

40功能:

定时器0溢出中断

41*****************************************************************/42voidtimer0_overflow(void)interruptTIMER0_OVERFLOW

43{

44u8i;

45u8p1_value=0;

46staticu8state=0;//点阵状态(扫描行数)

47staticu8count=0;

48

49TR0=0;

50

51count++;

52if(count==64)

53{

54state++;

55state%=8;

56count=0;

57}

58

59if(count

60{

61P0=0x00;

62}

63else

64{

65P0=0xFF;

66}

67

68p1_value=P1&0xf8;

69p1_value|=state;

70P1=p1_value;

71

72TH0=0xFF;//重新赋值

73TL0=0xFA;

74TR0=1;

75}

L5

(28).初始化定时器,每10us中断一次。

L5(51-57).每中断64次,点阵扫描移动到下一行,用state记录当前行数。

L5(59-66).扫描每一行输出的PWM都不一样,使用的方式和处理独立LED一致。

L5(68-70).输出点阵对应的位码。

下载验证:

下载到开发板上,可以看到运行效果,点阵第一行最暗,越往下越亮。

3.6点阵模拟音乐频谱分析效果

在很多音乐播放软件上,都有频谱分析的图形,如图8:

http:

7."png)图8

我们用也可以模拟相似的图形,代码如下:

程序清单6:

点阵模拟音乐频谱分析

1#include

52."h>

2#include"hw_config.h"

3#include"my_type.h"45//频谱波形表

6codeu8Wave=

7{

8{0xFF,0xFF,0xFF,0xFF,0xFE,0xBB,0xFE,0xAA},

9{0xFF,0xFF,0xFF,0xFE,0xFB,0xAE,0xFA,0xAA},

10{0xFF,0xFF,0xFF,0xFE,0xEB,0xBE,0xEA,0xAA},

11{0xFF,0xFF,0xFE,0xFB,0xAF,0xFE,0xAA,0xAA},

12{0xFF,0xFE,0xFB,0xBE,0xEA,0xBA,0xAA,0xAA},

13{0xFF,0xFE,0xBB,0xEE,0xBA,0xBA,0xAA,0xAA},

14{0xFE,0xBB,0xEE,0xBA,0xAA,0xAA,0xAA,0xAA},

15{0xBA,0xEF,0xBE,0xAA,0xAA,0xAA,0xAA,0xAA},

16{0xEE,0xBB,0xFE,0xAA,0xAA,0xAA,0xAA,0xAA},

17{0xEE,0xBB,0xFE,0xEA,0xAA,0xAA,0xAA,0xAA},

18{0xFE,0xEB,0xBE,0xFE,0xAA,0xAA,0xAA,0xAA},

19{0xFF,0xEE,0xBB,0xFF,0xAE,0xAA,0xAA,0xAA},

20{0xFF,0xFE,0xAF,0xFB,0xEE,0xAA,0xAA,0xAA},

21{0xFF,0xFF,0xFE,0xBB,0xEF,0xBA,0xAA,0xAA},

22{0xFF,0xFF,0xFF,0xFE,0xAB,0xFF,0xEE,0xAA},

23{0xFF,0xFF,0xFF,0xFF,0xFE,0xEB,0xBE,0xAA}

24};

25

26//亮度级别表

27codeu8LightLevel={1,2,4,8,16,32,50,64};

28

29//函数声明

30voidtimer0_init(void);

31

32voidmain(void)

33{

34//使能控制点阵的译码器

35LEDEN=0;

36ADDR3=0;

37

38timer0_init();

39

40while

(1)

41{

42}

43}

44

45/*****************************************************************46函数名称:

timer0_init

47功能:

初始化定时器0

48*****************************************************************/49voidtimer0_init(void)

50{

51TMOD=0x01;//运行模式1

52TH0=0xFF;//10us中断

53TL0=0xFA;

54EA=1;//开启中断

55ET0=1;

56TR0=1;//启动定时器

57

58}

59

60/*****************************************************************61函数名称:

timer0_overflow

62功能:

定时器0溢出中断

63*****************************************************************/64voidtimer0_overflow(void)interruptTIMER0_OVERFLOW

65{

66u8i;

67u8p1_value=0;

68staticu8state=0;//点阵状态(扫描行数)

69staticu8count=0;

70

71staticu8wave_state=0;//波形状态

72staticu16wave_count=0;

73

74TR0=0;

75

76//每中断1000次,改变波形状态

77wave_count++;

78if(wave_count==1000)

79{

80wave_count=0;

81wave_state++;

82wave_state%=16;

83}

84

85//每中断64次,改变扫描的行

86count++;

87if(count==64)

88{

89state++;

90state%=8;

91count=0;

92}

93

94if(count

95{

1P0=Wave;

2}

3else

4{

5P0=0xFF;

6}78//输出位码

9p1_value=P1&0xf8;

10p1_value|=state;

11P1=p1_value;

12

13//定时器重新赋值

14TH0=0xFF;

15TL0=0xF7;

16TR0=1;

17}

L6

(6).波形表,共16个状态,每个状态下有8个数据,即一个点阵界面。

扫描点阵时循环发送,实现动态效果。

L6(77-83).每中断1000次,更换一个状态。

L6(86-101).和L5的功能一致,只是点阵段码输出的数据变成了波形表。

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高等教育 > 哲学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1