文档结构  
翻译进度:已翻译     翻译赏金:0 元 (?)    ¥ 我要打赏

SwiftyGPIO

这是一个用于跟 Linux 的 GPIOs/SPI/PWM 进行交互的 Swift 库,例如可用来做 LED 灯闪灯等控制。

总结

该 Swift 库利用数字 GPIOs、SPI 接口和 PWM 信号提供了一种简单的方式与外部传感器和设备进行交互,支持 Linux 系统。

你可以配置端口属性,读写当前 GPIOs 值,使用 SPI 接口(使用主板提供的硬件支持或者软件 big-banging SPI)并生成一个 PWM 去驱动外部显示、传感器、LED 灯等各种传感器。

该库只支持提供可访问 GPIO是的 Linux ARM 主板(如树莓派、BeagleBone Black, UDOO, Tegra, CHIP 等等) 。

第 1 段(可获 1.38 积分)

从 0.8 版本开始 SwiftyGPIO 就使用 Swift 3.0, 而 Swift 2.x 的用户可以使用 专有的分支 来获取源码和文档。

目录:

支持的主板

已通过测试:

  • C.H.I.P.
  • BeagleBone Black (Thanks to @hpux735)
  • Raspberry Pi 2 (Thanks to @iachievedit)
  • Raspberry Pi 3
  • Raspberry Pi Zero (Thanks to @MacmeDan)
  • Raspberry Pi A,B Revision 1
  • Raspberry Pi A,B Revision 2
  • Raspberry Pi A+, B+
  • OrangePi (Thanks to @colemancda)
  • OrangePi Zero (Thanks to @eugeniobaglieri)
  • UDOOs
第 2 段(可获 1.25 积分)

下列主板没有经过测试,但应该是可以使用(共同特点 ARMv7/Ubuntu14/Raspbian 或者 ARMv6/Raspbian):

  • BananaPi
  • OLinuXinos
  • ODROIDs
  • Cubieboards
  • Tegra Jetson TK1

安装

你需要一个 Linux ARM 主板,Swift 3+ 才能使用这个库。

如果你有 RaspberryPi (A,B,A+,B+,Zero,ZeroW,2,3) 装有 Ubuntu 或者 Raspbian 系统,那么可以从 这里 下载 Swift 3.0.2 并根据文章中的帮助信息链接构建脚本库来自行构建(或者参考 1, 2, 3, 4) 。

最新预编译的 ARMv7 二进制文件可以从 Joe build server 获取,如果是 Ubuntu 16.04 可以在 这里 找到。

第 3 段(可获 1.46 积分)

Ubuntu 二进制版本同样也可以支持 BeagleBoneBlack, C.H.I.P. 或者其他任何 ARMv6/ARMv7 主板。

如果你的 Swift 版本支持 SPM,则只需在 Package.swift 中添加 SwiftyGPIO 依赖:

let package = Package(
    name: "MyProject",
    dependencies: [
        .Package(url: "https://github.com/uraimo/SwiftyGPIO.git", majorVersion: 0),
        ...
    ]
    ...
)

然后使用 swift build 进行构建。

这个编译器将会在 .build/ 目录下生成可执行文件。

如果你的 Swift 不支持 Swift Package Manager,则需要手工下载所有必需的文件:

第 4 段(可获 0.91 积分)
wget https://raw.githubusercontent.com/uraimo/SwiftyGPIO/master/Sources/SwiftyGPIO.swift https://raw.githubusercontent.com/uraimo/SwiftyGPIO/master/Sources/Presets.swift https://raw.githubusercontent.com/uraimo/SwiftyGPIO/master/Sources/SunXi.swift

一旦下载完毕,请在相同的目录下创建一个名为 main.swift 的额外文件包含你的应用代码。

当代码就绪,使用如下命令进行编译:

swiftc *.swift

编译欧将会生成一个 main 的可执行文件。

