vesperW · 6月24日

基于Pico和MicroPython点亮ws2812彩色灯带

  • Introduction
  • Practice
  • Conclusion

Introduction

点亮发光的LED灯是简单有趣的实验,点亮多个ws2812小灯串联起来的灯带,可对多个彩色小灯进行编程,从而实现各种有趣的显示效果。多个ws2812使用串联的方式级联在一起,微控制器以发出长短脉冲的序列控制彩色小灯显示的颜色和亮度。

此处略过控制ws2812发光的原理和控制方法,直接动手实验,讲述基于Pico电路板和MicroPython点亮ws2812彩色灯带的学习、调试和操作过程。调试过程中,使用了来自电子森林的Step-Pico电路板,同树莓派官方的RPI Pico电路板兼容,但换用了Type-C插座、新增了复位按键,以及4个ws2812彩灯级联起来的灯带,实际使用起来更加方便。

image.png
Step Pico上连接ws2812彩灯部分的原理图

Practice

在网上搜索到比较靠谱的关于使用MicroPython点亮ws2812彩灯的资料,大多来自于github上的micropythno-ws2812项目:

对于访问github不便的开发者,笔者在国内的gitee开源代码站点上做了个镜像(https://gitee.com/suyong_yq/m...),方便获取源码。如图x所示。

image.png
图x 在开源站点上的micropython-ws2812项目

这个项目基于早期使用STM32微控制器的pyb电路板开发,估计也能兼容Pico板子上的MicroPython,其中提供了一些有趣的用例。按照说明,开发者需要先将ws2812.py文件导入到MicroPython中,此处导入到Pico板子上的/lib目录下。如图x所示。

image.png
图x 导入ws2812b.py到Pico上的MicroPython

然后,运行代码仓库提供的用例:

from ws2812 import WS2812

ring = 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 show
  File "/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_count
        self.intensity = intensity

        # prepare SPI data buffer (4 bytes for each color)
        self.buf_length = self.led_count * 3 * 4
        self.buf = bytearray(self.buf_length)

        # SPI init
        self.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 !!!

image.png
图x 点亮ws2812灯带实验

Conclusion

在github上开源的micropython-ws2812项目的基础上,新增了指定SPI_SOUT引脚的实例化参数,实现了基于Pico电路板和MicroPython点亮ws2812b彩色灯带的效果。调试过程在Step Pico电路板上验证成功。

作者:安德鲁苏
来源:安德鲁的设计笔记本

推荐阅读

欢迎大家点赞留言,更多Arm技术文章动态请关注极术社区嵌入式客栈专栏欢迎添加极术小姐姐微信(id:aijishu20)加入技术交流群,请备注研究方向。

推荐阅读
关注数
2891
内容数
284
分享一些在嵌入式应用开发方面的浅见,广交朋友
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息