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

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

3天内不再提示

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

GReq_mcu168 来源:玩转单片机 2019-11-26 14:28 次阅读

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

最简单的一个 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
    +关注

    关注

    240

    文章

    23134

    浏览量

    658387
  • 流水灯
    +关注

    关注

    21

    文章

    432

    浏览量

    59634

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

文章出处:【微信号:mcu168,微信公众号:硬件攻城狮】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    亚马逊开发智能眼镜助力送货司机

    近日,据知情人士透露,亚马逊正在为其送货司机开发款智能眼镜,旨在通过提供精准的导航建议,缩短送货时间,提升送货效率。 据悉,这款智能眼镜将为送货司机提供沿途和每个站点的转向建议导航
    的头像 发表于 11-12 11:15 442次阅读

    虹科免拆诊断 | 2016 款宾利GT车仪表盘上的多个故障点亮

    2016款宾利GT车仪表盘上的多个故障点亮上海永达汽车集团有限公司张非凡故障现象故障诊断故障排除辆2016款宾利欧陆GT车,搭载CYCB发动机,累计行驶里程约为4.5万km。据车主反映,发动机
    的头像 发表于 09-26 08:03 254次阅读
    虹科免拆诊断 | 2016 款宾利GT车仪表盘上的多个故障<b class='flag-5'>灯</b><b class='flag-5'>点亮</b>

    2016款保时捷Macan车发动机故障异常点亮

    2016款保时捷Macan车发动机故障异常点亮杭州捷盛行汽车服务有限公司乐翔故障现象故障诊断故障排除辆2016款保时捷Macan车,搭载CYP发动机,累计行驶里程约为11.2万km。车主进厂反映
    的头像 发表于 07-11 08:09 378次阅读
    2016款保时捷Macan车发动机故障<b class='flag-5'>灯</b>异常<b class='flag-5'>点亮</b>

    dsp28335点程序

    点亮个小
    发表于 07-09 11:50 2次下载

    STM32L496-discovery生成的LED无法点亮是什么原因?

    板子是STM32L496-discovery。用网上教程使用stmcube生成LED点亮实验,无法点亮。但用L496自带的GPIO程序运行却可以点亮。不知道什么原因,请大神解答。
    发表于 04-28 08:01

    自定义系统时钟频率后,用库函数和微带两种方式点亮LED,为什么的闪烁频率不致?

    写了个自定义系统时钟频率的函数,然后自定义系统时钟频率为28MHz,在这个频率下用库函数和微带两种方式点亮LED,为什么的闪烁频率不
    发表于 03-25 21:45

    动力底盘域的“小步”,智能汽车的“大步”

    不懂汽车“新三大件”,别再自称“司机
    的头像 发表于 03-25 09:21 3097次阅读
    动力底盘域的“<b class='flag-5'>一</b>小步”,智能汽车的“<b class='flag-5'>一</b>大步”

    智慧杆:点亮智慧城市,构建未来生活

    随着城市化进程的加速和科技的不断创新,智慧城市建设已经成为当今社会发展的重要趋势。作为智慧城市建设的重要组成部分,智慧杆以其独特的功能和优势,正逐渐融入我们的日常生活中,点亮智慧城市,构建未来生活。
    的头像 发表于 03-20 17:35 265次阅读
    智慧<b class='flag-5'>灯</b>杆:<b class='flag-5'>点亮</b>智慧城市,构建未来生活

    TC387配置Autosar OS后主核跑飞了怎么解决?

    使用TC387芯片配置Autosar OS发现主核跑飞了,其他核正常运行OS任务切换,PC指针指向_IF_CONST区域,D[4]寄存器为1,D[15]寄存器为4,根据这两个寄存器用计算规则计算出的TCN和TIN好像有问题,在Trap中跑飞,请问下,
    发表于 03-06 08:24

    在STM32CubeIDE1.14.1开发环境中,创建点亮LED工程,在Debug时遇到报错怎么解决?

    在STM32CubeIDE1.14.1开发环境中,创建点亮LED工程,在Debug时遇到报错:Error message from debugger back end: localhost:61234: Connection timed out.求
    发表于 03-06 08:07

    智慧杆:点亮未来城市的领航者

    智慧杆是种集智能科技和照明功能于体的创新产品,正逐渐成为现代城市建设的热门选择。它们不仅能够为城市提供高效能的照明服务,还通过智能化的控制系统,实现了对城市环境、交通、市政、设施的全面监测
    的头像 发表于 03-04 14:33 294次阅读
    智慧<b class='flag-5'>灯</b>杆:<b class='flag-5'>点亮</b>未来城市的领航者

    2017款长安福特翼虎车发动机故障异常点亮

    2017款长安福特翼虎车发动机故障异常点亮作者:余姚东江名车专修厂叶正祥故障现象故障诊断故障排除辆2017款长安福特翼虎车,搭载CAF488WQ9发动机,累计行驶里程约为8.9万km。该车因
    的头像 发表于 01-20 08:08 983次阅读
    2017款长安福特翼虎车发动机故障<b class='flag-5'>灯</b>异常<b class='flag-5'>点亮</b>

    更换编码器不当引起飞车的具体原因?

    想问下各位更换编码器不当引起飞车的具体原因?是什么原理呢?不明白,郁闷中。。。。
    发表于 12-28 07:28

    采集到的ADIS16477-2的imu数据,测试陀螺、加速度计的漂移非常大怎么解决?

    我现在采集到的ADIS16477-2的imu数据,测试陀螺、加速度计的漂移非常大,IMU是放在台面上镜子不动的。 下图第一排陀螺x、y、z的原始数据,第二分别是5s钟平滑后的数据。 下图第一排
    发表于 12-28 07:25

    智慧杆:点亮未来的智慧之光

    随着科技的不断发展,智慧城市已经逐渐成为现实。作为智慧城市建设的重要组成部分,智慧杆的推广应用正逐渐被各地市政部门所重视。智慧杆不仅仅是杆,更是
    的头像 发表于 12-04 16:13 425次阅读
    智慧<b class='flag-5'>灯</b>杆:<b class='flag-5'>点亮</b>未来的智慧之光