You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Raspberry Pi Pico W运行WS2812代码多次后出现ENOMEM内存错误求助

Raspberry Pi Pico W WS2812呼吸灯代码内存错误(OSError: [Errno 12] ENOMEM)彻底解决方法

我使用WS2812呼吸灯代码在Thonny中多次运行后,出现以下错误:

OSError: [Errno 12] ENOMEM

用nuke.uf2清除Pico W存储只能临时解决,多次运行后错误依旧复现。原代码如下:

###############################################################
# WS2812 RGB LED Ring Light Breathing
# with the Raspberry Pi Pico Microcontroller
#
# by Joshua Hrisko, Maker Portal LLC (c) 2021
#
# Based on the Example neopixel_ring at:
# https://github.com/raspberrypi/pico-micropython-examples
###############################################################
#
import array, time
from machine import Pin
import rp2

#
############################################
# RP2040 PIO and Pin Configurations
############################################
#
# WS2812 LED Ring Configuration
led_count = 12 # number of LEDs in ring light
PIN_NUM = 1 # pin connected to ring light
brightness = 0.2 # 0.1 = darker, 1.0 = brightest

@rp2.asm_pio(sideset_init=rp2.PIO.OUT_LOW, out_shiftdir=rp2.PIO.SHIFT_LEFT,
             autopull=True, pull_thresh=24) # PIO configuration

# define WS2812 parameters
def ws2812():
    T1 = 2
    T2 = 5
    T3 = 3
    wrap_target()
    label("bitloop")
    out(x, 1)               .side(0)    [T3 - 1]
    jmp(not_x, "do_zero")   .side(1)    [T1 - 1]
    jmp("bitloop")          .side(1)    [T2 - 1]
    label("do_zero")
    nop()                   .side(0)    [T2 - 1]
    wrap()

# Create the StateMachine with the ws2812 program, outputting on pre-defined pin
# at the 8MHz frequency
sm = rp2.StateMachine(0, ws2812, freq=8_000_000, sideset_base=Pin(PIN_NUM))

# Activate the state machine
sm.active(1)

# Range of LEDs stored in an array
ar = array.array("I", [0 for _ in range(led_count)])
#
############################################
# Functions for RGB Coloring
############################################
#
def pixels_show(brightness_input=brightness):
    dimmer_ar = array.array("I", [0 for _ in range(led_count)])
    for ii,cc in enumerate(ar):
        r = int(((cc >> 8) & 0xFF) * brightness_input) # 8-bit red dimmed to brightness
        g = int(((cc >> 16) & 0xFF) * brightness_input) # 8-bit green dimmed to brightness
        b = int((cc & 0xFF) * brightness_input) # 8-bit blue dimmed to brightness
        dimmer_ar[ii] = (g<<16) + (r<<8) + b # 24-bit color dimmed to brightness
    sm.put(dimmer_ar, 8) # update the state machine with new colors
    time.sleep_ms(10)

def pixels_set(i, color):
    ar[i] = (color[1]<<16) + (color[0]<<8) + color[2] # set 24-bit color

def breathing_led(color):
    step = 5
    breath_amps = [ii for ii in range(0,255,step)]
    breath_amps.extend([ii for ii in range(255,-1,-step)])
    for ii in breath_amps:
        for jj in range(len(ar)):
            pixels_set(jj, color) # show all colors
        pixels_show(ii/255)
        time.sleep(0.02)
#
############################################
# Main Calls and Loops
############################################
#
# color specifications
red = (255,0,0)
green = (0,255,0)
blue = (0,0,255)
yellow = (255,255,0)
cyan = (0,255,255)
white = (255,255,255)
blank = (0,0,0)
colors = [blue,yellow,cyan,red,green,white]

while True: # loop indefinitely
for color in colors: # emulate breathing LED (similar to Amazon's Alexa)
breathing_led(color)
time.sleep(0.1) # wait between colors

问题根源

  1. 重复内存分配:每次调用pixels_show都会新建dimmer_ar数组,breathing_led每次执行都重新生成breath_amps列表,频繁分配内存导致碎片积累,最终耗尽可用内存。
  2. 资源残留:Thonny多次运行代码时,旧的StateMachine实例、全局变量未被彻底回收,持续占用内存。
  3. 代码缩进错误:原代码主循环的while和for语句无缩进,导致逻辑异常,加剧内存问题。

彻底解决方法

1. 优化内存复用

