1000字范文,内容丰富有趣,学习的好帮手!
1000字范文 > 树莓派40/100 - Pico控制WS2812B 一根信号线实现多种LED灯光效果(1)

树莓派40/100 - Pico控制WS2812B 一根信号线实现多种LED灯光效果(1)

时间:2023-05-20 02:16:51

相关推荐

树莓派40/100 - Pico控制WS2812B 一根信号线实现多种LED灯光效果(1)

从某多平台花了15元钱买了一米长的WS2812B彩灯,用于我的Pico编程试验,这种灯的神奇之处在于只需一根信号线,能够控制串联在一起的30颗LED灯珠(好像能长达1024颗灯),实现各种彩灯效果。

接线非常简单,正极接5V(我的灯带只有1米长,用树莓派Pico供电并不吃力,如果比较长的灯带,需要额外电源),一端接地,树莓派GP15接信号线Din。灯带里面的Do不用管它,它实际上是Dout的意思,信号经过Din处理后,点亮那个灯,吃掉一些字节,再经过Dout出来,从而可以串联更多的灯。

官方文档《Raspberry Pi Pico Python SDK》里有一节介绍PIO控制WS2812灯的代码,直接抄过来,修改一下灯的个数,引脚编号PIN_NUM,代码虽然不理解,但程序可以马上运行。

# Example using PIO to drive a set of WS2812 LEDs.import array, timefrom machine import Pinimport rp2# Configure the number of WS2812 LEDs.NUM_LEDS = 30PIN_NUM = 15brightness = 0.2@rp2.asm_pio(sideset_init=rp2.PIO.OUT_LOW, out_shiftdir=rp2.PIO.SHIFT_LEFT, autopull=True, pull_thresh=24)def ws2812():T1 = 2T2 = 5T3 = 3wrap_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 pinsm = rp2.StateMachine(0, ws2812, freq=8_000_000, sideset_base=Pin(PIN_NUM))# 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)])##########################################################################def pixels_show():dimmer_ar = array.array("I", [0 for _ in range(NUM_LEDS)])for i,c in enumerate(ar):r = int(((c >> 8) & 0xFF) * brightness)g = int(((c >> 16) & 0xFF) * brightness)b = int((c & 0xFF) * brightness)dimmer_ar[i] = (g<<16) + (r<<8) + bsm.put(dimmer_ar, 8)time.sleep_ms(10)def pixels_set(i, color):ar[i] = (color[1]<<16) + (color[0]<<8) + color[2]def pixels_fill(color):for i in range(len(ar)):pixels_set(i, color)def color_chase(color, wait):for i in range(NUM_LEDS):pixels_set(i, color)time.sleep(wait)pixels_show()time.sleep(0.2)def wheel(pos):# Input a value 0 to 255 to get a color value.# The colours are a transition r - g - b - back to r.if pos < 0 or pos > 255:return (0, 0, 0)if pos < 85:return (255 - pos * 3, pos * 3, 0)if pos < 170:pos -= 85return (0, 255 - pos * 3, pos * 3)pos -= 170return (pos * 3, 0, 255 - pos * 3)def rainbow_cycle(wait):for j in range(255):for i in range(NUM_LEDS):rc_index = (i * 256 // NUM_LEDS) + jpixels_set(i, wheel(rc_index & 255))pixels_show()time.sleep(wait)BLACK = (0, 0, 0)RED = (255, 0, 0)YELLOW = (255, 150, 0)GREEN = (0, 255, 0)CYAN = (0, 255, 255)BLUE = (0, 0, 255)PURPLE = (180, 0, 255)WHITE = (255, 255, 255)COLORS = (BLACK, RED, YELLOW, GREEN, CYAN, BLUE, PURPLE, WHITE)print("fills")for color in COLORS: pixels_fill(color)pixels_show()time.sleep(0.2)print("chases")for color in COLORS: color_chase(color, 0.01)print("rainbow")rainbow_cycle(0)

网上还有一个更精简的版本,便于慢慢理解程序的主要逻辑。

import arrayimport utimeimport machineimport rp2NUM_LEDS = 30@rp2.asm_pio(sideset_init=rp2.PIO.OUT_LOW, out_shiftdir=rp2.PIO.SHIFT_LEFT, autopull=True, pull_thresh=24)def ws2812():T1 = 2T2 = 5T3 = 3wrap_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()# 建立状态机,设置输出针的编号sm = rp2.StateMachine(0, ws2812, freq=8_000_000, sideset_base=machine.Pin(15))# 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)])# Cycle colours.for i in range(4 * NUM_LEDS):for j in range(NUM_LEDS):r = j * 100 // (NUM_LEDS - 1)b = 100 - j * 100 // (NUM_LEDS - 1)if j != i % NUM_LEDS:r >>= 3b >>= 3ar[j] = r << 16 | bsm.put(ar, 8)utime.sleep_ms(20)# Fade out.for _ in range(24):for j in range(NUM_LEDS):ar[j] >>= 1sm.put(ar, 8)utime.sleep_ms(50)

看看视频效果:

/x/page/o33047uvo1e.html

树莓派Pico控制WS2812b彩色灯珠

这里用到了PIO(Programmable IO )的概念,可以嵌入汇编语句,细节还有待后面进一步的学习。

还有一个状态机的概念,暂时也不太理解,没关系,先抄着慢慢学。

再来学习一下WS2812B的数据通讯协议,看用户手册,有这样一段话:

数据协议采用单线归零码的通讯方式,像素点在上电复位以后,DIN端接受从控制器传输过来的数据,首先送过来的24bit数据被第一个像素点提取后,送到像素点内部的数据锁存器,剩余的数据经过内部整形处理电路整形放大后通过DO端口开始转发输出给下一个级联的像素点,每经过一个像素点的传输,信号减少24bit。像素点采用自动整形转发技术,使得该像素点的级联个数不受信号传送的限制,仅受限信号传输速度要求。

可以看出,每经过一个像素点,吃掉24个二进制位,信号就是这样从头传到尾的。

这24个二进制位就是颜色的RGB值,不对,是GRB值,与电脑上常见的红绿蓝顺序有点不一样,所以可以在源代码里看到这样的写法:

(g<<16) + (r<<8) + b

说明书中提到的主要特点:

IC控制电路与LED点光源共用一个电源。控制电路与RGB芯片集成在一个5050封装的元器件中,构成一个完整的外控像素点。内置信号整形电路,任何一个像素点收到信号后经过波形整形再输出,保证线路波形畸变不会累加。内置上电复位和掉电复位电路。每个像素点的三基色颜色可实现256级亮度显示,完成16777216种颜色的全真色彩显示。端口扫描频率2KHz/s。串行级联接口,能通过一根信号线完成数据的接收与解码。任意两点传输距离在不超过5米时无需增加任何电路。当刷新速率30帧/秒时,级联数不小于1024点。数据发送速度可达800Kbps。光的颜色高度一致,性价比高。

后记:

WS2812B里的PIO汇编代码,后来也读懂了,详细的解释说明在这里。

推荐阅读:

树莓派Pico开发系列文章

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。