65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 Arduino 模拟和控制 GE 彩色效果灯

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.80/5 (13投票s)

2011年11月7日

CPOL

13分钟阅读

viewsIcon

147359

downloadIcon

1393

使用 Arduino 模拟和控制 GE 彩色效果灯。

Simulator screen shot

概述

本项目构建了一个 GE Color Effects 灯的圣诞灯控制器,允许编程控制多达 8 套圣诞灯。此外,它还提供了一种特定于功能的语言,用于对这些灯光进行编程,以及一个用于测试需要组装或悬挂灯光的程序的仿真环境。

预读

Arduino - 如果您从未听说过 Arduino,那么我建议您查看他们的网站。他们设计和销售一款开源微处理器平台,非常适合那些电子技术经验有限的人构建可编程的电子小工具。

GE Color Effects - 这可能是最酷的黑客圣诞灯了。每个灯泡都包含一个红色、绿色和蓝色的 LED,并且可以通过单条数据线发送指令来单独或成组控制。关于它们是什么以及它们如何工作的描述,请查看这篇文章,其中还提供了 Robert Quattlebaum (darco) 反向工程的基本控制信息。同时,您也可以在 Youtube 上搜索一些使用微处理器和这些灯光进行演示的精彩视频(那棵有十串灯的圣诞树绝对令人难以置信)。

引言

本文由硬件项目和 3 个程序组成

  • 硬件项目使用 Arduino Mega 2560 来控制多达八套灯光。
  • 第一个程序是在 Arduino Mega 上运行以控制灯光的固件。它通过读取一组指令来实现此目的,这些指令以每串灯的短整数数组的形式表示,用于告诉固件要生成什么灯光模式。固件也可以交叉编译并在 PC 上运行,在那里它们可以完成相同的任务,但会控制一个灯光仿真器。在 PC 上,我使用 VC++ 的 Express 版本进行编译。
  • 第二个程序是灯光仿真器。它将模拟一套或多套灯光,并根据您所需的布局在屏幕上排列它们。当您在 PC 上运行固件时,该固件会将指令发送到仿真器,仿真器将显示灯光的外观。我使用 VC# 的 Express 版本进行编译。
  • 最后一个程序是一个编译器(或者更准确地说是一个汇编器),它接受更高级的指令集并生成固件所需的短整数数组,以告知固件如何处理灯光。我使用 VC# 的 Express 版本进行编译。

此图让您对整个工作流程有所了解...

Block diagram

要尝试这个,您不需要 Arduino 也不需要构建任何硬件... 编译器、固件(为 PC 构建)和仿真器都可以在您的 PC 上运行。

硬件

我通过移除隔离电路并采用多适配器的共地配置,极大地简化了硬件设计。我曾担心这会引起问题,但似乎效果还不错。

在我第一个原型中,我使用了 Arduino Pro。它很便宜而且效果很好,但我很快就遇到了内存问题,因为它只有 2KB 的 RAM。即使经过多次重构以最小化内存使用,我发现控制 1 到 2 套灯光时仍然内存不足。所以,我升级到了 Arduino Mega 2560,拥有 8KB RAM。仍然很少,但如果您的内存使用非常节省,并且将所有静态数据(如指令)放入更慷慨的 256KB 闪存中,那就足够了。