重要提示: 当任何应用通过 sysfs/mmapped 寄存器与 GPIOs 进行交互时,如果你的操作系统没有一个预定义的用户组来访问这些功能,你就需要使用 root 权限来运行程序(sudo ./main)。如果你正在使用装有最新版 Raspbian(2016年11月发布)的树莓派,或者一个最新的 Ubuntu (至少是 16.04 Xenial 或者更新版本),就不需要 root 的权限,只需要通过 ./main 命令来启动应用接口。但在一些其他系统中,例如侦听器的特性可能会需要 root 的权限。

第 5 段(可获 1.44 积分)

此外,手工为 gpio 访问指定一个用户组的方法可以访问 这里 或者是 stackoverflow.遵循文章所说的步骤进行操作,记住要将你的用户添加到 gpio 组中,使用命令 sudo usermod -aG gpio pi 然后重启来让修改生效。

首个项目:LED 和传感器闪烁

如果你更喜欢开始一个真正的项目而不是阅读文档,如果你正在使用 Swift 3.0 以及最新版本的 SwiftyGPIO, Cameron Perry has a great step by step guide 这篇文章将教你配置一个支持 Swift 的树莓派,并连接有一个 LED 灯和一个温度传感器。

第 6 段(可获 1.45 积分)

如果你仍然在使用 Swift 2.x ,想体验 SwiftyGPIO 的话可以使用专门为 2.x 准备的分支版本。来自 iachieveedit 的 Joe 写了一个 非常棒的教程 可以解释那些你需要知道的内容。

更多的教程可以访问 中文, 日本語 和 Tiếng Việt.

使用

当前 SwiftyGPIO 输出了 GPIOs, SPIs(如果不可用的话就会创建一个 bit-banging VirtualSPI ) 和 PWMs,接下来让我们来看看如何使用这些方法。

GPIO

假设我们正在使用树莓派2主板,连接了一个 LED 灯在 GPIO P2 引脚上(可能带一个 1K 欧的电阻),以及 GND 接地。

第 7 段(可获 1.45 积分)

首先,我们需要获取主板上所有可用的 GPIOs,然后获得我们将要修改的其中一个的引用:

let gpios = SwiftyGPIO.GPIOs(for:.RaspberryPi2)
var gp = gpios[.P2]!

如果是我们支持的主板,那么获得的值可能是下列的内容:

  • .RaspberryPiRev1 (Pi A,B Revision 1, pre-2012, 26 pin header)
  • .RaspberryPiRev2 (Pi A,B Revision 2, post-2012, 26 pin header)
  • .RaspberryPiPlusZero (Raspberry Pi A+ and B+, Raspberry Zero, all with a 40 pin header)
  • .RaspberryPi2 (Raspberry Pi 2 or 3 with a 40 pin header)
  • .BeagleBoneBlack (BeagleBone Black)
  • .CHIP (the $9 C.H.I.P. computer).
  • .BananaPi (RaspberryPi clone)
  • .OrangePi
第 8 段(可获 1.18 积分)

GPIOs(for:) 返回的 map 对象包含了主板上所有的 GPIOs 信息,这些信息在 这些图表 中有详细的描述。

另外,如果主板不支持,那么我们需要手工的初始化每一个 GPIO 对象,可使用其 SysFS GPIO Id:

var gp = GPIO(name: "P2",id: 2)  // User defined name and GPIO Id

接下来是配置端口数据传输方向,可以是 GPIODirection.IN 和 GPIODirection.OUT,在这里我们选择 .OUT:

gp.direction = .OUT

然后将针脚的值设置为高电平,值为 “1”:

gp.value = 1

这样,LED 灯就亮了。

现在加上我们有一个开关连接到 P2,为了读取 P2 端口的输入值,数据传输方向必须设置为 .IN 然后就可以直接读取 value 属性来获得开关的状态:

第 9 段(可获 1.39 积分)
gp.direction = .IN
let current = gp.value

GPIO 对象的其他属性 (edge,active low) 指向了 GPIO 的额外可配置信息,但这些信息绝大多数的情况下都用不上。详细的属性信息请访问 kernel documentation

GPIOs 同时支持在引脚读数更改时执行闭包函数。闭包可以添加到 onRaising (引脚读数从 0 变成 1), onFalling (引脚读数从 1 变成 0) 以及 onChange (引脚读数发生变化):

