0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

教教大家如何花式点亮一排灯

0BFC_eet_china 来源:未知 作者:李倩 2018-05-02 09:05 次阅读

在上一期的“教你花式点灯”中,我们已经教会了大家如何将一颗灯点到极致。而点灯到这里还没有完哦,这次给大家来点进阶的小课程,来教教大家如何花式点亮一排灯。快快上车,老司机准备起飞了!

最简单的一个 LED 的实验之后,自然是增加几个 LED,咱排成一排来玩吧。最后,再把一排的 LED 排成一个 8 字来玩——七段数码管

流水灯一—— 跑马灯

第一个出场的肯定是经典的流水灯,也叫跑马灯

流水灯二—— 端口整体操作

再试流水灯,这里换一个端口整体操作,感受到更简洁没?

流水灯三—— 74HC959 扩展 IO 口

又是流水灯!这次使用 74HC595 来扩展 IO 口。对于 arduino 来说,IO 口资源是很紧张的,迟早会遇到不够用的时候,这时候就需要扩展。使用 74HC595 是一种比较常见的方案。

雨滴拖尾效果流水灯

不好意思,还是流水灯。这次模拟得更真实一点,加上水滴的拖尾效果。

首先是简单的方法,使用 uno 的六个 pwm 口来实现。

1.// ----------------------------------------------------------------------------

2.// raindropLEDS.ino

3.//

4.// Created 2015-06-04

5.// By seesea

6.//

7.// 雨滴流动效果

8.// 雨滴流动效果与流水灯(跑马灯)的区别在于雨滴流水效果有拖尾效果,即亮过的灯是慢慢熄灭的

9.//

10.// 使用 UNO 的六个 PWM 引脚实现雨滴流动的效果

11.// UNO 的六个 PWM 引脚为 pin 3 5 6 9 10 11,这几个脚分别接 6 个 LED 正极,LED 负极接 GND

12.//

13.// ----------------------------------------------------------------------------

14.

15.const unsigned char pins[] = { 3, 5, 6, 9, 10, 11 }; // 六个 pwm 引脚

16.const unsigned char initPwm= 240; // 最亮的灯的 pwm 值,即移动的时候在最头一个灯的亮度

17.const unsigned char deltaPwm = 10; // 灯慢慢熄灭的 pwm 值,后一个灯比前一个灯暗多少。这相当于是一个等差队列。等差的亮度感觉不大好,所以引入下一个等比的因素

18.const unsigned char deltaPercent = 30; // 后一个灯比前一个灯暗,其亮度是前一个灯的百分之几。相对于前面的递减,这个相当于是等比级数

19.const unsigned long delayMs= 100; // 移动延迟,单位 ms

20.const unsigned char pinNum = sizeof(pins) / sizeof(pins[0]);// 引脚数量,即 LED 个数

21.

22.unsigned char ledPwm[pinNum]; // 存放运行时每一个 LED 的亮度 PWM 值

23.

24.void setup()

25.{

26. for (char i = 0; i < pinNum; ++i)

27. {

28. pinMode(pins[i], OUTPUT);

29. ledPwm[i] = 0;

30. }

31.}

32.

33.void loop()

34.{

35. static unsigned char head = 0;

36.

37. // 每一次进入 loop() 函数都对所有的灯亮度进行处理

38. for (unsigned char i = 0; i < pinNum; ++i)

39. {

40. ledPwm[i] = ledPwm[i] * deltaPercent / 100;

41. if (ledPwm[i] <= deltaPwm)

42. ledPwm[i] = 0;

43. else

44. ledPwm[i] -= deltaPwm;

45.

46. if (i == head)

47. ledPwm[i] = initPwm;

48.

49. analogWrite(pins[i], ledPwm[i]);

50. }

51.

52. // 移动水滴头

53. head = (head + 1) % pinNum;

54.

55. // 延时

56. delay(delayMs);

57.}

雨滴拖尾效果流水灯二——数字 IO 口模拟

前面只有 6 个 PWM 口实在是不过瘾啊,来,我们把所有的 IO 口都用上,包括模拟口,它也是可以作为数字 IO 口使用的。

1.// ----------------------------------------------------------------------------

2.// digitalRaindropLEDS.ino

3.//

4.// Created 2015-06-04

5.// By seesea

6.//

7.// 数字引脚实现的雨滴流动效果

8.// 雨滴流动效果与流水灯(跑马灯)的区别在于雨滴流水效果有拖尾效果,即亮过的灯是慢慢熄灭的

9.//

10.// 使用 UNO 的所有引脚用模拟 PWM 实现雨滴流动的效果,包括模拟输入口也可以用做数字输出

