linux中应使用systemd服务而非rc.local或cron并行控制gpio:为每个任务创建独立.service文件,通过after=dev-gpio.device确保硬件就绪,并在脚本中安全导出引脚、设方向、写值。

Linux 本身没有“并行执行开关量”这种抽象概念;所谓“开关量”在工业控制或嵌入式场景里,通常指 GPIO 引脚的高低电平状态(如 echo 1 > /sys/class/gpio/gpio12/value)。你要的其实是:在系统启动时,并行执行多个控制 GPIO 或其他硬件资源的脚本。关键不是“开关量”,而是“并行执行 + 启动时机 + 硬件访问权限”。
为什么不能直接用 rc.local 并行调用?
很多人把多个 ./script1.sh &、./script2.sh & 塞进 /etc/rc.local,看似并行,实则隐患极多:
-
/etc/rc.local在 systemd 中默认由rc-local.service托管,该服务Type=oneshot,不等待子进程结束就标记完成 —— 导致你写的&实际上脱离了启动上下文,容易被 systemd 杀掉或失去日志归属 - GPIO 操作依赖
sysfs接口(如/sys/class/gpio/),而该接口在early阶段未必已导出引脚;过早执行会报错write error: Device or resource busy或No such file or directory - 多个脚本同时写同一 GPIO(比如都操作
gpio12)可能产生竞态,没加锁就会翻车
systemd 服务中如何真正并行启动多个硬件脚本?
正确做法是:为每个开关控制任务定义独立的 .service 文件,用 WantedBy=multi-user.target 统一激活,让 systemd 自动调度并行 —— 它比手动 & 更可靠、可监控、可依赖。
- 每个脚本对应一个 service,例如
/etc/systemd/system/gpio-led-red.service:
[Unit] Description=Set GPIO LED red ON After=dev-gpio.device # 确保 GPIO 设备节点已就绪(需提前 export) <p>[Service] Type=oneshot ExecStart=/usr/local/bin/set-gpio.sh 12 1 RemainAfterExit=yes</p><p>[Install] WantedBy=multi-user.target</p>
- 同理建
gpio-led-green.service、gpio-relay-1.service等,各自指定不同引脚和值 - 所有 service 启用后:
sudo systemctl enable gpio-led-red.service gpio-led-green.service gpio-relay-1.service - systemd 会自动并行启动它们(只要没显式声明
Before=/After=依赖)
脚本里怎么安全操作 GPIO?
直接 echo 到 sysfs 是最轻量的方式,但必须处理三件事:导出、方向、值。别跳步。
- 确保引脚已 export(否则
/sys/class/gpio/gpio12/不存在):
#!/bin/bash
PIN=$1
VALUE=$2
<h1>导出引脚(仅当未导出时)</h1><p>if [ ! -d "/sys/class/gpio/gpio${PIN}" ]; then
echo ${PIN} > /sys/class/gpio/export 2>/dev/null || true</p><h1>等待 udev 创建目录(短延时防 race)</h1><p>sleep 0.05
fi</p><h1>设为输出模式(必须!否则 write value 会失败)</h1><p>echo out > /sys/class/gpio/gpio${PIN}/direction 2>/dev/null</p><h1>写值</h1><p>echo ${VALUE} > /sys/class/gpio/gpio${PIN}/value 2>/dev/null</p>
- 路径必须用绝对路径:
/bin/bash开头,echo用/bin/echo更稳妥(启动时$PATH极简) - 加
2>/dev/null避免因重复 export 或权限问题中断整个 service - 不要用
sudo—— systemd service 默认以 root 运行,加 sudo 反而报错
@reboot cron 和 rc.local 的坑在哪?
这两个机制看似简单,但对硬件初始化类任务几乎不可靠:
-
@rebootcron 任务在用户 session 启动后才运行,此时内核模块、GPIO 子系统可能尚未完全就绪;且 cron 不保证 root 权限下能访问/sys/class/gpio/(取决于 cron 的上下文) -
/etc/rc.local在 systemd 下实际是rc-local.service,它默认After=network.target,但不保证dev-gpio.device已 ready —— 你看到脚本“执行了”,但echo 1 > ...返回 silent fail - 两者都无法做失败重试、状态追踪、依赖声明 —— 一个 GPIO 没设上,你根本不知道
真正要稳,就得用 systemd 的依赖模型:用 After=dev-gpio.device、Wants=dev-gpio.device 显式声明硬件准备就绪后再执行,而不是靠 sleep 或运气。











