基于Pico和MicroPython点亮ws2812彩色灯带
文章目录
- 基于Pico和MicroPython点亮ws2812彩色灯带
- Introduction
- Practice
- Conclusion
Introduction
点亮发光的LED灯是简单有趣的实验,点亮多个ws2812
小灯串联起来的灯带,可对多个彩色小灯进行编程,从而实现各种有趣的显示效果。多个ws2812
使用串联的方式级联在一起,微控制器以发出长短脉冲的序列控制彩色小灯显示的颜色和亮度。
此处略过控制ws2812
发光的原理和控制方法,直接动手实验,讲述基于Pico
电路板和MicroPython
点亮ws2812
彩色灯带的学习、调试和操作过程。调试过程中,使用了来自电子森林的Step-Pico
电路板,同树莓派官方的RPI Pico
电路板兼容,但换用了Type-C
插座、新增了复位按键,以及4个ws2812
彩灯级联起来的灯带,实际使用起来更加方便。
Practice
在网上搜索到比较靠谱的关于使用MicroPython点亮ws2812彩灯的资料,大多来自于github上的micropythno-ws2812
项目:
- https://github.com/JanBednarik/micropython-ws2812
对于访问github不便的开发者,笔者在国内的gitee开源代码站点上做了个镜像(https://gitee.com/suyong_yq/micropython-ws2812),方便获取源码。如图x所示。
这个项目基于早期使用STM32
微控制器的pyb
电路板开发,估计也能兼容Pico板子上的MicroPython,其中提供了一些有趣的用例。按照说明,开发者需要先将ws2812.py
文件导入到MicroPython中,此处导入到Pico板子上的/lib
目录下。如图x所示。
然后,运行代码仓库提供的用例:
from ws2812 import WS2812ring = WS2812(spi_bus=1, led_count=4)data = [(24, 0, 0),(0, 24, 0),(0, 0, 24),(0, 0, 0),
]ring.show(data)
试运行时,发现报错:
>>> %Run -c $EDITOR_CONTENT
Traceback (most recent call last):File "<stdin>", line 6, in <module>File "/lib/ws2812.py", line 45, in __init__
AttributeError: type object 'SPI' has no attribute 'MASTER'
在Pico的REPL中查看MicroPython的SPI类属性,发现确实没有MASTER
这个属性。
>>> import machine
>>> dir(machine)
['__class__', '__name__', 'ADC', 'I2C', 'I2S', 'PWM', 'PWRON_RESET', 'Pin', 'RTC', 'SPI', 'Signal', 'SoftI2C', 'SoftSPI', 'Timer', 'UART', 'USBDevice', 'WDT', 'WDT_RESET', '__dict__', 'bitstream', 'bootloader', 'deepsleep', 'dht_readinto', 'disable_irq', 'enable_irq', 'freq', 'idle', 'lightsleep', 'mem16', 'mem32', 'mem8', 'reset', 'reset_cause', 'soft_reset', 'time_pulse_us', 'unique_id']
>>> from machine import SPI
>>> dir(SPI)
['__class__', '__name__', 'read', 'readinto', 'write', 'LSB', 'MSB', '__bases__', '__dict__', 'deinit', 'init', 'write_readinto']
>>>
但ws2812.py
文件在初始化spi设备时确实使用了MASTER
属性。
# SPI init
self.spi = pyb.SPI(spi_bus, pyb.SPI.MASTER, baudrate=3200000, polarity=0, phase=1)
猜测,这可能是MicroPython版本更新导致的问题,也可能是MicroPython在不同芯片的跨平台设计的问题。
在寻找新的代码之前,我想先试着人工修复一下。毕竟当前的ws2812.py
文件已经把控制逻辑的框架都写好了,只要结合当前的驱动重新做下适配就好。
试着移除pyb.SPI.MASTER
的参数,再运行。还有报错:
>>> %Run -c $EDITOR_CONTENT
Traceback (most recent call last):File "<stdin>", line 6, in <module>File "/lib/ws2812.py", line 48, in __init__File "/lib/ws2812.py", line 57, in showFile "/lib/ws2812.py", line 63, in send_buf
AttributeError: 'SPI' object has no attribute 'send'
试着将send
换成write
,再运行。这个时候已经不报错了。但板子上的ws2812b
彩灯也没亮。
猜测,可能引脚没对上,板子上用GPIO23
接入灯带,但用例中没有指定SPI_SOUT
信号使用的引脚。查一下运行程序后GPIO23
引脚的状态:
>>> machine.Pin(23)
Pin(GPIO23, mode=ALT, pull=PULL_DOWN, alt=31)
此处为未配置alt=31
。但后续实验成功的情况下,GPIO32
引脚的复用功能应为SPI:
>>> machine.Pin(23)
Pin(GPIO23, mode=ALT, alt=SPI)
同时,经过比对原理图发现,当前板子上接入灯带使用的GPIO23
引脚未接入扩展引脚,也就意味着这肯定也不是默认的SPI输出引脚(默认的引脚一定是外接到板子的扩展插针上方便开发者接线)。此时,有两个思路:
- 在当前软件框架下,试着设定使用
GPIO23
作为某个硬件SPI
模块的输出脚 - 再找找别的
ws2812
的库,可以指定控制引脚信号的
在试第一条路的阶段,竟然直接走通了。
在实例化WS2812
对象的实例化函数的参数列表里,加入一个指定输出控制引脚的参数。然后在实例化函数内部实例化SPI
模块实例的时候,指定mosi
参数为传入引脚。为此,有改动如下:
在ws2812.py
文件中,有:
def __init__(self, spi_bus=1, pin=23, led_count=1, intensity=1):"""Params:* spi_bus = SPI bus ID (0, 1 or 2)* pin = output pin to ws2812, mosi of spi* led_count = count of LEDs* intensity = light intensity (float up to 1)"""self.led_count = led_countself.intensity = intensity# prepare SPI data buffer (4 bytes for each color)self.buf_length = self.led_count * 3 * 4self.buf = bytearray(self.buf_length)# SPI initself.spi = pyb.SPI(spi_bus, baudrate=3200000, polarity=0, phase=1, mosi=pyb.Pin(pin, pyb.Pin.OUT))
此处指定默认使用GPIO23
引脚连接灯带,并在实例化SPI
对象时,设定mosi
的引脚为输出Pin.OUT
。
然后,main.py文件中实例化WS2812对象时,传入GPIO23引脚的参数:
ring = WS2812(spi_bus=1, pin=23, led_count=4)
运行,有报错信息:
>>> %Run -c $EDITOR_CONTENT
Traceback (most recent call last):File "<stdin>", line 6, in <module>File "/lib/ws2812.py", line 46, in __init__
ValueError: bad MOSI pin
猜测,可能硬件spi_bus=1
可能没有映射到GPIO23
的信号。换用spi_bus=0
,再试试看:
ring = WS2812(spi_bus=0, pin=23, led_count=4)
运行竟然成功了。没有报错,板子上的ws2812小灯也都亮起来了。Bingo !!!
Conclusion
在github上开源的micropython-ws2812
项目的基础上,新增了指定SPI_SOUT
引脚的实例化参数,实现了基于Pico
电路板和MicroPython
点亮ws2812b
彩色灯带的效果。调试过程在Step Pico
电路板上验证成功。