nRF54L15智能家居原型开发:Zephyr与Matter实战
2026/9/21 19:15:04 网站建设 项目流程

1. 为什么我选了nRF54L15来做智能家居原型

智能家居原型开发这件事,我前前后后折腾过不少方案。最早用ESP32系列,后来试过STM32加外挂射频的方案,再后来也摸过一些国产RISC-V的开发板。每次选型都绕不开几个核心矛盾:无线协议要全、功耗要低、开发效率要高、生态要跟得上。直到nRF54L15出来,我才觉得找到了一个比较均衡的答案。

nRF54L15是Nordic Semiconductor在nRF52系列之后推出的新一代低功耗无线SoC,属于nRF54L系列。它最大的变化是从Cortex-M4升级到了Cortex-M33内核,主频提到了128MHz,Flash和RAM也大幅增加,同时把蓝牙低功耗、Thread、Zigbee、Matter这些协议的支持都做进了同一颗芯片里。对于智能家居原型来说,这意味着你不需要再为不同的设备准备不同的射频方案,一颗芯片就能覆盖从传感器节点到网关的大部分场景。

我这次搭建的原型目标很明确:做一个能实际跑起来的智能家居系统,包含温湿度采集节点、人体存在检测节点、一个本地网关,以及手机端的状态查看和控制。所有节点通过Thread组网,网关通过Matter协议把设备暴露给上层应用。固件全部基于Zephyr RTOS开发,代码开源,方便后续直接拿去做产品化验证。

适合谁来参考这篇内容?如果你已经有一点嵌入式开发基础,用过STM32或者ESP32,想往低功耗多协议方向转,那这篇会比较对路。如果你是完全零基础,也没关系,我会把环境搭建、固件编译、烧录调试这些步骤拆得足够细,你跟着走一遍就能把原型跑起来。整个过程中我会重点讲清楚每个选择背后的原因,以及我实际踩过的坑,这些在官方文档里通常不会写。

2. 开发环境搭建与工具链配置

2.1 为什么选Zephyr而不是裸机或FreeRTOS

nRF54L15的官方支持在Zephyr里是最完整的。Nordic自己维护的nRF Connect SDK就是基于Zephyr构建的,驱动、协议栈、示例代码都围绕Zephyr组织。如果你用裸机开发,蓝牙协议栈和Thread协议栈的移植工作量会非常大,而且后续升级协议版本时几乎要重写。FreeRTOS虽然也能跑,但Nordic没有提供官方适配,社区方案的质量参差不齐。

Zephyr的好处在于它把设备树、Kconfig、CMake这三套机制整合得很好。设备树描述硬件资源,Kconfig管理功能裁剪,CMake负责构建。刚开始接触会觉得有点绕,但一旦理解了这个框架,换芯片、换开发板的成本会低很多。比如你从nRF54L15换到nRF5340,大部分应用代码不用动,只需要改设备树和配置文件。

另一个实际考虑是Matter协议的支持。Matter的参考实现就是基于Zephyr的,如果你后续想把设备接入Matter生态,用Zephyr几乎是唯一顺畅的路径。我试过在FreeRTOS上移植Matter,光是把依赖库理清楚就花了两天,最后还卡在内存对齐问题上。

2.2 在Ubuntu上从零安装nRF Connect SDK

我用的开发主机是Ubuntu 22.04 LTS,这是Nordic官方推荐的环境。Windows下也能用,但工具链的坑会多一些,尤其是west命令和Python环境冲突的问题。如果你手头只有Windows,建议装个WSL2,体验接近原生Linux。

第一步是安装基础依赖。打开终端,执行:

sudo apt update sudo apt install --no-install-recommends git cmake ninja-build gperf \ ccache dfu-util device-tree-compiler wget \ python3-dev python3-pip python3-setuptools python3-tk python3-wheel xz-utils file \ make gcc gcc-multilib g++-multilib libsdl2-dev libmagic1

这些包看着多,但每个都有用。ninja-build是构建工具,比make快不少;gperf是Zephyr生成哈希表用的;dfu-util后面烧录固件会用到;libsdl2-dev是跑模拟器时需要的。我一开始偷懒只装了git和cmake,结果编译到一半报了一堆找不到头文件的错误,回头补装反而更费时间。

接下来安装west。west是Zephyr的元工具,负责管理多仓库代码和构建流程:

pip3 install --user west

装完后把~/.local/bin加到PATH里,不然终端找不到west命令。然后初始化工作区:

west init ~/ncs cd ~/ncs west update

