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
问题根源
- 重复内存分配:每次调用
pixels_show都会新建dimmer_ar数组,breathing_led每次执行都重新生成breath_amps列表,频繁分配内存导致碎片积累,最终耗尽可用内存。 - 资源残留:Thonny多次运行代码时,旧的StateMachine实例、全局变量未被彻底回收,持续占用内存。
- 代码缩进错误:原代码主循环的
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
相关产品推荐
相关产品推荐