将需要重复使用的数组、列表提前初始化,避免每次调用都新建对象:

  • 预生成breath_amps呼吸曲线列表,作为全局常量复用。
  • 预创建dimmer_ar调光数组,在pixels_show中只更新内容而非新建。

2. 清理残留资源

在代码开头添加检查,确保旧的StateMachine被关闭后再重新创建,避免多次运行时资源泄漏。

3. 修复代码缩进

修正主循环的缩进错误,保证逻辑正常执行。

修复后的完整代码

###############################################################
# WS2812 RGB LED Ring Light Breathing
# with the Raspberry Pi Pico Microcontroller
#
# by Joshua Hrisko, Maker Portal LLC (c) 2021
#
# Based on the Example neopixel_ring at:
# https://github.com/raspberrypi/pico-micropython-examples
###############################################################
#
import array, time, gc
from machine import Pin
import rp2

#
############################################
# RP2040 PIO and Pin Configurations
############################################
#
# WS2812 LED Ring Configuration
led_count = 12 # number of LEDs in ring light
PIN_NUM = 1 # pin connected to ring light
brightness = 0.2 # 0.1 = darker, 1.0 = brightest

# 预生成呼吸曲线列表,全局复用
step = 5
breath_amps = list(range(0, 255, step)) + list(range(255, -1, -step))

@rp2.asm_pio(sideset_init=rp2.PIO.OUT_LOW, out_shiftdir=rp2.PIO.SHIFT_LEFT,
             autopull=True, pull_thresh=24) # PIO configuration

# define WS2812 parameters
def ws2812():
    T1 = 2
    T2 = 5
    T3 = 3
    wrap_target()
    label("bitloop")
    out(x, 1)               .side(0)    [T3 - 1]
    jmp(not_x, "do_zero")   .side(1)    [T1 - 1]
    jmp("bitloop")          .side(1)    [T2 - 1]
    label("do_zero")
    nop()                   .side(0)    [T2 - 1]
    wrap()

# 检查并关闭旧的StateMachine(防止多次运行残留)
try:
    sm.active(0)
except NameError:
    pass
# Create the StateMachine with the ws2812 program, outputting on pre-defined pin
# at the 8MHz frequency
sm = rp2.StateMachine(0, ws2812, freq=8_000_000, sideset_base=Pin(PIN_NUM))

# Activate the state machine
sm.active(1)

# Range of LEDs stored in an array
ar = array.array("I", [0 for _ in range(led_count)])
# 预创建调光数组,全局复用
dimmer_ar = array.array("I", [0 for _ in range(led_count)])
#
############################################
# Functions for RGB Coloring
############################################
#
def pixels_show(brightness_input=brightness):
    global dimmer_ar
    for ii, cc in enumerate(ar):
        r = int(((cc >> 8) & 0xFF) * brightness_input) # 8-bit red dimmed to brightness
        g = int(((cc >> 16) & 0xFF) * brightness_input) # 8-bit green dimmed to brightness
        b = int((cc & 0xFF) * brightness_input) # 8-bit blue dimmed to brightness
        dimmer_ar[ii] = (g<<16) + (r<<8) + b # 24-bit color dimmed to brightness
    sm.put(dimmer_ar, 8) # update the state machine with new colors
    time.sleep_ms(10)

def pixels_set(i, color):
    ar[i] = (color[1]<<16) + (color[0]<<8) + color[2] # set 24-bit color

def breathing_led(color):
    global breath_amps
    for ii in breath_amps:
        for jj in range(len(ar)):
            pixels_set(jj, color) # show all colors
        pixels_show(ii/255)
        time.sleep(0.02)
#
############################################
# Main Calls and Loops
############################################
#
# color specifications
red = (255,0,0)
green = (0,255,0)
blue = (0,0,255)
yellow = (255,255,0)
cyan = (0,255,255)
white = (255,255,255)
blank = (0,0,0)
colors = [blue,yellow,cyan,red,green,white]

while True: # loop indefinitely
    for color in colors: # emulate breathing LED (similar to Amazon's Alexa)
        breathing_led(color)
        time.sleep(0.1) # wait between colors
    gc.collect() # 定期触发垃圾回收,清理内存碎片

额外建议

  • 使用Thonny的「Stop」按钮停止程序后,再重新运行,避免残留资源占用内存。
  • 若需长期运行,可适当调整gc.collect()的触发频率,平衡性能与内存回收效果。

内容的提问来源于stack exchange,提问作者JohanW28

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 00:30:54