11.// 各引脚接 LED 正极,LED 负极接 GND

12.// ----------------------------------------------------------------------------

13.

14.const unsigned char leds[] = { A5, A4, A3, A2, A1, A0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 }; // 所有的引脚按 LED 接线顺序排列

15.const unsigned int maxPwm = 100; // 手工模拟 PWM,可以自己定义最大的 PWM 值是多少,所以定义一个整百整千的数比较方便计算

16.const unsigned int initPwm = 100; // 最亮的灯的 pwm 值,即移动的时候在最头一个灯的亮度

17.const unsigned int deltaPwm = 1; // 灯慢慢熄灭的 pwm 值,后一个灯比前一个灯暗多少。这相当于是一个等差队列。等差的亮度感觉不大好,所以引入下一个等比的因素

18.const unsigned int deltaPercent = 70; // 后一个灯比前一个灯暗,其亮度是前一个灯的百分之几。相对于前面的递减,这个相当于是等比级数

19.const unsigned long delayMs = 70; // 移动延迟,单位 ms

20.const unsigned char ledNum = sizeof(leds) / sizeof(leds[0]);// 引脚数量,即 LED 个数

21.

22.unsigned int ledPwm[ledNum]; // 存放运行时每一个 LED 的亮度 PWM 值

23.

24.void setup()

25.{

26. for (char i = 0; i < ledNum; ++i)

27. {

28. pinMode(leds[i], OUTPUT);

29. ledPwm[i] = 0;

30. }

31.}

32.

33.extern volatile unsigned long timer0_millis; // 声明外部变量 timer0_millis 以便在程序中使用,其实就是 millis() 的返回值——程序运行的毫秒数

34.void loop()

35.{

36. static unsigned char head = 0;

37. static unsigned long lastTick = timer0_millis;

38. unsigned int i, j;

39.

40. // 先亮灯,等占空比到切换点的时候灭灯

41. for (i = 0; i < ledNum; ++i)

42. {

43. if (ledPwm[i] == 0)

44. continue;

45.

46. digitalWrite(leds[i], HIGH);

47. }

48.

49. // 水滴头是最亮的

50. ledPwm[head] = initPwm;

51.

52. // 这里就是数字口模拟的 PWM 程序了

53. for (i = 0; i < maxPwm; ++i)

54. {

55. for (j = 0; j < ledNum; ++j)

56. {

57. if (i == ledPwm[j])

58. digitalWrite(leds[j], LOW);

59. }

60.

61. delayMicroseconds(1);

62. }

63.

64. // 如果延时时间还没到,先跳出,不进行水滴的移动

65. // 由于是用数字口模拟的 PWM,程序要不停的跑,不能使用 delay() 来延时,会卡住的

66. if (timer0_millis - lastTick < delayMs)

67. return;

68.

69. lastTick = timer0_millis;

70.

71. // 处理每一个灯的亮度

72. for (i = 0; i < ledNum; ++i)

73. {

74. ledPwm[i] = ledPwm[i] * deltaPercent / 100;

75. if (ledPwm[i] <= deltaPwm)

76. ledPwm[i] = 0;

77. else

78. ledPwm[i] -= deltaPwm;

79.

80. if (i == head)

81. ledPwm[i] = initPwm;

82. }

83.

84. // 移动水滴头

85. head = (head + 1) % ledNum;

86.}

POV摇摇棒是时候舞起来了,摇起来吧。

1.// ----------------------------------------------------------------------------

2.// povLEDS.ino

3.//

4.// Created 2015-05-31

5.// By seesea

6.//

7.// 摇摇棒

8.//

9.// pin 0 - 7 接 LED 正极,LED 负极接 GND

10.// pin 8 接水银开关一脚,水银开关另一脚接 GND

11.// 水银开关水平于摇动方向固定放置。如果实际效果与预想效果水平相反,只要把水银开关两脚的接线互换就可以了

12.// 注意:由于 pin 0 1 通过 LED 接地了,下载的时候需要断开才能下载成功

13.// ----------------------------------------------------------------------------

14.

15.const unsigned char key = 8; // 水银开关

16.const unsigned char delayTimeMs = 2; // 扫描时LED的点亮延时

17.

18.// 取模软件使用纵向8点上高位的方式取模

19.unsigned char col[] =