let gpios = SwiftyGPIO.GPIOs(for:.RaspberryPi2)
var gp = gpios[.P2]!

gp.onRaising{
    gpio in
    print("Transition to 1, current value:" + String(gpio.value))
}
gp.onFalling{
    gpio in
    print("Transition to 0, current value:" + String(gpio.value))
}
gp.onChange{
    gpio in
    gpio.clearListeners()
    print("The value changed, current value:" + String(gpio.value))
}
第 10 段(可获 1.06 积分)

这个闭包要求接收一个唯一参数就是 GPIO 对象的引用,这样就不需要使用外部变量。调用 clearListeners() 可以移除所有侦听的闭包并禁用改动的处理方法。当 GPIOs 做好更新的检查,引脚的 direction 属性就不能被修改(和作为 .IN 进行配置),但一旦侦听函数被清除,不管是在闭包内还是其他地方,你就可以随意修改。

SPI

如果你的主板提供 SPI 连接,SwiftyGPIO 就有其预设的信息,可用的 SPIs 列表可以通过调用 hardwareSPIs(for:) (或者 getHardwareSPIsForBoard for Swift 2.x) 来获取。

第 11 段(可获 1.4 积分)

在树莓派和其他主板中,硬件 SPI SysFS 接口默认是不启用的,配置的方法请阅读 wiki.

让我们来看看使用树莓派2 的一些例子,树莓派2拥有一个双向的 SPI,可使用 SwiftyGPIO 作为两个单向的 SPIObjects 进行管理:

let spis = SwiftyGPIO.hardwareSPIs(for:.RaspberryPi2)
var spi = spis?[0]

返回的第一项是输出频,可通过 SPIObject 对象的 isOut 方法来进行识别。

此外,我们可以使用两个 GPIOs 来创建一个软件的 SPI,一个用来处理时钟引脚,另外一个用来发送实际数据。这种 bit-banging SPI 比硬件 SPI 要慢一些,推荐的方法是如果可以的话尽可能使用硬件 SPI。

第 12 段(可获 1.39 积分)

为了创建一个软件 SPI,只需要获取两个引脚,并创建一个 VirtualSPI 对象:

let gpios = SwiftyGPIO.GPIOs(for:.RaspberryPi2)
var sclk = gpios[.P2]!
var dnmosi = gpios[.P3]!
var spi = VirtualSPI(dataGPIO:dnmosi,clockGPIO:sclk)

这些对象都实现了相同的 SPIObject 协议,因此提供了相同的方法。为了区分不同的硬件和软件 SPIObjects ,可以使用 isHardware 方法来判断。

为了通过 SPI 发送一个或者多个字节数据,可以使用 sendData 方法。其最简单的调用方式是传递一个 UInt8 数组作为参数:

spi?.sendData([UInt(42)])

但对于软件 SPIs 而言(从现在开始,这些值在硬件 SPI 中都是被忽略的),你也可以指定一个首选的字节顺序 (MSB,LSB) 和两个连续比特之间的延迟(时钟宽度,默认是 0):

第 13 段(可获 1.2 积分)
spi?.sendData([UInt(42)], order:.LSBFIRST, clockDelayUsec:1000)

PWM

PWM 的输出信号可用于驱动例如伺服马达、RGB LED 灯等设备, 当你只有数字 GPIO 端口时用来生成类似模拟信号输出。

如果你的主板提供并支持 PWM 端口(目前只有树莓派提供),就可以通过 hardwarePWMs 工厂方法获得可用的 PWMOutput 对象:

let pwms = SwiftyGPIO.hardwarePWMs(for:.RaspberryPi2)!
let pwm = (pwms[0]?[.P18])!

该方法访问所有支持 PWM 函数的端口列表,根据控制它们的 PWM 频道进行分组。

第 14 段(可获 0.95 积分)

每个频道你只能使用一个端口,考虑到树莓派相关的板子只提供了两个频道,因此你可以同时使用两个 PWM 输出通道,例如 GPIO12 和 GPIO13 或者 GPIO18 和 GPIO19.

