Arduino 接线草图和库可在 Visual Studio 内复制/粘贴到 Arduino 接线项目,并在 Raspberry Pi 2、Raspberry Pi 3 或 Minnowboard Max 上运行。 有时需要对这些文件稍作修改,以便使它们与 Windows 环境或你正在使用的板更兼容。 本指南将介绍这些修改以及你可能会在部署 Arduino 接线项目时遇到的常见问题。
移植
更新引脚
不言而喻,许多草图和库(尤其是用于 Arduino 防护的草图和库)可能包含对 Arduino 设备的特定连接器引脚的引用。 你将要自定义你的草图来针对你正在处理的设备和你正在使用的配置使用相应的连接器引脚。
Arduino 接线最终需要引用“引脚”的任何函数的物理连接器引脚编号。 你可以直接使用这些编号,不过我们还提供了一些对应于特定板上的连接器引脚的预定义引脚名称。
例如,Raspberry Pi 2 和 3 上的物理连接器引脚 29 也称为 GPIO5。 你可以通过使用以下任一命令在 Raspberry Pi 2 和 3 上将 GPIO 引脚 5 设置为 HIGH 状态:
pinMode( 29, OUTPUT );
digitalWrite( 29, HIGH );
或
pinMode( GPIO5, OUTPUT );
digitalWrite( GPIO5, HIGH );
预定义引脚名称可以在 pins_arduino.h 中找到,并包含在某个 Arduino 接线项目中,但由于物理连接器引脚因你进行生成所针对的硬件设置而异,因此我们还在此处包含了一个表,用于介绍每台设备可以使用哪些引脚名称。
Raspberry Pi 2 和 3

| 引脚定义 | 相应的引脚编号 |
|---|---|
| LED_BUILTIN | 板载 LED |
GPIO* where * refers to [0, 27] |
请参考引出线图 |
| GCLK | 7 |
GEN* where * refers to [0, 5] |
*请参考引出线图 |
| SCL1 | 5 |
| SDA1 | 3 |
| CS0(或者 CE0 或 SS) | 24 |
| CS1(或 CE1) | 26 |
| SCLK(或 SCK) | 23 |
| MISO | 21 |
| MOSI | 19 |
| RXD | 10 |
| TXD | 8 |
Minnowboard Max

