最完整Nerves实战指南:用Elixir构建工业级嵌入式系统
你还在为嵌入式开发烦恼吗?
嵌入式开发长期面临三大痛点:开发效率低下(C/C++编译周期长)、系统稳定性差(内存泄漏、崩溃)、远程维护难(现场调试成本高)。Nerves框架的出现彻底改变了这一现状——它将Elixir的开发效率、Erlang VM的高可用性与Linux的硬件兼容性完美结合,让你能用函数式编程构建 robust(坚固级)的嵌入式系统。
读完本文你将掌握:
- 从零搭建Nerves开发环境(支持Windows/macOS/Linux)
- 3分钟创建第一个Elixir嵌入式项目
- 固件烧录与远程调试全流程
- 硬件外设控制(GPIO/I2C/SPI)实战
- 工业级部署最佳实践
Nerves核心优势解析
Nerves不是传统意义上的Linux发行版,而是一个专为嵌入式场景优化的Elixir运行时环境。它直接将Erlang VM作为系统核心进程启动,摒弃了传统Linux的庞大用户态组件,同时保留了Linux内核的硬件驱动能力。
技术架构全景图
与传统方案核心差异
| 特性 | Nerves(Elixir) | 传统嵌入式(C/C++) | 树莓派系统(Python) |
|---|---|---|---|
| 开发效率 | 热重载+交互式调试 | 编译-烧录循环(分钟级) | 脚本便捷但规模受限 |
| 系统稳定性 | 故障隔离+自动重启 | 内存泄漏风险高 | 全局解释器锁限制 |
| 并发处理 | 轻量级进程(百万级) | 线程/进程(千级) | 多线程受限 |
| 远程管理 | OTA更新+SSH内置 | 需手动实现 | 第三方工具拼凑 |
| 硬件兼容性 | 基于Linux内核 | 直接硬件访问 | 依赖系统驱动 |
| 代码体积 | 最小10MB | 最小KB级 | 数百MB系统+应用 |
开发环境搭建(全平台指南)
系统要求检查清单
- 操作系统:Windows 10+ (WSL2) / macOS 10.13+ / Linux(x86_64/arm64)
- Elixir版本:1.18.3+ (OTP 27)
- 硬件空间:至少20GB空闲磁盘空间
- 网络环境:可访问国内CDN(用于依赖下载)
分平台安装步骤
macOS (Homebrew)
# 安装系统依赖
brew update && brew install fwup squashfs coreutils xz pkg-config
# 安装asdf版本管理器
git clone https://gitee.com/mirrors/asdf.git ~/.asdf --branch v0.14.0
echo '. $HOME/.asdf/asdf.sh' >> ~/.zshrc
source ~/.zshrc
# 安装Erlang/Elixir
asdf plugin add erlang https://gitee.com/mirrors/asdf-erlang.git
asdf plugin add elixir https://gitee.com/mirrors/asdf-elixir.git
asdf install erlang 27.3.3
asdf install elixir 1.18.3-otp-27
asdf global erlang 27.3.3 elixir 1.18.3-otp-27
# 安装Nerves引导工具
mix archive.install hex nerves_bootstrap
Linux (Ubuntu/Debian)
# 安装系统依赖
sudo apt update && sudo apt install -y \
build-essential automake autoconf git squashfs-tools \
ssh-askpass pkg-config curl libmnl-dev libssl-dev \
libncurses5-dev help2man libconfuse-dev libarchive-dev
# 安装fwup
asdf plugin add fwup https://gitee.com/mirrors/asdf-fwup.git
asdf install fwup 1.10.2
asdf global fwup 1.10.2
# 后续步骤同macOS的asdf安装部分
Windows (WSL2)
# 管理员模式安装WSL2
wsl --install -d Ubuntu
# 在Ubuntu子系统内执行Linux安装步骤
# 然后在Windows侧安装fwup
choco install fwup
验证安装:重启终端后执行
mix nerves.info,应显示Nerves环境信息
3分钟创建第一个项目
项目初始化流程
# 创建项目(支持自动依赖安装)
mix nerves.new hello_nerves --install
# 进入项目目录
cd hello_nerves
# 设置目标硬件(以树莓派4为例)
export MIX_TARGET=rpi4
# 安装依赖(首次运行会下载系统镜像)
mix deps.get
支持的硬件目标:rpi0(树莓派Zero)、rpi3(树莓派3)、rpi4(树莓派4)、bbb(BeagleBone)、x86_64(通用PC)等10+官方平台
项目结构解析
hello_nerves/
├── lib/ # Elixir源代码
│ ├── hello_nerves.ex # 应用入口
│ └── hello_nerves/ # 业务模块
├── config/ # 配置文件
│ ├── config.exs # 通用配置
│ └── target.exs # 目标设备配置
├── mix.exs # 项目元数据
└── firmware/ # 构建产物
└── hello_nerves.fw # 固件文件
固件构建与烧录全流程
构建固件
# 编译项目并生成固件
mix firmware
# 查看固件信息
mix firmware.metadata
首次构建说明:首次构建会下载约500MB的系统镜像(缓存于~/.nerves/artifacts),后续构建时间<30秒
烧录到SD卡
# 自动检测并烧录(需插入SD卡)
mix firmware.burn
# 指定设备路径(推荐方式)
mix firmware.burn -d /dev/sdb # Linux
mix firmware.burn -d /dev/rdisk2 # macOS
烧录验证:烧录完成后,SD卡会显示两个分区:BOOT(引导区)和ROOTFS(根文件系统)
高级烧录选项
# 生成镜像文件(用于批量部署)
mix firmware.image --output hello_nerves.img
# 通过网络烧录(需设备已联网)
mix firmware.push nerves.local
设备连接与调试
多方式连接设备
| 连接方式 | 所需条件 | 操作命令 |
|---|---|---|
| USB串口 | USB-TTL线缆 | screen /dev/ttyUSB0 115200 |
| 网络SSH | 设备联网(默认nerves.local) | ssh nerves.local -l nerves |
| USB以太网 | USB数据线连接 | ssh nerves.local -l nerves |
| HDMI显示器 | HDMI线缆+键盘 | 直接操作IEx终端 |
IEx交互式调试
# 连接成功后将看到类似如下界面
Interactive Elixir (1.18.3) - press Ctrl+C to exit (type h() ENTER for help)
hello_nerves 0.1.0 (abc123) arm rpi4
iex(nerves@nerves.local)1>
# 查看系统信息
iex> Nerves.Runtime.KV.get_all()
# 控制GPIO(需添加circuits_gpio依赖)
iex> {:ok, led} = Circuits.GPIO.open(18, :output)
iex> Circuits.GPIO.write(led, 1) # 点亮LED
iex> Circuits.GPIO.write(led, 0) # 关闭LED
工具链扩展:运行
h Toolshed查看内置系统工具(支持ls、df、ping等命令)
硬件外设控制实战
GPIO控制LED闪烁
# 添加依赖(mix.exs)
defp deps do
[
{:circuits_gpio, "~> 2.0"}
]
end
# 代码实现(lib/hello_nerves/led.ex)
defmodule HelloNerves.LED do
@led_pin 18 # 树莓派GPIO18对应物理引脚12
def start_link(_opts) do
{:ok, led} = Circuits.GPIO.open(@led_pin, :output)
Process.put(:led, led)
schedule_toggle()
{:ok, pid} = Agent.start_link(fn -> :on end, name: __MODULE__)
{:ok, pid}
end
defp schedule_toggle do
Process.send_after(self(), :toggle, 1000) # 1秒切换一次状态
end
def handle_info(:toggle, state) do
led = Process.get(:led)
new_state = if state == :on, do: :off, else: :on
Circuits.GPIO.write(led, if new_state == :on, do: 1, else: 0)
schedule_toggle()
{:noreply, new_state}
end
end
I2C传感器数据读取
# 添加依赖
{:circuits_i2c, "~> 2.0"}
# 读取BME280温湿度传感器
defmodule HelloNerves.BME280 do
def read do
{:ok, ref} = Circuits.I2C.open("i2c-1") # 打开I2C总线
data = Circuits.I2C.write_read(ref, 0x76, <<0xD0>>, 1) # 读取设备ID
# 更多传感器操作代码...
end
end
网络配置与OTA更新
配置WiFi连接
# 添加依赖
{:vintage_net_wifi, "~> 0.13"}
# 配置(config/target.exs)
config :vintage_net,
config: [
{"wlan0", %{
type: VintageNetWiFi,
vintage_net_wifi: %{
networks: [
%{
ssid: "你的WiFi名称",
psk: "你的WiFi密码",
key_mgmt: :wpa_psk
}
]
},
ipv4: %{method: :dhcp}
}}
]
实现OTA更新
# 添加依赖
{:nerves_firmware_ssh, "~> 0.9"}
# 配置SSH密钥(config/target.exs)
config :nerves_firmware_ssh,
authorized_keys: [
File.read!(Path.expand("~/.ssh/id_rsa.pub"))
]
# 执行OTA更新(开发机)
mix firmware.push nerves.local
工业级部署最佳实践
系统安全加固
# 禁用root登录
config :nerves_ssh,
user: "nerves",
password: :disabled,
authorized_keys: [
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQ..." # 预配置授权密钥
]
# 配置防火墙
config :vintage_net,
firewall: [
allowed_ports: [22, 80, 443] # 只开放必要端口
]
系统监控与日志
# 添加依赖
{:ring_logger, "~> 0.8"}
# 配置日志持久化
config :logger,
backends: [RingLogger, {LoggerFileBackend, :error_log}],
logger_file_backend: [
path: "/root/error.log",
level: :error
]
# 在IEx中查看日志
RingLogger.tail() # 实时查看日志
RingLogger.save("/root/logs.txt") # 保存日志
示例项目与学习资源
官方示例项目
# 克隆示例仓库
git clone https://gitcode.com/gh_mirrors/ne/nerves_examples.git
# 常用示例
cd nerves_examples/blinky # LED闪烁(基础)
cd nerves_examples/hello_phoenix # Web界面(中级)
cd nerves_examples/livebook # 交互式开发(高级)
推荐学习路径
-
入门:Nerves Livebook(浏览器内交互式学习)
git clone https://gitcode.com/gh_mirrors/ne/nerves_livebook.git cd nerves_livebook MIX_TARGET=rpi4 mix deps.get firmware.burn -
进阶:Circuits库文档
- GPIO: https://hexdocs.pm/circuits_gpio
- I2C: https://hexdocs.pm/circuits_i2c
- SPI: https://hexdocs.pm/circuits_spi
-
实战:构建智能家居控制器
- 基于树莓派Zero W
- 支持WiFi和蓝牙
- 控制灯光、温湿度监测
常见问题解决
构建失败
| 错误信息 | 可能原因 | 解决方案 |
|---|---|---|
| 找不到工具链 | 目标平台未设置 | export MIX_TARGET=rpi4 |
| 依赖冲突 | Elixir版本不匹配 | 确认使用Elixir 1.18+ |
| 网络超时 | 依赖下载失败 | 配置代理:export HTTP_PROXY=... |
设备无法启动
- 检查电源:确保使用5V/2A电源适配器
- 验证SD卡:用
fsck检查文件系统 - 恢复出厂设置:重新烧录固件
社区支持与贡献
获取帮助
- 论坛:Elixir Forum(Nerves板块)
- Discord:https://discord.gg/elixir(#nerves频道)
- 邮件列表:nerves@nerves-project.org
贡献代码
# Fork并克隆仓库
git clone https://gitcode.com/你的用户名/nerves.git
cd nerves
# 创建特性分支
git checkout -b feature/my-feature
# 提交PR
git push origin feature/my-feature
贡献指南:请先阅读CONTRIBUTING.md,确保代码符合项目规范
总结与展望
Nerves框架彻底改变了嵌入式开发的范式,让开发者能够:
- 用Elixir的简洁语法编写嵌入式代码
- 利用OTP的容错机制构建高可靠系统
- 通过热重载实现秒级开发循环
- 用Phoenix/LiveView构建现代用户界面
随着物联网的发展,Nerves正成为工业控制、智能家居、机器人等领域的首选框架。立即开始你的Nerves之旅,体验函数式编程带来的嵌入式开发革命!
收藏本文,关注Nerves项目更新,持续获取嵌入式开发最佳实践!
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