west update这一步会拉取所有依赖仓库,包括Zephyr内核、HAL层、协议栈、示例代码等。网络状况好的话大概十几分钟,慢的话可能要半小时以上。我建议第一次跑的时候去泡杯茶,别盯着进度条看。

拉完之后设置工具链环境变量:

west zephyr-export pip3 install --user -r ~/ncs/zephyr/scripts/requirements.txt

这里有个坑要注意:requirements.txt里的包版本可能会和你系统里已有的Python包冲突。如果报错,建议用virtualenv隔离一个环境出来,别直接往系统Python里装。

2.3 安装交叉编译工具链

nRF54L15用的是Cortex-M33内核,需要ARM的GNU工具链。Nordic提供了预编译版本,直接下载解压就行:

cd ~ wget https://developer.arm.com/-/media/Files/downloads/gnu/12.2.rel1/binrel/\ arm-gnu-toolchain-12.2.rel1-x86_64-arm-none-eabi.tar.xz tar xf arm-gnu-toolchain-12.2.rel1-x86_64-arm-none-eabi.tar.xz

解压后把bin目录加到PATH:

export PATH=~/arm-gnu-toolchain-12.2.rel1-x86_64-arm-none-eabi/bin:$PATH

建议把这行写进~/.bashrc,不然每次开新终端都要重新设置。工具链版本我选的是12.2,这是Nordic当前验证过的版本。用更新的版本可能会遇到链接脚本不兼容的问题,别问我怎么知道的。

验证工具链是否可用:

arm-none-eabi-gcc --version

能正常输出版本号就说明装好了。

2.4 开发板连接与驱动确认

nRF54L15 DK通过USB连接到Ubuntu后,系统会自动识别出两个设备:一个J-Link调试器接口,一个USB转串口。用lsusb应该能看到Nordic Semiconductor的VID:

lsusb | grep Nordic

正常情况下会显示ID 1915:xxxx Nordic Semiconductor ASA。如果没看到,检查USB线是不是只供电不传数据的那种。我手头有一根线就是只能充电,插上去半天没反应,换线之后立刻就好了。

串口设备通常是/dev/ttyACM0/dev/ttyACM1,前者是J-Link的CDC接口,后者是目标板的串口输出。用dmesg | tail可以看到具体的设备名。如果权限不够,把自己加到dialout组:

sudo usermod -aG dialout $USER

然后重新登录一次让组权限生效。

3. 智能家居原型的整体架构设计

3.1 节点角色划分与通信协议选择

这个原型我设计了三种角色:传感器节点、执行器节点、网关。传感器节点负责采集环境数据,执行器节点控制继电器或LED,网关负责组网和协议转换。

通信协议上,节点之间用Thread。Thread是基于IPv6的Mesh网络协议,低功耗、自组网、支持多跳,非常适合智能家居场景。相比Zigbee,Thread的原生IP支持让网关和云端对接更简单,不需要额外的协议转换层。相比蓝牙Mesh,Thread的Mesh能力更成熟,节点数量多的时候稳定性更好。

网关到手机端用Matter。Matter是应用层协议,底层可以跑在Thread、Wi-Fi或以太网上。我这里让网关同时具备Thread边界路由器和Matter桥接的功能,手机通过Matter发现和控制设备。这样做的原因是Matter的生态兼容性最好,苹果、谷歌、亚马逊的智能家居平台都支持,后续想接入哪个平台都不用改固件。

3.2 硬件选型与外围电路

nRF54L15 DK本身集成了调试器、按键、LED、传感器,做原型验证足够了。但要做实际的传感器节点,需要外接一些模块。

温湿度传感器我选了SHT40,I2C接口,精度±1.5%RH和±0.2°C,功耗很低。人体存在检测用的是毫米波雷达模块,型号是Seeed的MR60BHA1,UART接口,能检测静止和微动人体。相比PIR传感器,毫米波雷达不会因为人坐着不动就误判为无人,体验好很多。

执行器部分用了一个5V继电器模块,通过GPIO控制。注意nRF54L15的GPIO是3.3V电平,驱动继电器模块时确认模块支持3.3V逻辑输入,否则要加电平转换。我一开始直接接上去,继电器偶尔会误动作,后来加了光耦隔离才稳定。

电源方面,传感器节点用CR2477纽扣电池供电,设计目标是一年以上的续航。nRF54L15的休眠电流在微安级别,配合Thread的休眠终端模式,这个目标是可以达到的。网关则用USB持续供电,不需要考虑功耗。

3.3 软件分层与代码组织