| 引脚定义 | 相应的引脚编号 |
|---|---|
GPIO* where * refers to [0, 9] |
请参考引出线图 |
| SCL | 13 |
| SDA | 15 |
| CS0(或者 CE0 或 SS) | 5 |
| SCLK(或 SCK) | 11 |
| MISO | 7 |
| MOSI | 9 |
| CTS1 | 10 |
| RTS1 | 12 |
| RX1 | 8 |
| TX1 | 6 |
| RX2 | 19 |
| TX2 | 17 |
常见问题
在 Visual Studio 中找不到“Arduino 接线应用程序”Visual C++ 项目模板
原因: 未安装适用于 Visual Studio 的 Windows IoT 项目模板扩展。
解决方案: 你必须先安装适用于 Windows IoT 项目模板的 Visual Studio 扩展才能在 Visual Studio 中创建 Arduino 接线项目。 转到 Windows IoT 核心版项目模板扩展页面来从 Visual Studio 库下载该扩展!
错误:在调用某个函数时“找不到标识符”
原因: 当调用尚未在文档中声明的函数时,在链接器过程中会发生此错误。
解决方案: 在 C++ 中,所有函数都必须在调用前进行声明。 如果你已在草图文件中定义了新函数,该函数的声明或完整实现必须在任何调用它的尝试上方(通常在文档顶部)。
示例:
以下代码块将引发错误“‘myFunction’:找不到标识符”
void setup()
{
}
void loop()
{
myFunction();
}
void myFunction()
{
//do something
}
有两种解决方案。 首先,你可以在任何调用上方声明该函数。 通常,此声明在文件顶部完成。
// Declare function here
void myFunction();
void setup()
{
}
void loop()
{
myFunction();
}
// And, define the function here
void myFunction()
{
//do something
}
或者,也可以将函数的整个实现移到任何调用上方。 这会导致同时声明和定义该函数。
void setup()
{
}
void myFunction()
{
//do something
}
void loop()
{
myFunction();
}
我的解决方案在初始化时无限期挂起
存在可能导致 C++ 解决方案在初始化时无限期挂起(死锁)的已知问题。 如果你发现你的解决方案看起来永久挂起,并且你无法使用调试器“闯入”Arduino 接线应用程序的 setup() 或 loop() 部分中的任何声明,则可能遇到此类型的问题。
原因: 在解决方案完成初始化前创建了某个对象或调用了某个函数,从而导致异步操作。 这可能由对象的构造函数调用 pinMode 等 API 函数所导致。
解决方案: 将任何对象构造函数和函数调用从代码的初始化部分中移开,并移到 setup() 块中。
示例 1:
在解决方案本身完成初始化前,此草图的执行会调用称为 setPinModes() 的函数。 解决方案将显示为执行,但会无限期挂起。
bool setPinModes();
int pin = GPIO5;
bool initialized = setPinModes();
void setup()
{
}
void loop()
{
if( initialized )
{
//do something
}
}
bool setPinModes()
{
if( pin < 0 ) return false;
pinMode( pin, OUTPUT );
return true;
}
解决方案如下,我们仅仅将 setPinModes() 的执行移到 setup() 函数:
bool setPinModes();
int pin = GPIO5;
bool initialized;
void setup()
{
initialized = setPinModes();
}
void loop()
{
if( initialized )
{
//do something
}
}
bool setPinModes()
{
if( pin < 0 ) return false;
pinMode( pin, OUTPUT );
return true;
}
示例 2:
在调用 setup() 前,此草图的执行会在堆栈上创建一个对象。 由于对象在其构造函数中调用 pinMode,这还会导致死锁。 这不是常见问题,但可能在来自某些库(如 Arduino LiquidCrystal 库)的对象上发生。
class MyObject
{
public:
MyObject()
{
pinMode( GPIO5, OUTPUT );
}
void doSomething()
{
//...
}
};
MyObject myObject;
void setup()
{
}
void loop()
{
myObject.doSomething();
}
解决方案如下。 我们已将对象更改为对象指针,并将对象的初始化移到了 setup()。
class MyObject
{
public:
MyObject()
{
pinMode( GPIO5, OUTPUT );
}
void doSomething()
{
//...
}
};
MyObject *myObject;
void setup()
{
myObject = new MyObject();
}
void loop()
{
myObject->doSomething();
}
使用 Serial.print() 和 Serial.println()
许多 Arduino 草图使用 Serial 将数据打印到串行控制台(如果打开)或写入串行线(USB 或 tx/rx)。
以前版本的 Lightning SDK 不包含硬件 Serial 支持,因此我们提供了一个 Log() 函数,用于将数据输出到 Visual Studio 中的调试程序输出窗口。 必须删除 Serial.print*() 或 Serial.write()。
但是,从 Lightning SDK v1.1.0 开始,我们添加了 Hardware Serial 支持,并且完全支持 Serial.print*() 或 Serial.write() 函数。 因此,如果要复制为 Arduino 生成的草图,你不需要在该草图的 Windows IoT 版本中替换其中任何串行引用。
除了写入到硬件串行引脚之外,我们还扩展了 Serial.print() 和 Serial.println() 的功能,以便在连接了调试程序时输出到调试程序窗口。
调试输出发送设置为默认输出,因为在运行草图时,大多数用户都需要读取该输出。 但是,也可以禁用该功能;例如,为了提高性能,只需调用 Serial.enablePrintDebugOutput(false); 即可在草图中禁用它。 要重新启用它,请调用 Serial.enablePrintDebugOutput(true);。 写入到硬件串行引脚不受这些调用的影响。
请注意,不需要将任何外设连接到串行引脚(例如 FTDI),即可获取发送到调试程序窗口的输出。 但是,你需要确保在调试应用程序时调试程序窗口处于打开状态。

Windows IoT 核心版“项目模板扩展”页面上的项目模板已更新,以允许使用现成可用的硬件 Serial。 但是,如果你的 Arduino 接线应用程序是使用较旧项目模板版本创建的,则需要执行以下操作:1) 将项目升级到 Lightning SDK v1.1.0 或更高版本;2) 添加所需的硬件串行设备功能,以使 AppxManifest 能够使用 Serial。
硬件串行设备功能要求
Windows 10 IoT 核心版中的硬件串行功能要求向 AppX 清单添加设备功能声明。
通过在解决方案资源管理器中键入文件名,找到项目中的 Package.appxmanifest 文件。 然后,右键单击该文件并选择“打开方式…”。 选择“XML(文本)编辑器”,然后单击“确定”。

在 appx 清单文件编辑器中,将 serialcommunication 设备功能添加到项目中,如以下 XML 代码片段所示:
<Capabilities>
<Capability Name="internetClient" />
<!-- General Arduino Wiring required capabilities -->
<iot:Capability Name="lowLevelDevices" />
<DeviceCapability Name="109b86ad-f53d-4b76-aa5f-821e2ddf2141"/>
<!-- The serialcommunication capability is required to access Hardware Serial. -->
<DeviceCapability Name="serialcommunication">
<Device Id="any">
<Function Type="name:serialPort"/>
</Device>
</DeviceCapability>
</Capabilities>
将项目升级到最新 Lightning SDK
Arduino 接线项目依赖 Lightning SDK NuGet 包来实现所需的 Arduino 接线功能和声明,并与 Lightning 驱动程序交互。 最新 Lightning SDK 将包含最新的改进和 Bug 修复。 要升级到最新 Lightning SDK,请执行以下步骤:
- 在解决方案资源管理器中,右键单击相关项目文件夹,然后单击“管理 NuGet 包…”
- 在 NuGet 包管理器中,转到“已安装”选项卡。你应该会看到 Microsoft.IoT.Lightning 包已安装
- 可用版本将在“版本”组合框内列出。
- 选择最新版本,然后单击“更新”以更新你的包。
- 请注意,要升级到预发行版本,请务必同时选中“包括预发行版”复选框。