Color Effects 灯配有一个 3A 5V 适配器,足以运行 2 串灯。8 串灯需要 4 个适配器和 7.5V 适配器来运行 Arduino。该电路还包括一些关键元件,使其易于使用/测试。

  • 一个重置按钮,可以重置程序...由于它不会切断灯光的电源,因此它不会重置任何灯泡寻址问题,因此有时您仍然需要断开电源。
  • 2 个调试按钮。在开机时按住这些按钮(单独或一起),可以将设备置于 3 种调试模式之一。
  • 一个电源 LED,显示 Arduino 已通电。
  • 一个错误 LED,用于标记错误和其他条件。
  • 一个进度 LED,在程序运行时闪烁,表明一切正常。
  • 这是完整的接线图。

    Wiring diagram

    这就是装在一个漂亮的盒子里面的所有东西。Arduino 在左下角可见。

    Picture of completed hardware

    还值得对灯光本身做一些评论。每串灯有 50 个灯泡。灯泡地址在初始化期间建立,使用我的固件意味着它们将始终按从控制器到末尾的顺序编号 0...49(但不必如此)。每个灯泡都可以单独控制颜色和亮度。还可以使用广播命令到虚幻的灯泡 63 来控制亮度。灯泡控制协议涉及沿数据线发送高低电压模式。每个高/低电平持续 10 微秒,完整的单个灯泡命令需要 820 微秒。

    编译器

    如上所述,编译器实际上更像是一个汇编器,除了某些变量命名和跳转测量外,它基本上是用一些数字替换一些符号,并生成一个数据文件和一个用于固件的 `.h` 文件。

    指令集非常简单,并在下载文件中的 TidlyWiki HTML 文件中有详细解释,因此我只在这里介绍基本知识。

    指令是与一串灯泡相关的简单指令。

    // set bulbs 0..9 red and bright
    SetColour
    0
    9
    red
    bright
    
    // set bulbs 10 to yellow and 19 to blue and graduate bulbs 11..18
    SetFadeColour
    10
    19
    yellow
    blue
    bright
    
    donothing
    1

    指令按周期执行。所有指令在同一个周期内执行,直到遇到 `donothing` 或 `loop` 指令。

    有些指令跨越多个周期。这些命令在多个周期内显示一个效果,例如逐渐改变颜色或亮度,甚至移动灯泡。

    // rotate bulbs 10..19 1 bulb to the right 50 times
    RotateBulbs
    10
    19
    1
    50
    1
    1

    控制多串灯时,您为每串灯定义一个单独的程序。在执行时,周期进度是集中控制的,即所有 `string` 在程序进入周期 2 之前完成其周期 1 命令。通过仔细编写,您可以跨多串灯泡同步图案。包含的一些预构建示例显示了这一点。秘诀是确保每个程序都有相同数量的周期。

    编译器为每个程序发出一个 `.dat` 文件。这些文件由固件在 PC 上运行时使用,允许您在无需为每次测试重新编译固件的情况下测试程序。

    编译器还发出一个单独的 `.h` 文件。这个 `.h` 文件包含多达 8 个程序,并在部署到 Arduino 之前编译到固件中。您真的只需要在最后,当您对程序在仿真器中的外观满意时才这样做。

    要编译,只需将 1 到 8 个程序文件传递给编译器。第一个传递的文件被视为 `.h` 文件中的程序 0。

    编译器还理解一些通用概念,并具有代表它们的关键字,以使程序更具可读性。例如 `NOCOLOR`、`LASTBULB`、`YES`、`NO` 等关键字。这些都在 `TiddlyWiki` 文件中涵盖。

    仿真器

    仿真器最多可模拟八套灯光。它通过在屏幕上显示小圆圈作为灯泡来实现这一点,然后根据 PC 上运行的固件收到的指令对其进行着色。固件通过使用 TCP/IP 连接与仿真器通信。使用的地址保存在 `tcpip.txt` 文件中。默认情况下是回环适配器 127.0.0.1,但也可以是网络上的另一台机器。

    仿真器还可以通过串行链接直接从连接的 Arduino 获取输入。您可以通过模拟器上的菜单并包含 `gloabl.h` 文件中的适当 #defines 来设置此项。这会大大减慢程序速度,并且通常不需要,除非在尝试调试我的固件时。在此模式下运行时,您甚至可以监控 Arduino 的可用内存。

    仿真器可以布局灯泡,以表示它们在房屋上是如何串起来的。要做到这一点,只需编辑 `house.xlsm` 文件并生成一个 `output.xml` 文件,该文件可以替换 `GELightsSimulator.xml` 文件,使用您自己的布局。

    固件... 在 PC 上运行时

    固件的核心在 PC 和 Arduino 上运行相同。但是,在 PC 上运行时,内存显然不是主要问题,因此 PC 版本会进行更多的错误检查并提供广泛的跟踪消息,这有助于您解决程序中的问题。这是通过代码中大量使用 `#ifdef PC` 预编译器指令来实现的。它还将所有内容记录到 LOG 文件中,可以检查该文件以解决时序问题。

    在 PC 上运行时,固件将尝试查找正在运行的仿真器实例。如果找不到,它将从当前文件夹启动一个。固件还将查找作为命令行参数传递的一个或多个 `.dat` 文件,并将它们视为要运行的程序。如果未找到,则将运行任何内部编译的 `program.h`。

    固件... 在 Arduino 上运行时

    在 Arduino 上运行时,固件运行的是精简版本。内存使用量以及因此的验证等都很少。Arduino 的 11 号引脚是您将收到的唯一错误消息,它将仅设置为高电平,并且在遇到问题时程序将停止。许多问题甚至不会被检测到... 程序只是无法按预期工作。我强烈建议先在 PC 上进行测试。

    Arduino 的 13 号引脚将随着程序在程序周期中进行而高/低交替。这表明程序正在运行。

    我必须承认,在 Arduino SDK 中设置和运行代码时我有点作弊。太想尽快弄清楚所有内容,所以我只是将所有类放入了一个库中,其余部分放在示例目录的一个文件夹中。我使用一个批处理文件将其从我进行 PC 开发的文件夹复制到 Arduino 编译器的文件夹中。

    最小化内存使用

    当我第一次编写固件时,即使是简单的命令序列也无法运行,因为它会耗尽内存。PC 拥有数 GB 的 RAM 确实会让您在内存利用率方面变得懒惰。在我最初的迭代中,所有内容都是整数,程序始终以列表的形式保存在内存中,而像旋转灯泡这样的命令会保留自己的灯泡工作副本。

    为了减小内存使用量,进行了以下更改:

    • 静态数据已移至闪存... 没有理由为从不更改的数据使用 RAM。Arduino 需要特殊的声明和访问协议才能使其正常工作。
    • 使用字节和短整数而不是整数来最小化浪费的字节。
    • 灯泡颜色的未使用位被用来隐藏状态标志,以避免添加字节。
    • 指令仅在需要时即时构建,并在完成后立即销毁。
    • 错误检查和验证在很大程度上被移除。
    • 需要临时副本的命令被最小化,并且仅在需要时分配。
    • 在管理灯泡时,使用了指针算法而不是指针数组。这节省了大量内存。

    这增加了代码大小和复杂性,并稍微减慢了程序速度,但降低内存使用的好处使其值得。

    程序中最占用内存的组件是跟踪每串灯泡中 50 个灯泡的状态。不幸的是,这是无法避免的邪恶,因为不可能查询物理灯泡的状态。指令通常依赖于它们理解灯泡状态的能力,然后才能决定新状态,因此必须对其进行跟踪。

    时序

    将 16MHz 的 Arduino 与对信号时序如此敏感的设备进行接口是一个巨大的挑战。Color Effects 正在寻找一个持续 10 微秒的高/低电平。任何超过一微秒的偏差都可能导致灯光出现异常行为。

    在我最初的 Arduino Pro 原型机中,每次输出后休眠 7 微秒效果很好。当我转到 Arduino Mega 时,这必须减少到 4 微秒,即便如此,我仍然会偶尔出现错误的灯泡亮起... 引入进一步的 3 微秒精炼(如果发送的信号与最后一个信号相同)以避免累积信号延迟问题。

    唯一可以解决这个问题的方法是使用逻辑分析仪。

    2012 年版本增加了并行输出选项,但默认情况下未启用,因为我遇到了我没有时间解决的时序问题。这些问题可能会在未来的版本中得到解决。

    指令集

    决定在指令集中包含或排除哪些内容始终是一个挑战。基本指令非常明显,理论上仅使用 `SetColour` 和 `DoNothing` 指令就可以构建任何模式,但更复杂的模式将非常冗长且几乎不可能调试,因为它们的体积太大。添加更复杂的指令可以实现一些相当酷的效果,而无需编写笨拙的程序,但这些指令本身都相当大,而且通常内存消耗很大。每次我想出一个想要显示的模式时,总是会问:我需要一个新指令,还是有办法让现有指令集完成我想要的功能?总的来说,我认为它是差不多的,但如果您决定添加一个新指令来处理一个复杂模式比试图让现有指令集完成您想要的功能更容易,我也不会感到惊讶。

    添加新指令需要修改编译器,以便能够识别新指令。这通常只是在命令数组中添加一行,并在解码表中添加一些关键字。您还需要在 `instructions.cpp` 文件中添加一个继承自 `Instruction` 类的新类,并实现所需的重写函数。基本上,`Construct` 方法初始化指令,`Execute` 方法执行指令的一个周期。您需要添加成员变量来跟踪指令在周期之间的状态。仿真器应该不需要更改,因为它对指令一无所知...它只知道如何显示灯泡。

    结论

    我还能说什么呢,编程这些设备让我想起了我的 Z80 汇编器编程时代... 内存几乎为零,CPU 很慢,但用它们完成的事情令人惊叹。

    历史

    • v1.0 2011 年 11 月
    • v1.1 2011 年 11 月 - 修复了 Loop 指令中的内存泄漏
    • v1.2 2011 年 12 月 - 修复了 6N137 引脚标签
    • v2.0 2012 年 11 月 - 主要重写,包括
      • 添加了跨字符串变量 - 有关详细信息,请参阅下载文件中的 Manual.html。
      • 添加了灯泡消息的并行输出,但由于时序问题默认禁用。
      • 添加了子例程以最小化代码大小。
      • 改进了内存利用率。
      • 添加了 Raspberry Pi 支持,但由于缺乏 RTOS Linux 映像导致问题,影响了信号时序。
      • 模拟器消息转换为 TCP/IP 和串行端口,支持远程调试,包括 Arduino 内存使用监视。
      • 代码重构,将大多数可选编译设置放在 Global.h 中。
      • 代码重构,将大多数平台特定代码放在一个平台类中。

    改进机会

    修复并行消息。

    修复 Raspberry Pi 实现。

© . All rights reserved.