固件代码我分成四层:硬件抽象层、驱动层、应用层、协议层。

硬件抽象层放在boards/目录下,用设备树描述引脚映射和外设配置。驱动层在drivers/里,封装了SHT40、雷达模块、继电器的读写接口。应用层在src/下,包含数据采集逻辑、状态机、事件处理。协议层直接用Zephyr自带的Thread和Matter组件,不需要自己实现。

这样分层的好处是换硬件时只需要改设备树和驱动层,应用逻辑不动。比如你把手头的nRF54L15 DK换成自定义板,只要设备树写对了,上层代码一行不用改。

代码仓库的结构大概是这样:

smart-home-prototype/ ├── boards/ │ └── nrf54l15dk/ │ └── nrf54l15dk_nrf54l15_cpuapp.overlay ├── drivers/ │ ├── sht40/ │ ├── radar/ │ └── relay/ ├── src/ │ ├── main.c │ ├── sensor_node.c │ ├── gateway.c │ └── matter_bridge.c ├── prj.conf ├── CMakeLists.txt └── README.md

prj.conf是Kconfig配置文件,用来开启需要的功能模块。比如要启用Thread,就加CONFIG_NET_L2_OPENTHREAD=y;要启用Matter,就加对应的Matter配置项。这个文件是裁剪固件大小的关键,不需要的功能全部关掉,能省不少Flash和RAM。

4. 核心功能实现与关键代码解析

4.1 设备树配置:把硬件资源描述清楚

设备树是Zephyr里最容易被忽视但又最重要的部分。它把芯片的外设资源和板级的引脚连接用文本描述出来,编译时生成头文件供驱动使用。

以SHT40为例,它接在I2C1上,从地址是0x44。在overlay文件里这样写:

&i2c1 { status = "okay"; clock-frequency = <I2C_BITRATE_STANDARD>; sht40: sht40@44 { compatible = "sensirion,sht40"; reg = <0x44>; status = "okay"; }; };

compatible字段告诉Zephyr用哪个驱动来匹配这个设备。SHT40在Zephyr的主线里有现成驱动,所以直接写sensirion,sht40就行。如果没有现成驱动,就要自己写一个,并在compatible里用自定义的字符串。

雷达模块走UART,配置稍微复杂一点:

&uart1 { status = "okay"; current-speed = <115200>; pinctrl-0 = <&uart1_default>; pinctrl-1 = <&uart1_sleep>; pinctrl-names = "default", "sleep"; };

pinctrl指定了引脚映射,default是工作状态,sleep是低功耗状态。这两个状态都要配,不然进休眠后引脚状态不对,会漏电。

继电器就是普通的GPIO:

/ { relays { compatible = "gpio-leds"; relay1: relay_1 { gpios = <&gpio1 10 GPIO_ACTIVE_HIGH>; label = "Relay 1"; }; }; };

这里借用了gpio-leds的兼容字符串,因为继电器和LED的控制逻辑一样,都是高低电平。实际项目里可以自己定义一个relay-gpios的绑定,但原型阶段没必要那么讲究。

4.2 传感器数据采集与Thread上报

SHT40的驱动用起来很简单,Zephyr已经把I2C读写封装好了。初始化后调用SHT40_FETCH就能拿到温湿度值:

const struct device *sht = DEVICE_DT_GET(DT_NODELABEL(sht40)); struct sensor_value temp, hum; sensor_sample_fetch(sht); sensor_channel_get(sht, SENSOR_CHAN_AMBIENT_TEMP, &temp); sensor_channel_get(sht, SENSOR_CHAN_HUMIDITY, &hum);

sensor_value结构体里val1是整数部分,val2是小数部分,单位是百万分之一。比如温度25.3°C,val1是25,val2是300000。上报前要转成字符串或者CBOR格式,我选了CBOR,因为二进制编码体积小,适合低功耗场景。

Thread上报用Zephyr的socket API。节点加入网络后,创建一个UDP socket,把数据发到网关的地址:

int sock = zsock_socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); struct sockaddr_in6 dest = { .sin6_family = AF_INET6, .sin6_port = htons(1234), }; zsock_inet_pton(AF_INET6, gateway_addr, &dest.sin6_addr); zsock_sendto(sock, payload, payload_len, 0, (struct sockaddr *)&dest, sizeof(dest));

网关地址通过Thread的mDNS发现,不需要硬编码。Zephyr里有mDNS responder和querier的示例,直接拿来用就行。