20.{

21. // 心

22. // 0x30,0x48,0x44,0x22,0x44,0x48,0x30,0x00

23.

24. // I 心 U

25. 0x82,0xFE,0xFE,0x82,0x00,0x30,0x78,0x7C,

26. 0x3E,0x7C,0x78,0x30,0x00,0xFC,0xFE,0x02,

27. 0x02,0xFE,0xFC,0x00,0x00,0x00

28.

29. /* 1 2 3

30. 0x00,0x42,0xFE,0x02,0x00,0x00,0x00,0x00,

31. 0x46,0x8A,0x92,0x92,0x62,0x00,0x00,0x00,

32. 0x84,0x82,0x92,0xB2,0xCC,0x00

33. */

34.};

35.

36.unsigned char cols = (sizeof(col) / sizeof(col[0]));

37.

38.void setup()

39.{

40. DDRD = 0xFF;

41. pinMode(key, INPUT_PULLUP);

42.}

43.

44.void loop()

45.{

46. char i = 0;

47. char keyValue = digitalRead(key);

48. char delta = 1;

49.

50. if (keyValue == 1) // 摇动方向由右向左的时候

51. {

52. // 这里可以尝试两种方案

53. // 一种是向左扫的时候熄灭所有灯

54. // 另一种是反向点亮各列,从而由于方向也是反的,显示就变回正的

55. // 根据需要,把 if 条件改成 0 或 1 可以选择不同的方案

56. // 第一种方案的优点是不容易有重影,但缺点是亮度低

57. // 第二种方案的优缺正好相反

58. if (0)

59. {

60. // 向左摇熄灭所有灯

61. i = 0;

62. PORTD = 0x00;

63.

64. // 如果选择这种方案就不需要继续下面的扫描了,return掉即可

65. return;

66. }

67. else

68. {

69. delta = -delta;

70. }

71. }

72.

73. if (delta == 1)

74. {

75. // 向右摇的时候

76. for (i = 0; i < cols; ++i)

77. {

78. PORTD = col[i];

79. delay(delayTimeMs);

80. }

81. }

82. else

83. {

84. // 向左摇的时候

85. for(i = cols - 1; i >= 0; --i)

86. {

87. PORTD = col[i];

88. delay(delayTimeMs);

89. }

90. }

91.}

接线图我觉得得上一下,效果图嘛,从几百张照片里挑个好看的来:

静态数码管显示

总站成一排多无聊,是时候改改造行了。现在排成 8 字吧。先点亮一个 8 字,用静态显示方法。

1.// ----------------------------------------------------------------------------

2.// static7segLEDS.ino

3.//

4.// Created 2015-06-06

5.// By seesea

6.//

7.// 静态七段数码管

8.// 使用 PORTD 静态显示七段数码管,循环显示 0 - F

9.//

10.// 这里使用的是共阳七段数码管,如果使用共阴的,只要把段码表取反即可

11.// 数码管段的顺序按如下标示排列

12.//

13.// A

14.// ---

15.//F| G |B

16.// ---

17.//E| D |C

18.// ---. DP

19.//

20.// 然后根据需要显示的数字生该段点亮输出 1,可以制作段码表。这种方式做出来的是共阴的,所以使用的时候取反即为共阳的段码

21.// +---+--+--+--+--+--+--+--+--+-----+

22.// | | A| B| C| D| E| F| G|DP| 段码|

23.// +---+--+--+--+--+--+--+--+--+-----+

24.// | 0 | 1| 1| 1| 1| 1| 1| 0| 0| 0xFC|

25.// +---+--+--+--+--+--+--+--+--+-----+

26.// | 1 | 0| 1| 1| 0| 0| 0| 0| 0| 0x60|

27.// +---+--+--+--+--+--+--+--+--+-----+

28.// | 2 | 1| 1| 0| 1| 1| 0| 1| 0| 0xDA|

29.// +---+--+--+--+--+--+--+--+--+-----+

30.// | 3 | 1| 1| 1| 1| 0| 0| 1| 0| 0xF2|

31.// +---+--+--+--+--+--+--+--+--+-----+

32.// | 4 | 0| 1| 1| 0| 0| 1| 1| 0| 0x66|

33.// +---+--+--+--+--+--+--+--+--+-----+

34.// | 5 | 1| 0| 1| 1| 0| 1| 1| 0| 0xB6|

35.// +---+--+--+--+--+--+--+--+--+-----+

36.// | 6 | 1| 0| 1| 1| 1| 1| 1| 0| 0xBE|

37.// +---+--+--+--+--+--+--+--+--+-----+

38.// | 7 | 1| 1| 1| 0| 0| 0| 0| 0| 0xE0|

39.// +---+--+--+--+--+--+--+--+--+-----+

40.// | 8 | 1| 1| 1| 1| 1| 1| 1| 0| 0xFE|

41.// +---+--+--+--+--+--+--+--+--+-----+

42.// | 9 | 1| 1| 1| 1| 0| 1| 1| 0| 0xF6|

