ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

树莓派Pico低功耗实战:从2.5μA理论值到稳定3.5μA工程实测

树莓派Pico低功耗实战:从2.5μA理论值到稳定3.5μA工程实测 1. 为什么树莓派 Pico 的“低功耗软件控制”不是一句空话而是必须亲手验证的工程现实很多人第一次看到树莓派 Pico 官方文档里写着“深度睡眠电流低至 2.5μA”第一反应是“哇这比我的智能手表待机还省电”——然后兴冲冲写完machine.deepsleep()就去睡觉第二天醒来发现电池掉了 30%。我试过三次每次都在凌晨三点被手机弹出的电量告警惊醒盯着万用表上跳动的 87μA 发呆。这不是芯片不行而是我们对“低功耗”的理解还停留在 API 函数名层面没沉到寄存器、时钟树、外设唤醒源、IO 状态保持这些物理层细节里。Pico 的低功耗能力本质上是一套软硬协同的“状态契约”软件必须主动释放所有硬件资源硬件才肯进入深度节能模式而一旦某个外设比如 UART 接收缓冲区还有未读字节或者一个 GPIO 被意外拉高悄悄“违约”整个系统就会卡在浅睡眠里功耗从微安级飙升到毫安级——差了整整一千倍。这不是理论值和实测值的误差这是你代码里一行没写的pin.init(Pull.UP)和一行多写的uart.read(1)共同酿成的功耗事故。这篇内容不讲“如何点亮 LED”也不堆砌 SDK 文档里的函数列表。它是我用三块 Pico、两块自制 PCB、七种不同电池从 CR2032 到 18650、以及连续 47 天不间断功耗日志记录后整理出的一份可复现、可测量、可归因的实践手册。核心关键词就五个Pico、低功耗、software、API、注意事项——每一个词都对应着一个必须亲手踩过的坑。如果你的目标是让 Pico 在纽扣电池上撑过一年或者让传感器节点在野外无维护运行六个月那么接下来的内容就是你真正需要的“操作边界说明书”。2. 深度睡眠前的“临终检查清单”为什么deepsleep()不是终点而是起点Pico 的machine.deepsleep()看似简单但它的执行效果完全取决于调用前那一瞬间的系统状态。官方文档里那句“所有 RAM 内容丢失CPU 停止仅 RTC 和某些唤醒源保持供电”背后藏着至少 12 个必须手动干预的硬件状态点。我把它拆解成一份可逐项打钩的“临终检查清单”每漏一项功耗就可能翻十倍。2.1 关闭所有非必要外设时钟——不是“不用”就等于“关”RP2040 的时钟树是分层的。即使你没初始化SPI或I2C只要其对应的时钟门控位Clock Gating Register没被清零该外设的时钟域仍在震荡持续消耗电流。实测数据很说明问题外设类型时钟关闭前电流时钟关闭后电流降幅UART012.3 μA0.8 μA93%SPI08.7 μA0.5 μA94%I2C06.2 μA0.3 μA95%关键操作不是“不创建对象”而是显式关闭时钟。以 MicroPython 为例import machine # 正确做法显式关闭所有已知外设时钟 machine.mem32[0x4000c000 0x04] 0 # 关闭 UART0 时钟 (0x4000c000 是 PSM_BASE) machine.mem32[0x4000c000 0x08] 0 # 关闭 UART1 时钟 machine.mem32[0x4000c000 0x10] 0 # 关闭 SPI0 时钟 machine.mem32[0x4000c000 0x14] 0 # 关闭 SPI1 时钟 machine.mem32[0x4000c000 0x18] 0 # 关闭 I2C0 时钟 machine.mem32[0x4000c000 0x1c] 0 # 关闭 I2C1 时钟提示0x4000c000是 RP2040 的 Power Supply Manager (PSM) 寄存器基址0x04等偏移量对应各外设的时钟使能位。这个地址和偏移量在 RP2040 数据手册第 287 页的 “Clock Gating Registers” 表格中有明确定义。别信网上那些“自动管理”的库它们只管初始化不管善后。2.2 IO 引脚状态重置——悬空引脚是静默的电流黑洞这是最隐蔽也最致命的坑。Pico 的 GPIO 在深度睡眠时如果配置为输入且未设置上下拉引脚处于高阻态Hi-Z。一旦附近有电磁干扰比如开关电源的纹波、WiFi 路由器的射频泄漏悬空引脚会像天线一样拾取噪声导致内部 ESD 保护二极管间歇导通产生数十微安的漏电流。我用示波器抓过一次一个悬空的 GP15在实验室环境下平均漏电流高达 18μA。解决方案不是“随便接个下拉电阻”而是按功能分类处理已连接传感器/模块的引脚确认其待机模式下的电气特性。例如DS18B20 温度传感器在休眠时要求数据线保持上拉此时 GP4 必须配置为Pin.PULL_UP纯输出引脚如驱动 LED在睡眠前强制设为Pin.OUT并输出低电平避免驱动外部电路纯输入引脚如按键必须明确设置Pin.PULL_UP或Pin.PULL_DOWN绝不能留悬空未使用的引脚全部配置为Pin.INPin.PULL_DOWN。RP2040 的默认复位状态是Pull-down但软件初始化后可能被覆盖必须显式重置。实操代码段# 重置所有未使用引脚为安全状态 for pin_num in [0, 1, 2, 3, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28]: try: p machine.Pin(pin_num, machine.Pin.IN, machine.Pin.PULL_DOWN) p.value() # 读取一次确保状态生效 except: pass # 某些引脚如 USB DP/DN无法配置跳过2.3 中断与唤醒源的“双向确认”——你以为的唤醒可能是系统在假醒Pico 支持多种唤醒源GPIO 边沿触发、RTC 定时器、USB 连接事件。但很多开发者只做了单向配置rtc.alarm(0, 30)设置了 30 秒后唤醒却忘了检查rtc.wake_on_alarm(0, True)是否真正生效。更麻烦的是GPIO 唤醒需要同时满足两个条件1该 GPIO 的 IRQ 使能位被置位2该 GPIO 的唤醒使能位WAKE_EN在 SIO 寄存器中被置位。缺一不可。我遇到过最典型的故障用 GP21 做按键唤醒代码里写了irq(triggerPin.IRQ_RISING)但没写machine.mem32[0xd0000000 0x14] | (1 21)SIO_WAKE_EN0 寄存器地址0xd0000000 是 SIO_BASE。结果现象是按键按下去LED 闪一下系统立刻又睡过去——因为中断触发了但硬件没允许它真正退出睡眠状态CPU 只是短暂地“抽搐”了一下。验证唤醒源是否就绪的终极方法是读取SIO_WAKE_EN0和SIO_WAKE_EN1寄存器的值并与你的预期唤醒引脚做位运算比对# 检查 GP21 是否已启用为唤醒源 SIO_BASE 0xd0000000 WAKE_EN0 machine.mem32[SIO_BASE 0x14] expected_bit 1 21 if WAKE_EN0 expected_bit: print(GP21 唤醒源已启用) else: print(GP21 唤醒源未启用需手动设置) machine.mem32[SIO_BASE 0x14] | expected_bit注意SIO_WAKE_EN0控制 GP0-GP31SIO_WAKE_EN1控制 GP32-GP47Pico W 专用。普通 Pico 只需关注WAKE_EN0。这个寄存器地址和位定义在 RP2040 数据手册第 322 页 “SIO Wake-up Enable Registers” 有完整说明。3. 从“能睡”到“睡得稳”RTC 定时器的精度陷阱与校准实战当你的目标是“每天只醒一次采集温湿度”那么 RTC实时时钟就是整个低功耗系统的节拍器。但 Pico 的内置 RTC 并非原子钟它的精度受晶振温漂、电压波动、甚至 PCB 布线电容的影响。官方标称精度是 ±50ppm即每天误差约 4.3 秒但我在实测中发现一块常温下的 Pico连续 72 小时日志显示其 RTC 每小时快 0.87 秒——换算下来一天快 20.9 秒一个月就快 10 分钟。这意味着你设定的“每天 8:00 唤醒”第三周可能变成“7:50”第五周直接错过整点。3.1 理解 RTC 的底层机制它不是一个独立芯片而是依赖主晶振的“软件计数器”Pico 没有独立的 RTC 晶振如 DS3231它的 RTC 是通过将主晶振12MHz分频后由一个 48 位计数器实现的。因此RTC 的精度完全绑定于主晶振的稳定性。而主晶振的频率又会随 VCC 电压变化——当电池从 3.3V 放电到 2.9V 时实测晶振频率偏移可达 120ppm。这就是为什么用新电池测试完美的定时器在旧电池上会严重失准。解决方案不是换晶振Pico 硬件不支持而是建立电压-频率补偿模型。我采集了同一块 Pico 在不同电压下的 RTC 偏差数据VCC (V)24 小时累计偏差 (秒)计算得出的 ppm 偏移3.3018.22103.1522.72633.0028.53312.8535.1408规律非常明显电压每下降 0.15Vppm 偏移增加约 50ppm。于是我写了一个动态校准函数在每次唤醒后先读取 ADC 测得的 VCC通过machine.ADC(4)读取内部 VREF再根据当前电压查表修正下次的唤醒时间# VCC-ppm 补偿查找表简化版 VCC_PPM_TABLE [ (3.30, 210), (3.15, 263), (3.00, 331), (2.85, 408), (2.70, 485) ] def get_compensated_sleep_ms(target_ms): # 读取当前 VCC adc machine.ADC(4) vref 3.3 * (adc.read_u16() / 65535) # 线性插值计算当前 ppm ppm 0 for i in range(len(VCC_PPM_TABLE)-1): v_low, p_low VCC_PPM_TABLE[i] v_high, p_high VCC_PPM_TABLE[i1] if v_low vref v_high: ratio (vref - v_high) / (v_low - v_high) ppm p_low ratio * (p_high - p_low) break # 计算补偿后的真实睡眠时间单位ms # 公式真实时间 目标时间 * (1 ppm/1e6) compensated_ms target_ms * (1 ppm / 1000000) return int(compensated_ms) # 使用示例计划睡眠 24 小时86400000 ms real_sleep_ms get_compensated_sleep_ms(86400000) rtc.alarm(0, real_sleep_ms // 1000) # alarm 参数是秒3.2 避免“唤醒即死”RTC 告警的原子性与中断抢占另一个高频故障是RTC 告警触发后系统刚唤醒还没来得及执行rtc.alarm_left(0)查询剩余时间就被另一个高优先级中断比如 UART 接收中断打断导致alarm_left()返回错误值进而误判为“闹钟已过期”程序逻辑崩溃。根本原因在于rtc.alarm_left()是一个非原子操作它需要读取多个寄存器并做减法。RP2040 的 RTC 寄存器在唤醒瞬间处于不稳定状态必须等待一个“稳定窗口”。官方推荐的稳定时间是 100μs但实测在低温或低压下需要 500μs 才可靠。我的解决办法是在deepsleep()返回后的第一行代码插入一个精确的time.sleep_us(500)然后再访问 RTC 寄存器import time import machine # ... 睡眠前的清理工作 ... # 进入深度睡眠 machine.deepsleep() # 以下代码在唤醒后执行 time.sleep_us(500) # 强制等待 RTC 寄存器稳定 # 现在可以安全读取 remaining rtc.alarm_left(0) if remaining 0: print(闹钟已触发开始执行任务) # 执行你的采集、上传等逻辑 else: print(f闹钟未触发剩余 {remaining} 秒)提示time.sleep_us()在 MicroPython 中是纳秒级精度的它比time.sleep_ms(1)更可靠因为后者在底层会触发调度器引入不可预测的延迟。4. 低功耗通信的“生死线”UART、I2C、SPI 在睡眠唤醒周期中的协同设计绝大多数 Pico 低功耗项目最终都要把采集的数据发出去。而通信外设恰恰是功耗大户。UART 在 115200 波特率下发送一个字节就要消耗约 1.2mA 电流I2C 总线若上拉电阻选得过大如 10kΩ在长距离布线时上升沿变缓主控需要更长时间等待 ACK间接拉长了通信总耗时。这就引出了一个核心矛盾通信越快瞬时功耗越高通信越慢总耗时越长平均功耗未必降低。必须找到那个“最优通信窗口”。4.1 UART 的“脉冲式”通信策略发完即走绝不恋战我测试过三种 UART 通信模式在发送 32 字节 JSON 数据时的总能耗使用 INA219 电流传感器记录模式描述总耗时峰值电流平均电流总能耗 (μJ)持续发送uart.write(data)后立即uart.read(1)等待响应285ms8.3mA4.1mA965脉冲发送uart.write(data)不读响应发完立刻uart.deinit()112ms9.7mA7.2mA812硬件流控启用 RTS/CTS严格控制发送节奏342ms5.8mA2.9mA995结论反直觉峰值电流最高、但总时间最短的“脉冲发送”模式总能耗最低。因为它把能量集中在最短时间内释放避免了长时间的“低效等待”。这就像短跑运动员冲刺 10 秒比匀速走 100 秒消耗的总能量还少。实施要点发送前确保 UART 已初始化波特率设为最高可靠值Pico 在 3.3V 下115200 是安全上限发送后立刻调用uart.deinit()彻底关闭 UART 外设及其时钟如果需要响应改用“唤醒-发送-等待-再睡眠”的两阶段协议第一次唤醒只发请求收到响应后再唤醒一次处理数据。# 脉冲式 UART 发送函数 def uart_pulse_send(uart, data): # 确保 UART 处于活动状态 if not hasattr(uart, _active) or not uart._active: uart.init(baudrate115200, txPin(0), rxPin(1)) uart._active True uart.write(data) # 立即关闭 UART释放所有资源 uart.deinit() uart._active False # 使用 uart_pulse_send(machine.UART(0), b{temp:23.5,hum:45}\n)4.2 I2C 的“冷启动”优化规避上拉电阻的隐性功耗I2C 总线的上拉电阻是常被忽视的功耗源。标准 4.7kΩ 上拉在 3.3V 下当总线被拉低时每个上拉电阻会持续消耗3.3V / 4700Ω ≈ 0.7mA电流。如果挂了 3 个设备光是上拉电阻就吃掉 2.1mA——这已经超过了 Pico 深度睡眠的总电流解决方案是用 MOSFET 开关控制上拉电阻的供电。我设计了一个简单的电路一个 N-MOSFET如 2N7002其栅极接 Pico 的一个 GPIO如 GP22源极接地漏极接上拉电阻的 VCC 端。这样只有在需要通信时才把 GP22 拉高给上拉电阻供电通信结束立刻拉低 GP22切断上拉电阻的电流路径。硬件改动极小软件只需两行# 初始化上拉供电控制引脚 pullup_en machine.Pin(22, machine.Pin.OUT, value0) def i2c_wake(): pullup_en.value(1) # 通电 time.sleep_us(10) # 等待电压稳定 # 此时再初始化 I2C 并通信 i2c machine.I2C(0, sdaPin(4), sclPin(5), freq400000) def i2c_sleep(): i2c.deinit() # 先关闭 I2C 外设 pullup_en.value(0) # 再切断上拉供电实测效果在挂载 BME280 和 SSD1306 的双设备 I2C 总线上此方案将通信前的待机电流从 2.3mA 降至 0.8μA降幅达 99.96%。4.3 SPI 的“片选即生命”CS 信号的时序与电平陷阱SPI 通信中片选CS信号的状态直接决定了从设备是否“在线”。很多开发者以为只要spi.write()结束从设备就自动休眠了。错。BME680、ADS1115 等常见传感器其休眠指令必须通过 SPI 发送特定命令字且 CS 信号必须在整个命令传输过程中保持稳定低电平。如果 CS 在命令中途被意外拉高从设备会认为指令中断停留在不确定状态持续消耗电流。我用逻辑分析仪抓过一次 ADS1115 的通信波形CS 信号在发送0x01休眠命令的第三个时钟周期被拉高结果 ADS1115 的电流从 0.1μA休眠态飙升到 150μA待机态且再也无法恢复。正确做法是将 CS 引脚的控制权完全交给软件禁用任何硬件自动管理。MicroPython 的SPI类不提供 CS 管理必须手动控制# 手动管理 CS 的 SPI 通信 cs_pin machine.Pin(17, machine.Pin.OUT, value1) # 初始高电平设备未选中 spi machine.SPI(0, baudrate1000000, sckPin(18), mosiPin(19), misoPin(16)) def spi_write_with_cs(spi, cs_pin, data): cs_pin.value(0) # 选中设备 time.sleep_us(1) # 确保建立时间 spi.write(data) time.sleep_us(1) # 确保保持时间 cs_pin.value(1) # 取消选中 # 发送休眠命令以 ADS1115 为例 spi_write_with_cs(spi, cs_pin, b\x01) # 0x01 是 ADS1115 的休眠命令5. 实战避坑指南从“能跑通”到“能量产”的 7 个血泪教训以上所有原理和代码都源于我在将 Pico 低功耗方案从实验室推向实际部署时踩过的 7 个具体坑。它们不写在任何官方文档里但每一个都足以让一个本该续航一年的节点在两周内耗尽电池。5.1 坑一USB 串口调试器的“暗电流”——拔掉它功耗立降 120μA这是最基础也最容易被忽略的坑。当你用 USB-TTL 模块如 CH340、CP2102连接 Pico 进行调试时模块上的 3.3V 稳压器会通过 Pico 的 VBUS 引脚向 Pico 的 3.3V 电源轨注入电流。即使 Pico 处于深度睡眠这部分电流依然存在且无法被软件关闭。实测一块 CP2102 模块在 Pico 睡眠时贡献了 123μA 的额外电流。解决方案所有功耗测试必须在完全脱离 USB 连接的状态下进行。使用电池供电并用万用表的 μA 档直接跨接在电池正极与 Pico VIN 引脚之间测量。调试信息改用 LoRa 或 BLE 模块无线回传或写入内部 Flash 日志待节点唤醒后再批量上传。5.2 坑二MicroPython 固件版本的“功耗后门”——1.19.1 比 1.22.1 低 8μA不同版本的 MicroPython 固件其底层 C 代码对 RP2040 电源管理寄存器的操作逻辑不同。我在对比测试中发现使用pico-micropython-1.19.1.uf2固件时深度睡眠电流稳定在 2.8μA而升级到pico-micropython-1.22.1.uf2后同一块硬件、同一份代码电流升至 10.6μA。深入分析固件源码后发现1.22.1 版本为了兼容 Pico W 的 WiFi 功能在deepsleep()前多执行了一次psm_set_vreg_to_pass()调用该调用会将 LDO 稳压器切换到更高功耗的“pass-through”模式。解决方案对于纯 Pico非 Pico W项目锁定使用 1.19.1 或更早的稳定版固件。不要盲目追求最新版。固件下载地址在 Raspberry Pi 官网的 “Legacy MicroPython releases” 页面。5.3 坑三ADC 通道的“幽灵采样”——不关闭它就在后台偷偷耗电Pico 的 ADC 是一个独立的模拟模块即使你从未调用过machine.ADC()只要其时钟被使能默认是使能的ADC 模块就会持续进行后台校准和噪声采样消耗约 3.5μA 电流。这个值在数据手册的 “Power Consumption” 表格里有明确标注但被藏在“ADC active, no conversion”这一行。解决方案在睡眠前必须显式关闭 ADC 时钟。RP2040 的 ADC 时钟位于 PSM 寄存器的ADC_CLK位偏移量0x20# 关闭 ADC 时钟 PSM_BASE 0x4000c000 machine.mem32[PSM_BASE 0x20] 05.4 坑四内部温度传感器的“热失控”——它不关你就别想低功耗Pico 的内部温度传感器machine.temperature()是一个独立的模拟前端其使能位在ADC_CS寄存器地址0x4004c000的TEMP_SENSE_EN位bit 3。这个位在芯片复位后默认为 0关闭但一旦你调用过machine.temperature()MicroPython 的底层驱动就会将其置 1并且不会在deepsleep()时自动清零。结果就是睡眠时温度传感器仍在工作消耗 2.1μA。解决方案在睡眠前手动清零该位# 关闭内部温度传感器 ADC_CS_REG 0x4004c000 machine.mem32[ADC_CS_REG] ~(1 3) # 清除 bit 35.5 坑五Flash 写入的“擦除风暴”——一次flash.write()可能触发 4KB 擦除Pico 的内部 Flash 是以 4KB 为扇区进行擦除的。当你用uos.dupterm()或自定义日志函数频繁向 Flash 写入小数据时文件系统如 LittleFS为了保证一致性可能会触发整个扇区的擦除操作。一次擦除操作峰值电流可达 25mA持续时间约 100ms总能耗巨大。更糟的是擦除会显著缩短 Flash 寿命。解决方案禁用所有运行时 Flash 写入。日志改用环形内存缓冲区RAM buffer只在唤醒后、通信前将缓冲区内容一次性打包发送。或者使用外部 SPI Flash如 W25Q80其擦除粒度更小4KB 或 64KB且可独立供电控制。5.6 坑六PCB 布线的“寄生电容”——1cm 长的未铺铜走线等效 0.8pF在高频、低功耗设计中PCB 就是电路的一部分。我曾设计过一块 Pico 底板所有元件布局完美但 GP23RTC 闹钟输出引脚旁有一段 1.2cm 长、未铺铜的 0.2mm 宽走线。这段走线与地平面形成了约 0.8pF 的寄生电容。在 RTC 闹钟触发的瞬间这个电容需要被充电导致唤醒延时增加了 3.2μs更重要的是它在每次唤醒时都产生一个微小的电流尖峰长期累积使平均电流上升了 0.3μA。解决方案所有低功耗敏感信号线RTC、唤醒 GPIO、ADC 输入必须遵循“短、直、包地”原则。长度尽量控制在 5mm 以内走线两侧用地线包围关键信号线下方必须是完整地平面。用嘉立创的免费 PCB 设计工具其 DRC设计规则检查能帮你标出所有违规走线。5.7 坑七电池自放电的“终极杀手”——CR2032 的月自放电率高达 3%所有关于“Pico 深度睡眠电流 2.5μACR2032 220mAh 电池可续航 10 年”的计算都忽略了一个残酷事实CR2032 纽扣电池自身的月自放电率在 1%-3% 之间。这意味着即使 Pico 电流为 0一块全新的 CR2032放在抽屉里三个月电量也会损失 5%-10%。而 Pico 的实际深度睡眠电流考虑所有优化后约为 3.5μA其理论续航是(220mAh * 1000) / 3.5μA ≈ 6.3 年但扣除电池自放电有效寿命不足 2 年。解决方案对续航要求严苛的项目放弃 CR2032改用 ER14250 等锂亚硫酰氯电池。其年自放电率低于 1%且标称电压 3.6V 更匹配 Pico 的宽电压输入范围1.8V-5.5V。虽然成本高 3 倍但换来的是真正的“十年免维护”。6. 一套可直接抄作业的“低功耗启动模板”把上面所有知识点浓缩成一份开箱即用的 MicroPython 模板。它不是一个玩具 Demo而是一个经过 37 次迭代、已在 12 个野外监测点稳定运行超 6 个月的生产级代码骨架。你可以直接复制替换你的业务逻辑就能获得接近理论极限的功耗表现。# low_power_template.py import machine import time from machine import Pin, UART, I2C, ADC, RTC # 1. 硬件资源预定义 # 请根据你的实际硬件修改以下引脚号 WAKE_GPIO_PIN 21 # GPIO 唤醒引脚 RTC_ALARM_SEC 300 # RTC 唤醒间隔秒建议从 300 开始测试 VCC_ADC_CHANNEL 4 # 内部 VCC 测量通道 UART_TX_PIN 0 # UART 发送引脚 UART_RX_PIN 1 # UART 接收引脚 I2C_SDA_PIN 4 # I2C SDA 引脚 I2C_SCL_PIN 5 # I2C SCL 引脚 PULLUP_EN_PIN 22 # I2C 上拉供电控制引脚如使用 # 2. 全局状态管理 class LowPowerManager: def __init__(self): self.rtc RTC() self.vcc_adc ADC(VCC_ADC_CHANNEL) self.wake_pin Pin(WAKE_GPIO_PIN, Pin.IN, Pin.PULL_DOWN) self.pullup_en Pin(PULLUP_EN_PIN, Pin.OUT, value0) if PULLUP_EN_PIN else None def _disable_periph_clocks(self): 关闭所有外设时钟 PSM_BASE 0x4000c000 # 关闭 UART0/1, SPI0/1, I2C0/1, ADC for offset in [0x04, 0x08, 0x10, 0x14, 0x18, 0x1c, 0x20]: machine.mem32[PSM_BASE offset] 0 def _reset_io_pins(self): 重置所有未使用 IO 为安全状态 safe_pins [0,1,2,3,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,22,23,24,25,26,27,28] for p in safe_pins: try: Pin(p, Pin.IN, Pin.PULL_DOWN)
返回列表