这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界» 论坛首页» 活动中心» 板卡试用» 【换取手持数字示波器】+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 跳转至

回复

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