这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 活动中心 » 板卡试用 » 【换取手持数字示波器】+pico驱动WS2812灯环

共1条 1/1 1 跳转至

【换取手持数字示波器】+pico驱动WS2812灯环

专家
2024-04-06 15:59:57   被打赏 40 分(兑奖)     打赏

     树莓派pico不仅支持SPI和I2C控制器发送数据,它还有自己的特殊协议:可编程IO。今天就该话题展开学习,使用pico驱动一个12颗RGB灯环。在一般MCU中,可通过寄存器操作将指定的IO口输出高低电平,pico使用MicroPython语言去操作IO输出电平状态,显得更精简。

     树莓派pico与WS2812灯环模块连接如下:

VBUS-------->5V

GND--------->GND

GP0---------->DI

驱动WS2812.png

      使用Thonny软件编写代码如下:

import array, time
from machine import Pin
import rp2
from rp2 import PIO, StateMachine, asm_pio
 
# Configure the number of WS2812 LEDs.
NUM_LEDS = 12
 
@asm_pio(sideset_init=PIO.OUT_LOW, out_shiftdir=PIO.SHIFT_LEFT, autopull=True, pull_thresh=24)
def ws2812():
    T1 = 2
    T2 = 5
    T3 = 3
    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]
 
# Create the StateMachine with the ws2812 program, outputting on Pin(22).
sm = StateMachine(0, ws2812, freq=8000000, sideset_base=Pin(0))
 
# Start the StateMachine, it will wait for data on its FIFO.
sm.active(1)

# Display a pattern on the LEDs via an array of LED RGB values.
ar = array.array("I", [0 for _ in range(NUM_LEDS)])

while True:
    print("blue")
    for j in range(0, 255):
        for i in range(NUM_LEDS):
            ar[i] = j
        sm.put(ar,8)
        time.sleep_ms(10)
     
    print("red")
    for j in range(0, 255):
        for i in range(NUM_LEDS):
            ar[i] = j<<8
        sm.put(ar,8)
        time.sleep_ms(10)
     
    print("green")
     
    for j in range(0, 255):
        for i in range(NUM_LEDS):
            ar[i] = j<<16
        sm.put(ar,8)
        time.sleep_ms(10)
     
    print("white")
    for j in range(0, 255):
        for i in range(NUM_LEDS):
            ar[i]=(j<<16)+(j<<8)+j
        sm.put(ar,8)
        time.sleep_ms(10)

下面就代码进行简要说明:

       代码中每秒发送800000位数据(注意频率是8000000,程序的每个周期是10个时钟周期)。每一位数据都是一个脉冲,一个短脉冲表示0,一个长脉冲表示1。数据进入状态机有两个阶段。第一个是称为先进先出(FIFO)的内存。这是主Python程序发送数据到的地方。第二个是输出移位寄存器(OSR),这就是out()指令获取数据的地方。两者通过拉指令连接,拉指令从FIFO获取数据并将其放在OSR中。然而,由于我们的程序设置了启用autopull的阈值为24,所以每次我们从OSR读取24位时,它将从FIFO重新加载指令out(x,1)从OSR中获取一位数据,并将其放入名为x的变量中(PIO中只有两个可用变量:x和y)。jmp指令告诉代码直接移动到特定的标签,但是它可以有一个条件。指令jmp(not_x,”do_zero”) 告诉代码,如果x的值为0(或者,在逻辑术语中,如果not_x为真,并且not_x是x的反面,在pio级别中,0为假任何其他数字为真),则移动到do_zero。

       在这里,我们跟踪一个名为ar的数组,它保存了我们希望LED拥有的数据。数组中的每个数字都包含了一盏灯上所有三种颜色的数据。格式上它是二进制的。使用PIO的一个问题是,你经常需要处理单个数据位。每一位数据都是1或0,数字可以通过这种方式建立,所以以10为基数的2就是二进制的10。以10为基数的3在二进制中等于11。二进制数的8位中最大的数是11111111,或者以10为基数的255。我们实际上把三个数字存储在一个数字中。这是因为在MicroPython中,整数存储在32位,但每个数字只需要8位。设置RGB颜色:前八位是蓝色,后八位是红色,最后八位是绿色。8位最多可以存储255 个数字,所以每个LED都有255个亮度级别。我们可以使用移位运算符<<来实现这一点。这将在一个数字的末尾加上一 定数量的0,所以如果我们想让LED的红色、绿色和蓝色亮度达到1级,我们将每个值都设为1。

         通过以上编程体验,可以得出如下结论:

PIO状态机使用的语言非常简洁,所以只有少量的指令。

in():移动1到32位到状态机;与out()类似,状态机相反。

push():将数据发送到连接状态机和主存的内存中MicroPython程序。

pull():从连接状态机和主存的内存块中获取数据MicroPython程序。这里我们没有使用它,因为通过在程序中包含 autopull=True,当我们使用 out() 时,会自动发生这种情况。

mov():在两个位置之间移动数据(例如x和y变量)。

irq():控制中断。如果需要触发一个特定的接口程序的MicroPython端运行,就可以使用这些

wait():暂停直到发生一些事情(例如 IO pin 更改了一个设定值或中断发生)。

       pico虽然只有少量的指令,但可以实现大量的通信协议。大多数指令都是用于以某种形式移动数据。如果需要以任何特定的方式准备数据,例如控制LED的颜色,这应该在主MicroPython程序中完成,而不是在PIO程序中。

环形彩灯.zip

12_WS2812.zip




关键词: 换取手持数字示波器     pico驱动WS2812灯环    

共1条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]