43.// +---+--+--+--+--+--+--+--+--+-----+

44.// | A | 1| 1| 1| 0| 1| 1| 1| 0| 0xEE|

45.// +---+--+--+--+--+--+--+--+--+-----+

46.// | B | 0| 0| 1| 1| 1| 1| 1| 0| 0x3E|

47.// +---+--+--+--+--+--+--+--+--+-----+

48.// | C | 0| 0| 0| 1| 1| 0| 1| 0| 0x1A|

49.// +---+--+--+--+--+--+--+--+--+-----+

50.// | D | 0| 1| 1| 1| 1| 0| 1| 0| 0x7A|

51.// +---+--+--+--+--+--+--+--+--+-----+

52.// | E | 1| 0| 0| 1| 1| 1| 1| 0| 0x9E|

53.// +---+--+--+--+--+--+--+--+--+-----+

54.// | F | 1| 0| 0| 0| 1| 1| 1| 0| 0x8E|

55.// +---+--+--+--+--+--+--+--+--+-----+

56.// ----------------------------------------------------------------------------

57.

58.// 共阳段码表 0 - F

59.const unsigned char segTable[] = {

60. ~0xFC, ~0x60, ~0xDA, ~0xF2, ~0x66, ~0xB6,

61. ~0xBE, ~0xE0, ~0xFE, ~0xF6, ~0xEE, ~0x3E,

62. ~0x1A, ~0x7A, ~0x9E, ~0x8E

63. };

64.

65.void setup()

66.{

67. DDRD = 0xFF; // PORTD 设置为输出

68.}

69.

70.void loop()

71.{

72. for (char i = 0; i < sizeof(segTable) / sizeof(segTable[0]); ++i)

73. {

74. PORTD = segTable[i];

75. delay(500);

76. }

77.}

动态数码管显示

上面是一位数码管的显示,可以使用静态,如果要显示多位,那可得动起来了。

1.// ----------------------------------------------------------------------------

2.// dynamic7segLEDS.ino

3.//

4.// Created 2015-06-06

5.// By seesea

6.//

7.// 动态七段数码管

8.// 动态显示七段数码管,从 0000 开始计数,9999 后回 0

9.//

10.// 使用 PORTD 进行段选,使用 pin 8 9 10 11 进行位选

11.// ----------------------------------------------------------------------------

12.

13.#define COM_ON HIGH// 共阳数码管启用的公共端电平

14.#define COM_OFF LOW // 共阳数码管禁用的公共端电平

15.

16.// 共阳段码表 0 - F

17.const unsigned char segTable[] = {

18. ~0xFC, ~0x60, ~0xDA, ~0xF2, ~0x66, ~0xB6,

19. ~0xBE, ~0xE0, ~0xFE, ~0xF6, ~0xEE, ~0x3E,

20. ~0x1A, ~0x7A, ~0x9E, ~0x8E

21.};

22.

23.const unsigned char pinPos[] = { 8, 9, 10, 11 }; // 位选管脚,按从低位到高位的排列

24.const unsigned intinitNum= 0; // 计数初始值

25.const unsigned intmaxNum = 9999; // 最大计数

26.const unsigned char com_num= sizeof(pinPos) / sizeof(pinPos[0]);// 公共端的数量,用于确定有几位

27.const unsigned long delayMs= 50; // 动态扫描延迟时间

28.

29.void setup()

30.{

31. DDRD = 0xFF; // PORTD 设置为输出

32. for (char i = 0; i < sizeof(pinPos) / sizeof(pinPos[0]); ++i)

33. {

34. pinMode(pinPos[i], OUTPUT);

35. }

36.}

37.

38.// 于七段数码管上显示数字 num

39.// 将 num 数字的个十百千等各位的数字一位一位分离出来显示到每一位数码管上

40.void display7segLED(unsigned int num)

41.{

42. unsigned int digital;

43. for (unsigned char i = 0; i < com_num; ++i)

44. {

45. digital = num % 10;

46. num /= 10;

47.

48. PORTD = segTable[digital];

49. digitalWrite(pinPos[i], COM_ON);

50.

51. delayMicroseconds(10);

52. digitalWrite(pinPos[i], COM_OFF); // 传说中的消隐,避免发生重影

53. }

54.}

55.

56.void loop()

57.{

58. static unsigned long lastTick = millis();

59. static unsigned intnum = initNum;

60.

61. display7segLED(num);

62.

63. // 动态扫描,不能用 delay 阻塞式的延迟哦,前面试验过的这种用法现在派上用场了

64. if (millis() - lastTick < delayMs)

65. return;

66.

67. lastTick = millis();

68. ++num;

69. if (num >= maxNum)

70. num = initNum;

71.}