一旦你获取到端口对应的 PWMOutput 对象,就需要对之进行初始化,选择 PWM 函数。在这种主板上,每个端口可以有一个或者多个函数 (简单 GPIO, SPI, PWM, 等等…) 然后你可以为你想要进行配置的专用的寄存器选择函数。

pwm.initPWM()

要开始 PWM 信号调用,需要调用 startPWM 并提供以纳秒为单位的期间参数(需要做 1/频率的转换)和以百分比提供的占空比数据。

第 15 段(可获 1.5 积分)
print("PWM from GPIO18 with 500ns period and 50% duty cycle")
pwm.startPWM(period: 500, duty: 50)

一旦你调用了该方法,ARM SoC 的 PWM 子系统将启动并开始生成信号,你不需要做任何其他事情,程序会自动的执行,你可以插入一个 sleep(seconds) 语句来进行休眠。

当你想要停止 PWM 信号时,调用 stopPWM() 方法即可:

pwm.stopPWM()

如果你想要修改正在生成的信号,无需停止之前的信号生成器,只需要使用不同的参数调用 startPWM 即可。

这个特性使用 M/S 算法,并且从 300 纳秒到 200 毫秒的这段期间测试成功,如果要生成的信号超过这个范围,可能会导致过度抖动,这对某些程序来说是不可接受的。如果你需要生成某种信号已经达到该范围的极限,最好手头准备一台示波器,对生成的信号进行验证。

第 16 段(可获 1.93 积分)

示例

不同板子的示例程序都放置在 Examples 目录下,你只需要简单修改就可以开始使用。

下面是 C.H.I.P. 板子的例子,用来显示当前所有的 GPIO0 的属性值,修改 Direction 和 Value 并重新显示属性值试试:

let gpios = SwiftyGPIO.GPIOs(for:.CHIP)
var gp0 = gpios[.P0]!
print("Current Status")
print("Direction: "+gp0.direction.rawValue)
print("Edge: "+gp0.edge.rawValue)
print("Active Low: "+String(gp0.activeLow))
print("Value: "+String(gp0.value))

gp0.direction = .OUT
gp0.value = 1

print("New Status")
print("Direction: "+gp0.direction.rawValue)
print("Edge: "+gp0.edge.rawValue)
print("Active Low: "+String(gp0.activeLow))
print("Value: "+String(gp0.value))
第 17 段(可获 0.7 积分)

这第二个例子制作一个闪烁频率为 150 毫秒的 LED 等:

import Glibc

let gpios = SwiftyGPIO.GPIOs(for:.CHIP)
var gp0 = gpios[.P0]!
gp0.direction = .OUT

repeat{
    gp0.value = (gp0.value == 0) ? 1 : 0
    usleep(150*1000)
}while(true)

我们无法使用 CHIP 测试硬件 SPI ,但 SwiftyGPIO 就可以,它提供了一个实现了 SPI 接口的软件,你只需要两个 GPIO 来初始化即可:

let gpios = SwiftyGPIO.GPIOs(for:.CHIP)
var sclk = gpios[.P0]!
var dnmosi = gpios[.P1]!

var spi = VirtualSPI(dataGPIO:dnmosi,clockGPIO:sclk) 

pi.sendData([UInt8(truncatingBitPattern:0x9F)])
第 18 段(可获 0.54 积分)

注意到我们使用了构造器 UInt8(truncatingBitPattern:) 来将 0x9F 转成 Int 数值,这并不是实际需要的,但仍推荐对每个用户提供的数值或者是计算的整数进行转换,因为 Swift 不支持隐私的将数值截断成更小的整数类型,如果你尝试进行转换的 Int 值无法填充到 UInt8 上,那么程序就会崩溃。

SwiftyGPIO 构建

一些项目和库构建时需要 SwiftyGPIO。如果你可以分享一些你已经构建的项目,请让我们知道。

第 19 段(可获 1.99 积分)

推荐项目

额外文档

更多的关于该项目的文档请看 docs 目录。

第 20 段(可获 1.19 积分)

文章评论