采集周期我设的是30秒一次。这个值权衡了数据实时性和功耗。温湿度变化本来就慢,30秒足够。如果是人体存在检测,响应要快一些,我设的是1秒上报一次,但只在状态变化时发,不是周期性发。

4.3 网关的Matter桥接与本地控制逻辑

网关跑的是Thread边界路由器加Matter桥接的固件。Thread边界路由器负责把Thread网络和外部IP网络打通,Matter桥接把Thread设备映射成Matter设备。

Matter的设备模型里,每个功能对应一个Cluster。温度传感器对应Temperature Measurement Cluster,湿度对应Relative Humidity Cluster,继电器对应On/Off Cluster。在代码里定义端点:

static const struct matter_endpoint ep_temp = { .endpoint_id = 1, .device_type = MATTER_DEVICE_TYPE_TEMPERATURE_SENSOR, .clusters = { MATTER_CLUSTER_TEMP_MEASUREMENT, MATTER_CLUSTER_RELATIVE_HUMIDITY, }, };

网关收到Thread节点的数据后,更新对应的Cluster属性,Matter控制器(手机App)就能读到最新值。控制指令反向走一遍:手机发On/Off命令,网关通过Thread发给执行器节点。

本地控制逻辑我加了一个简单的规则引擎。比如温度超过28度自动开风扇,湿度低于30%自动开加湿器。规则用JSON配置,存在网关的Flash里,可以通过Matter的自定义Cluster在线修改。这样不用重新烧固件就能调整自动化策略。

4.4 低功耗管理与实测数据

传感器节点的功耗优化是重点。nRF54L15支持多种低功耗模式,我用的是System OFF模式,休眠电流实测1.2微安。唤醒源配了两种:定时器唤醒和GPIO中断唤醒。

定时器唤醒用于周期性采集,30秒一次。GPIO中断用于雷达模块的触发信号,有人经过时立刻唤醒。这样既保证了数据新鲜度,又不会因为频繁唤醒浪费电。

实测数据:CR2477电池容量1000mAh,节点平均电流约35微安(含采集和上报的峰值摊薄),理论续航约1000/0.035≈28571小时,约3.2年。实际因为电池自放电和温度影响,打个七折,两年以上没问题。

网关的功耗不用太在意,USB供电,实测工作电流约45mA,峰值120mA(Matter配网时)。

5. 烧录、调试与常见问题排查

5.1 固件编译与烧录的完整流程

编译命令很简单:

west build -b nrf54l15dk/nrf54l15/cpuapp smart-home-prototype

-b指定板子,nrf54l15dk是开发板名,nrf54l15是SoC型号,cpuapp表示编译给应用核。nRF54L15是双核架构,还有一个网络核跑蓝牙协议栈,但Thread跑在应用核上,所以只编应用核就行。

烧录:

west flash

默认用J-Link烧录,速度很快,几秒钟完成。如果想看串口输出:

west espressif monitor

不对,这是ESP32的命令。Zephyr里用:

west zephyr monitor

或者直接用screen

screen /dev/ttyACM1 115200

退出screen按Ctrl+A然后K,再按Y确认。

5.2 常见编译错误与解决方法

问题一:west build报找不到板子定义。

通常是west update没跑完或者Zephyr的版本不对。检查~/ncs/zephyr/boards/arm/下有没有nrf54l15dk目录。如果没有,说明SDK版本太旧,需要更新到最新版。

问题二:链接时提示Flash溢出。

nRF54L15的Flash是1.5MB,看着很大,但Thread加Matter的协议栈占了不少。如果开了调试日志和断言,很容易超。解决办法是在prj.conf里关掉不用的功能:

CONFIG_LOG=n CONFIG_ASSERT=n CONFIG_THREAD_ANALYZER=n

生产固件里这些本来就不该开。

问题三:I2C通信失败,读不到SHT40的数据。

先确认硬件连接:SDA、SCL、VCC、GND四根线有没有接错。然后用逻辑分析仪或者示波器看波形。如果波形正常但读不到数据,检查从地址对不对。SHT40的地址是0x44,但有些模块出厂时改了地址,用i2c scan命令扫一下:

i2c scan i2c@1

Zephyr的shell里集成了这个命令,能列出总线上所有响应的地址。

5.3 Thread组网失败的排查思路

Thread组网失败是最让人头疼的问题,因为涉及射频、协议、配置多个层面。我整理了一个排查顺序:

现象可能原因排查方法
节点无法加入网络网络密钥不匹配检查CONFIG_OPENTHREAD_NETWORKKEY是否一致
加入后频繁掉线射频干扰或距离过远ot neighbor查看邻居质量,调整信道
能加入但ping不通边界路由器未启动检查网关的ot br状态
数据上报超时UDP端口被防火墙拦截确认网关和节点端口一致

信道选择上,Thread默认用信道11到26。如果周围Wi-Fi多,建议避开Wi-Fi常用的1、6、11信道对应的频段。我实测把Thread信道设到25之后,丢包率从8%降到了0.5%。

5.4 Matter配网踩过的坑

Matter配网需要二维码和配对码。Nordic的示例里会自动生成,但如果你改了设备类型或者Cluster配置,二维码要重新生成。生成工具在ncs/modules/lib/matter/scripts/tools/下,用matter-pairing-code脚本。

配网时手机App搜不到设备,最常见的原因是mDNS没通。Matter依赖mDNS做设备发现,如果网关的mDNS服务没起来,手机就找不到。检查方法是在网关上跑:

avahi-browse -a

看有没有Matter的服务实例。如果没有,检查CONFIG_NET_MDNS=y有没有开。

另一个坑是IPv6地址冲突。Matter要求设备有全球唯一的IPv6地址,如果网关的Thread前缀和Wi-Fi前缀冲突,配网会失败。解决办法是给Thread网络分配一个独立的ULA前缀,别和Wi-Fi用同一个网段。

6. 开源固件仓库说明与二次开发建议

6.1 仓库结构与编译入口

开源仓库我放在了GitHub上,名字叫nrf54l15-smart-home。目录结构和前面说的一样,根目录下有README.md说明编译步骤,prj.conf是默认配置,prj_sensor.confprj_gateway.conf分别是传感器节点和网关的配置。

编译传感器节点:

west build -b nrf54l15dk/nrf54l15/cpuapp -- -DCONF_FILE=prj_sensor.conf

编译网关:

west build -b nrf54l15dk/nrf54l15/cpuapp -- -DCONF_FILE=prj_gateway.conf

--后面的参数传给CMake,CONF_FILE指定用哪个配置文件。这样一套代码可以编出不同角色的固件,不用维护多个分支。

6.2 如何添加新的传感器类型

添加新传感器的步骤我总结成四步:

  1. 在设备树overlay里添加节点,写对compatiblereg
  2. 如果Zephyr主线有驱动,直接在prj.conf里开对应的CONFIG_选项。如果没有,在drivers/下新建目录,实现device_initsample_fetch接口。
  3. 在应用层调用sensor_sample_fetchsensor_channel_get读取数据。
  4. 在Thread上报的payload里加上新的字段,网关侧同步更新解析逻辑。

以添加一个PM2.5传感器为例,如果用的是UART接口的模块,驱动层要处理串口协议解析。我建议把协议解析放在独立的线程里,别在中断里做,不然会影响Thread的实时性。

6.3 从原型到产品的差距

原型能跑通不代表能直接量产。从原型到产品,至少还有这几步要走:

  • 硬件改版:开发板的射频匹配电路是优化过的,但自定义板的PCB布局会影响天线性能。建议用Nordic的参考设计,别自己乱改匹配网络。
  • 认证:蓝牙、Thread、Matter都有各自的认证要求。nRF54L15的协议栈已经过了认证,但整机还需要做EMC和射频测试。
  • OTA升级:原型阶段用J-Link烧录,产品必须支持OTA。Zephyr有MCUboot和Matter OTA两种方案,建议用Matter OTA,和生态兼容。
  • 安全加固:原型里调试接口是开的,产品要关掉。Flash里的密钥要加密存储,别明文放。

6.4 后续扩展方向

这个原型还有不少可以扩展的地方。比如加一个本地语音控制,用nRF54L15的PDM接口接数字麦克风,跑简单的关键词识别。或者加一个电子墨水屏,显示当前温湿度和设备状态。再或者把网关的规则引擎换成更复杂的场景联动,支持时间段、条件组合。

我个人比较感兴趣的是把Thread网络和Matter的能耗管理结合起来。Matter有Energy Management Cluster,可以上报设备的功耗数据,配合智能插座做用电优化。这个方向目前做的人不多,但实际价值不小。

最后分享一个调试小技巧:nRF54L15的RTT日志比串口日志快很多,而且不占用UART资源。在prj.conf里开CONFIG_USE_SEGGER_RTT=y,然后用J-Link RTT Viewer看日志,刷新率能到毫秒级。排查实时性问题时特别有用,串口打印的延迟有时候会掩盖真正的时序问题。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询