都学会了嘛~还没看过瘾?!

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • led
    led
    +关注

    关注

    237

    文章

    22444

    浏览量

    645838
  • 流水灯
    +关注

    关注

    21

    文章

    432

    浏览量

    59103

原文标题:Arduino点灯玩成这样,也是没谁了

文章出处:【微信号:eet-china,微信公众号:电子工程专辑】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    做个器件,用一排二极管来显示电流的大小,如何实现?...

    本人想做个器件,就是用一排二极管来显示电流的大小。该支路电流大,则二极管亮的个数多,支路电流小,则二极管亮的个数少。请问各位大侠,如何实现此功能,需要用芯片么?
    发表于 01-13 20:16

    LED点亮问题

    请教大家,汽车LED,日间行车灯点亮,怎么设计啊?
    发表于 11-14 20:27

    想做个用MSP430控制的花式,用什么元件比较好呢?

    想做个用MSP430控制的花式、、
    发表于 04-30 10:51

    LCD1602为什么显示一排黑格???

    大家好,我是个单片机初学者。最近在做个多功能电子万年历。我在网上已经用PROTUES仿真成功了,但是用面包板连好硬件图之后LCD1602上只是第二行显示一排黑色的小方格,请问
    发表于 11-09 16:56

    哪位大虾告诉我,这个按键板上的这一排是什么电子元件?

    哪位大虾告诉我,这个按键板上的这一排是什么电子元件?
    发表于 08-10 18:34

    求大神帮忙请教 贴片二极管丝印 第一排 S4 ;第二 79A。 这是什么二级管,坏的了,不知道型号

    贴片二极管丝印 第一排 S4;第二 79A。 这是什么二级管,坏的了,不知道型号。谢谢
    发表于 03-15 10:11

    lcd1602拔掉后重新上电就只会显示一排方格

    各位大神,为什么我的1602如果把P30,P31插在烧录器上然后上电就会显示,中通拔掉P30,P31也会显示,但拔掉后重新上电就只会显示一排方格。(程序上P3口定义为标准IO口,P30、P31没有外接电路)
    发表于 01-10 18:39

    从TQFP144测试座引出引脚,中间那一排引脚不知道如何处理?

    `我需要从IC201-1444-026-2中引出线出来,但是位置却不够走线,这种情况可以怎么处理,我将外面的一排设置成单面的孔,让中间一排的从孔之间的位置出来可以么?`
    发表于 03-19 15:15

    Altium中这一排孔怎么做到让1,2孔的距离是固定值?

    一排孔,我怎么做到让1,2孔的距离是固定值,其他过孔的间距和这两个
    发表于 08-16 03:26

    怎么快速选中Altium中这一排引脚?

    Altium这一排引脚我怎么快速选中
    发表于 09-10 05:35

    请问AD元件统一排放位置快捷键是什么?

    AD元件统一排放位置快捷键是多少
    发表于 09-30 04:30

    如何利用51单片机完成布置的LED花式闪烁?

    如何利用51单片机完成布置的LED花式闪烁?
    发表于 09-29 07:31

    使用定时器0定时定时间并在中断处理程序中执行代码分享

    实验任务: 使用定时器0定时定时间并在中断处理程序中执行代码 实现现象:LED1每隔0.5s亮灭变化次硬件接线:J14跳线帽拿掉,否则下面一排LED会点亮影响观察上面
    发表于 11-23 06:59

    教教大家如何花式点亮一排

    又是流水灯!这次使用 74HC595 来扩展 IO 口。对于 arduino 来说,IO 口资源是很紧张的,迟早会遇到不够用的时候,这时候就需要扩展。使用 74HC595 是一种比较常见的方案。
    的头像 发表于 03-23 09:07 7862次阅读
    来<b class='flag-5'>教教</b><b class='flag-5'>大家</b>如何<b class='flag-5'>花式</b><b class='flag-5'>点亮</b><b class='flag-5'>一排</b>灯

    教教大家如何花式点亮一排灯,老司机准备起飞了!

    又是流水灯!这次使用 74HC595 来扩展 IO 口。对于 arduino 来说,IO 口资源是很紧张的,迟早会遇到不够用的时候,这时候就需要扩展。使用 74HC595 是一种比较常见的方案。
    的头像 发表于 11-26 14:28 4290次阅读
    <b class='flag-5'>教教</b><b class='flag-5'>大家</b>如何<b class='flag-5'>花式</b><b class='flag-5'>点亮</b><b class='flag-5'>一排</b>灯,老司机准备起飞了!