柔性PCB与Zephyr RTOS实战:打造低功耗蓝牙多传感器节点

📅 2026/8/19 5:32:55
柔性PCB与Zephyr RTOS实战:打造低功耗蓝牙多传感器节点
1. 项目缘起当柔性电路板遇见“章鱼”最近在折腾一个挺有意思的小玩意儿我把它叫做“柔性PCB章鱼”。这个想法的源头其实挺偶然的。当时手头正好有几片从旧设备上拆下来的柔性电路板边角料看着它们弯来折去的样子突然就想到能不能用这种“软”的特性去做一个形态可以自由变化、能适应各种不规则表面的电子装置就像章鱼的触手一样既能灵活伸展又能感知和交互。这个“章鱼”的核心我选用了nRF52840这颗蓝牙MCU。原因很简单它性能足够强集成蓝牙5.0功耗控制优秀而且最关键的是它有丰富的GPIO和ADC资源非常适合用来连接和控制多个分布在“触手”上的传感器或执行器。为了快速验证想法我决定在Zephyr RTOS上进行开发。Zephyr对nRF52系列的支持非常成熟其设备树和Kconfig配置系统能让我清晰地管理分布在柔性PCB不同“触手”上的外设这对于一个多节点、布线可能比较复杂的系统来说简直是福音。整个项目的目标是制作一个基于柔性PCB的、形态可定制的多传感器/执行器节点。它可以通过蓝牙比如用Serial Bluetooth Terminal这类APP与手机或电脑通信每个“触手”末端都可以焊接不同的功能模块比如RGB LED、微型振动马达、触摸传感器、甚至环境光传感器。你可以把它贴在衣服上做成可穿戴的交互装置卷在笔杆上做成智能笔或者铺在桌面上作为一个分布式的控制面板。下面我就来详细拆解从设计、制作到编程、调试的完整过程以及中间遇到的那些“坑”。2. 柔性PCB设计与制作从图纸到可弯曲的电路柔性PCB是整个项目的物理基础也是最需要精心设计的一环。它不同于普通的FR4硬质PCB在材料、走线规则和结构设计上都有其特殊性。2.1 材料选择与叠层结构我这次使用的是单面聚酰亚胺基材的柔性电路板。聚酰亚胺薄膜俗称“黄金薄膜”是柔性PCB最常用的基材它耐高温、绝缘性好、弯折寿命长。我选择的厚度是0.1mm这个厚度在保证一定机械强度的同时提供了非常好的柔韧性。覆铜厚度为1盎司约35μm对于信号线和一般的电源线来说足够了。对于一个小型的、实验性的“章鱼”项目双面板甚至多层软板成本过高且制作复杂。单面板完全能满足需求。我们需要在设计中充分考虑如何利用单面实现所有连接这通常意味着需要更多的“飞线”在PCB上就是跳线或者巧妙地布局。2.2 核心设计章鱼触手状的走线布局在EDA软件我用的KiCad中布局时核心思想是模仿章鱼的形态中心“躯干”放置主控MCU nRF52840、晶振、必要的去耦电容、以及蓝牙天线匹配电路。这部分区域相对固定弯折需求小可以适当加强比如在背面贴一层加强钢片但本次未使用。辐射状“触手”从“躯干”向外辐射出多条细长的走线通道。每条“触手”对应一组功能例如触手A分配3根线控制一个RGB LED共阳极触手B分配2根线连接一个振动电机和其驱动三极管触手C分配1根模拟线连接光敏电阻并搭配分压电阻等。走线规则柔性PCB的走线要尽可能平滑避免锐角最好使用圆弧或45度角拐弯以减少应力集中防止弯折时铜箔断裂。线宽我设置在0.3mm以上以保障电流能力和机械强度。线间距同样设为0.3mm满足常规工艺要求。铺铜与开窗柔性PCB通常不做大面积的实心铺铜。因为铜在反复弯折时容易疲劳断裂大面积铜皮会降低板子的柔韧性。我仅在MCU电源引脚附近做了局部网格化铺铜以增强电源稳定性。焊盘可以适当加大并做“泪滴”处理以加强导线与焊盘的连接强度。加强筋设计在“触手”与“躯干”的连接处以及“触手”上需要焊接较重元件如micro USB座的位置我在阻焊层开了窗计划后续手工贴上一层聚酰亚胺胶带作为局部加强防止这些位置因受力而撕裂。注意发给PCB制板厂时一定要在工艺要求中明确注明“柔性电路板”并指定基材和厚度。很多常规参数如孔铜厚度、油墨类型也需要根据柔性板工艺进行调整最好直接咨询板厂的技术支持。2.3 焊接与装配挑战焊接柔性PCB需要格外小心低温快焊使用可调温烙铁温度设置在300-320°C之间。过高的温度或过长的加热时间会损伤聚酰亚胺基材导致其起泡或变形。采用“点焊”方式接触时间尽可能短。固定与支撑焊接时一定要将柔性PCB平铺在耐高温的硅胶垫或木板上并用高温胶带固定边缘防止其翘曲或移动。对于nRF52840这类QFN封装使用热风枪返修台会更安全、均匀。记得先在焊盘上涂抹适量的锡膏再将芯片对准用热风枪以适中的风速和温度通常280-300°C均匀加热直至锡膏熔化回流。连接器选择为了将“触手”末端的信号引出来连接外部传感器我使用了间距为1.0mm的FPC排线插座。这种插座高度低连接可靠。也可以在“触手”末端直接设计焊盘焊接导线并用热缩管或UV胶进行固定和保护。3. 固件开发基于Zephyr RTOS构建多任务系统硬件准备就绪后下一步就是让“章鱼”的大脑——nRF52840运行起来。我选择Zephyr是因为它的可配置性和模块化非常适合这种自定义程度高的项目。3.1 开发环境搭建与项目创建首先按照Zephyr官方文档安装工具链包括CMake, Ninja, Python环境以及ARM GCC工具链。然后获取Zephyr源码并设置环境变量。创建一个新的Zephyr应用项目mkdir flex_pcb_octopus cd flex_pcb_octopus west init -m https://github.com/nrfconnect/sdk-nrf --mr main zephyr_project cd zephyr_project west update west zephyr-export之后我可以在zephyr_project目录外创建自己的应用目录app并在其中编写源码。3.2 设备树DTS配置硬件抽象的关键Zephyr的设备树是描述硬件的核心。我需要为我的“章鱼”创建一个自定义的板级定义。创建板级目录在zephyr/boards/arm/下我参考类似nRF52840的开发板如nrf52840dk_nrf52840创建了自己的板级目录flex_octopus_nrf52840。编写设备树源文件.dts这是重头戏。我需要根据我的柔性PCB实际布线定义所有的GPIO引脚用途。// flex_octopus_nrf52840.dts 部分内容 / { model Flexible PCB Octopus Board; compatible custom,flex-octopus-nrf52840; chosen { zephyr,console uart0; zephyr,shell-uart uart0; zephyr,bt-mon-uart uart0; zephyr,bt-c2h-uart uart0; }; leds { compatible gpio-leds; led0: led_0 { gpios gpio0 13 GPIO_ACTIVE_HIGH; // 触手A上的红色LED label Red LED on Tentacle A; }; // ... 可以定义更多LED }; gpio_keys { compatible gpio-keys; button0: button_0 { gpios gpio0 11 (GPIO_PULL_UP | GPIO_ACTIVE_LOW); // 触手B上的触摸传感器 label Touch sensor on Tentacle B; zephyr,code INPUT_KEY_0; }; }; aliases { led0 led0; sw0 button0; }; }; uart0 { compatible nordic,nrf-uarte; status okay; current-speed 115200; tx-pin 6; rx-pin 8; }; i2c0 { compatible nordic,nrf-twi; status okay; sda-pin 26; // 假设触手C用于I2C scl-pin 27; // 可以在这里定义挂载的I2C设备如OLED屏 }; adc { status okay; // 配置ADC通道例如读取触手D上的光敏电阻 channel0 { reg 0; zephyr,gain ADC_GAIN_1_6; zephyr,reference ADC_REF_VDD_1_4; zephyr,acquisition-time ADC_ACQ_TIME_DEFAULT; zephyr,input-positive NRF_SAADC_AIN2; // 对应P0.02/AIN2 zephyr,resolution 12; label LDR_ADC_CH; }; };这个.dts文件精确地描述了我的硬件哪个引脚接了LED哪个引脚接了按钮UART、I2C、ADC用了哪些引脚。Zephyr内核在编译时会根据这个描述生成相应的驱动和宏定义使得我在应用代码中可以通过label如Red LED on Tentacle A来引用设备而不需要关心底层具体的引脚编号实现了硬件抽象。编写板级配置文件.conf在同一个板级目录下创建flex_octopus_nrf52840.conf用于启用或禁用内核功能模块。例如# 启用蓝牙 CONFIG_BTy CONFIG_BT_PERIPHERALy CONFIG_BT_DEVICE_NAMEFlexOctopus # 启用串口控制台 CONFIG_SERIALy CONFIG_UART_CONSOLEy # 启用GPIO和ADC驱动 CONFIG_GPIOy CONFIG_ADCy # 启用看门狗可选提高可靠性 CONFIG_WATCHDOGy3.3 应用逻辑实现多线程与蓝牙服务在应用代码src/main.c中我构建了一个简单的多任务系统线程创建我创建了两个主要的线程。主控线程负责初始化硬件、管理蓝牙连接状态、处理来自手机APP的命令如改变LED颜色、控制电机开关。传感器采样线程以一个较低的频率例如每秒1次循环读取ADC获取光敏电阻的值并通过蓝牙通知Notification主动上报给已连接的手机客户端。蓝牙服务定义使用Zephyr的蓝牙GATT API我自定义了一个简单的服务。// 定义一个自定义服务包含LED控制特征和光照度读取特征 static struct bt_gatt_attr attrs[] { BT_GATT_PRIMARY_SERVICE(BT_UUID_CUSTOM_SERVICE), BT_GATT_CHARACTERISTIC(BT_UUID_LED_CONTROL, BT_GATT_CHRC_WRITE, BT_GATT_PERM_WRITE, NULL, write_led_callback, NULL), BT_GATT_CHARACTERISTIC(BT_UUID_LIGHT_LEVEL, BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, BT_GATT_PERM_READ, read_light_callback, NULL, NULL), BT_GATT_CCC(light_ccc_cfg_changed, BT_GATT_PERM_READ | BT_GATT_PERM_WRITE), };BT_UUID_LED_CONTROL特征属性为WRITE手机APP可以向其写入数据在write_led_callback回调函数中我解析数据并控制对应“触手”上的RGB LED。BT_UUID_LIGHT_LEVEL特征属性为READ和NOTIFY。手机可以随时读取read_light_callback同时我在传感器采样线程中当光照变化超过阈值时会调用bt_gatt_notify函数主动向手机推送新数据。GPIO与ADC驱动调用通过设备树中定义的label可以轻松获取设备指针并操作。// 获取LED设备 const struct device *led_dev DEVICE_DT_GET(DT_ALIAS(led0)); gpio_pin_configure(led_dev, PIN, GPIO_OUTPUT_ACTIVE); gpio_pin_set(led_dev, PIN, 1); // 点亮LED // 获取ADC设备并读取 const struct device *adc_dev DEVICE_DT_GET(DT_NODELABEL(adc)); adc_sequence_init(sequence); adc_read(adc_dev, sequence);4. 调试与烧录解决“J-Flash里没有MCU型号”的难题开发过程中烧录和调试是必不可少的环节。我手头有一个J-Link EDU调试器但在J-Flash软件里选择MCU型号时发现列表里并没有直接名为“nRF52840”的选项。这是一个常见问题。4.1 J-Flash MCU型号选择策略J-Flash的器件列表是基于其内置的Flash算法和调试脚本的。对于nRF52840你需要找到Nordic Semiconductor对应的条目。通常有以下几种方式直接搜索Nordic在J-Flash的Target Device选择界面在搜索框输入“Nordic”。你会看到一系列Nordic的芯片例如nRF52832_xxAA、nRF52840_xxAA等。选择nRF52840_xxAA即可。xxAA指的是Flash和RAM的容量变体对于常见的nRF52840-QIAA选择这个通用型号是没问题的。使用nRF Command Line Tools对于Nordic芯片更推荐使用其官方的工具链。安装nRF Command Line Tools它包含了nrfjprog命令行工具可以完全独立于J-Flash进行擦除、编程、复位等操作非常方便。# 擦除芯片 nrfjprog -e -f nrf52 # 烧录hex文件 nrfjprog --program build/zephyr/zephyr.hex -f nrf52 # 复位并运行 nrfjprog -r -f nrf52在SEGGER Embedded Studio中如果你使用SEGGER的IDE创建新项目时选择“Nordic nRF5 Devices”然后在下拉列表中就能找到nRF52840。提示如果J-Flash列表中确实没有也可能是软件版本太旧。更新到最新版的J-Flash软件和J-Link驱动通常能解决这个问题。此外确保你的J-Link硬件固件也是最新的。4.2 串口蓝牙终端调试在固件中我使能了UART控制台CONFIG_UART_CONSOLEy。这样除了蓝牙我还可以通过USB转TTL串口模块连接到“章鱼”板子的调试串口在DTS中定义的uart0对应特定的GPIO在PC端使用PuTTY、Tera Term等工具查看Zephyr的Shell输出进行调试。同时手机端安装Serial Bluetooth Terminal这类APP。在APP中搜索并连接名为“FlexOctopus”的设备。连接成功后APP会列出设备的所有GATT服务Service和特征Characteristic。找到我自定义的服务就可以向LED_CONTROL特征写入特定的数据格式例如FF0000表示红色来控制LED。订阅LIGHT_LEVEL特征的Notify手机APP就能实时接收并显示从“章鱼”触手上传的光照度数据。这种“有线串口日志 无线蓝牙交互”的组合调试方式极大地提高了开发效率。5. 功耗优化实战让“章鱼”长时间潜伏作为一个可能由电池供电的可穿戴或嵌入式设备功耗是必须考虑的问题。nRF52840本身低功耗特性很好但需要软件配合才能发挥。5.1 Zephyr电源管理基础Zephyr提供了完善的电源管理框架。对于nRF52系列主要的低功耗模式是System ON模式下的IDLE状态CPU暂停外设可选运行和System OFF模式深度睡眠仅少数GPIO和RTC能唤醒。在我的“章鱼”应用中我采取了以下策略外设模块化供电在硬件上我为每个“触手”上的功能模块如电机、高亮LED的电源线串联了MOS管。在软件中通过GPIO控制MOS管的通断当不需要某个模块工作时彻底切断其电源消除静态电流消耗。合理配置线程和睡眠在main.c的main函数初始化所有硬件和创建线程后主线程实际上就无事可做了。我让主线程在完成初始化后进入一个空循环但在这个循环中调用k_sleep(K_FOREVER)或者k_cpu_idle()。这样当所有工作线程如传感器采样线程都处于阻塞态例如在等待信号量或睡眠时系统会自动进入低功耗的IDLE状态。传感器采样线程的间歇性工作传感器线程不应该忙等。我使用k_timer或者简单的k_sleep()来让它周期性地被唤醒。void sensor_thread(void *p1, void *p2, void *p3) { while (1) { // 1. 打开ADC和传感器供电MOS管 gpio_pin_set(power_ctrl_dev, SENSOR_POWER_PIN, 1); k_sleep(K_MSEC(10)); // 等待电源稳定 // 2. 执行ADC采样 read_sensor_data(); // 3. 立即关闭传感器供电 gpio_pin_set(power_ctrl_dev, SENSOR_POWER_PIN, 0); // 4. 处理数据如果需要则发送蓝牙通知 if (data_changed) { bt_gatt_notify(...); } // 5. 进入长时间睡眠例如9.99秒 k_sleep(K_MSEC(9990)); } }这样传感器模块在99%的时间都是断电的只有不到1%的时间在工作极大地降低了平均电流。蓝牙连接间隔优化在蓝牙连接参数协商中可以适当增加连接间隔Connection Interval。更长的间隔意味着射频收发机更长时间处于睡眠状态功耗更低但会降低数据吞吐的实时性。对于传感器上报这种低频应用将连接间隔设置为100ms甚至更长是完全可以接受的。这可以在Zephyr的蓝牙配置中调整。5.2 实测功耗数据通过上述优化我用万用表串联在电池供电回路中测量平均电流深度睡眠System OFF仅GPIO唤醒电流低于1μA几乎可以忽略不计。空闲状态IDLE蓝牙未广播未连接平均电流约3-5μA。蓝牙广播状态平均电流约30-50μA广播间隔设为1秒。蓝牙连接状态100ms连接间隔无数据收发平均电流约200-400μA。激活状态传感器采样、LED点亮电流峰值可达几十mA但持续时间极短。对于一个200mAh的纽扣电池在大部分时间处于广播或空闲状态下理论上可以工作数月之久。这完全满足了一个低功耗交互装置的需求。6. 形态拓展与高级玩法基础功能实现后这个“柔性PCB章鱼”平台的可玩性就体现出来了。6.1 触手功能的多样化每条“触手”的末端焊盘都可以视为一个通用的IO接口。除了之前提到的LED、电机、光敏电阻还可以接入数字传感器如DHT11温湿度传感器单总线、触摸芯片如TTP223。模拟传感器如麦克风模块声音强度、弯曲传感器测量形变。执行器如微型舵机需要PWM输出、蜂鸣器。通信模块如一个超小的433MHz发射模块让“章鱼”具备无线遥控能力。只需要在设备树中为新的传感器分配GPIO或ADC资源并在应用代码中增加相应的驱动逻辑即可。Zephyr的驱动模型使得添加新设备变得相对规范。6.2 动态点阵屏与图形显示如果我想在“躯干”部分集成一块小型的OLED屏SSD1306通过I2C或SPI驱动来显示系统状态或简单的动画也是可行的。Zephyr有成熟的ssd1306显示驱动。我可以创建一个专门的显示刷新线程或者利用Zephyr的LVGL图形库需要较大的RAM和Flash来制作更复杂的UI。对于更复杂的动态图片显示虽然受限于MCU的存储空间nRF52840有1MB Flash256KB RAM无法存储大量位图但可以通过算法生成简单图形如几何图案、波形图或者将高度压缩的少量图标存储到Flash中按需解码显示。6.3 多“章鱼”组网协作一个更有趣的想法是制作多个“章鱼”让它们之间通过蓝牙Mesh或者简单的2.4GHz私有协议nRF52840的Radio外设支持ESB进行通信。例如一个“章鱼”贴在手腕作为主控其他“章鱼”分布在身体其他部位或家具上作为传感器节点形成一个柔性的体感或环境感知网络。Zephyr对蓝牙Mesh有很好的支持这为构建此类分布式柔性传感网络提供了软件基础。7. 避坑实录与经验沉淀在整个项目过程中踩坑是不可避免的。这里记录几个印象深刻的点柔性PCB撕裂最早的一版设计中我在“触手”根部与“躯干”连接处使用了直角走线并且在反复弯折测试中该处铜箔最终断裂。解决方案后续版本将所有拐角改为圆弧过渡并在该区域背面粘贴了薄层聚酰亚胺胶带作为加强筋再未出现断裂问题。蓝牙信号受干扰最初将蓝牙天线一个贴片陶瓷天线布在了MCU和DC-DC电源电路附近导致蓝牙连接距离极短且不稳定。解决方案在改版时严格按照天线设计指南将天线布置在板边下方所有层净空并远离数字电路和电源线。同时使用π型匹配电路对天线进行调试需要矢量网络分析仪或依赖芯片厂商的参考设计。Zephyr设备树配置错误曾错误地将一个GPIO引脚在设备树中同时分配给i2c0的sda-pin和一个gpio-leds节点导致编译虽然通过但运行时I2C无法正常工作。解决方案仔细检查设备树确保引脚资源分配无冲突。Zephyr的编译系统不会检查这种硬件层面的冲突需要开发者自己保证。低功耗模式下外设漏电在实现深度睡眠时发现即使代码调用了pm_power_state_force电流仍有几百微安。解决方案使用nRF52的GPIOPIN_CNF寄存器将所有未使用的GPIO引脚配置为Disconnected输入模式高阻态。对于已使用的引脚根据外围电路情况配置为上拉、下拉或保持输出固定电平防止因引脚悬空产生漏电流。这个“柔性PCB章鱼”项目从最初一个模糊的想法到最终成为一个可以灵活弯折、无线通信、低功耗运行的实体整个过程充满了硬件和软件交织的挑战与乐趣。它不仅仅是一个具体的作品更是一个验证想法、学习现代嵌入式开发流程特别是RTOS和设备树的绝佳平台。最大的体会是柔性电子给了物理形态以自由而像Zephyr这样的现代RTOS和nRF52840这样的高性能低功耗MCU则给了功能实现以自由。两者结合能催生出很多传统硬质PCB裸机编程难以实现的创意产品。如果你也对可穿戴设备、交互艺术或分布式传感感兴趣不妨从这样一个小的柔性节点开始尝试。