├── .gitignore ├── LICENSE ├── README.md ├── examples ├── fireflies.py ├── flash.py ├── rainbow.py └── thermometer.py ├── pico_ws2812b.jpg └── ws2812b.py /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | *.bak 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 benevpi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Retired 2 | This library is now retired and won't be getting updates. There's an improved version here: https://github.com/blaz-r/pi_pico_neopixel This version extends the code here and includes support for RGBW LEDs as well as RGB leds with the R, G and B components in a different order. 3 | 4 | I'll leave the code here for the foreseeable future, so feel free to use it, extend it or modify it as you see fit, but the above library is an improvement. 5 | 6 | 7 | # pico_ws2812b 8 | a library for using WS2812b leds (aka neopixels) with Raspberry Pi Pico 9 | 10 | ![neopixels in action]( 11 | https://github.com/benevpi/pico_python_ws2812b/blob/main/pico_ws2812b.jpg) 12 | 13 | 14 | You'll first need to save the ws2812b.py file to your device (for example, open it in Thonny and go file > save as and select MicroPython device. Give it the same name). Once it's there, you can import it into your code. 15 | 16 | You create an object with the parameters number of LEDs, state machine ID and GPIO number in that order. so, to create a strip of 10 leds on state machine 0 and GPIO 0, you use: 17 | 18 | ``` 19 | pixels = ws2812b.ws2812b(10,0,0) 20 | ``` 21 | 22 | This object has two methods, show() which sends the data to the strip, and set_pixel which sets the colour values for a particular LED. The parameters are LED number, red, green, blue with the colours taking values between 0 and 255. 23 | 24 | At the moment, this isn't working with the interpreter, so you have to run it from a file. Looks like it's running just too slow to keep up with the PIO buffer from the interpreter. The key methods are set_pixel(r,g,b), set_pixel_line(p1, p2, r, g, b) which sets a row of pixels from pixel p1 to pixel p2 (inclusive), and fill(r,g,b) which fills all the pixels with the colour r,g,b. 25 | 26 | ``` 27 | pixels.set_pixel(5,10,0,0) 28 | pixels.set_pixel_line(5,7,0,10,0) 29 | pixels.fill(20,5,0) 30 | ``` 31 | 32 | Pull requests are open if you'd like more features! 33 | -------------------------------------------------------------------------------- /examples/fireflies.py: -------------------------------------------------------------------------------- 1 | import time 2 | import ws2812b 3 | import random 4 | 5 | numpix = 50 # Number of NeoPixels 6 | # Pin where NeoPixels are connected 7 | strip = ws2812b.ws2812b(numpix, 0,0) 8 | 9 | colors = [ 10 | [232, 100, 255], # Purple 11 | [200, 200, 20], # Yellow 12 | [30, 200, 200], # Blue 13 | [150,50,10], 14 | [50,200,10], 15 | ] 16 | 17 | max_len=20 18 | min_len = 5 19 | #pixelnum, posn in flash, flash_len, direction 20 | flashing = [] 21 | 22 | num_flashes = 10 23 | 24 | for i in range(num_flashes): 25 | pix = random.randint(0, numpix - 1) 26 | col = random.randint(1, len(colors) - 1) 27 | flash_len = random.randint(min_len, max_len) 28 | flashing.append([pix, colors[col], flash_len, 0, 1]) 29 | 30 | strip.fill(0,0,0) 31 | 32 | while True: 33 | strip.show() 34 | for i in range(num_flashes): 35 | 36 | pix = flashing[i][0] 37 | brightness = (flashing[i][3]/flashing[i][2]) 38 | colr = (int(flashing[i][1][0]*brightness), 39 | int(flashing[i][1][1]*brightness), 40 | int(flashing[i][1][2]*brightness)) 41 | strip.set_pixel(pix, colr[0], colr[1], colr[2]) 42 | 43 | if flashing[i][2] == flashing[i][3]: 44 | flashing[i][4] = -1 45 | if flashing[i][3] == 0 and flashing[i][4] == -1: 46 | pix = random.randint(0, numpix - 1) 47 | col = random.randint(0, len(colors) - 1) 48 | flash_len = random.randint(min_len, max_len) 49 | flashing[i] = [pix, colors[col], flash_len, 0, 1] 50 | flashing[i][3] = flashing[i][3] + flashing[i][4] 51 | time.sleep(0.005) 52 | 53 | 54 | -------------------------------------------------------------------------------- /examples/flash.py: -------------------------------------------------------------------------------- 1 | import time 2 | from ws2812b import ws2812b 3 | 4 | num_leds = 30 5 | pixels = ws2812b(num_leds, 0,0, delay=0) 6 | 7 | pixels.fill(10,10,10) 8 | pixels.show() 9 | 10 | pixels.brightness(200) 11 | 12 | while True: 13 | for i in range(num_leds): 14 | for j in range(num_leds): 15 | pixels.set_pixel(j,abs(i+j)%10,abs(i-(j+3))%10,abs(i-(j+6))%10) 16 | pixels.show() 17 | time.sleep(0.05) 18 | 19 | 20 | -------------------------------------------------------------------------------- /examples/rainbow.py: -------------------------------------------------------------------------------- 1 | import time 2 | import ws2812b 3 | 4 | numpix = 30 5 | strip = ws2812b.ws2812b(numpix, 0,0) 6 | 7 | RED = (255, 0, 0) 8 | ORANGE = (255, 165, 0) 9 | YELLOW = (255, 150, 0) 10 | GREEN = (0, 255, 0) 11 | BLUE = (0, 0, 255) 12 | INDIGO = (75, 0, 130) 13 | VIOLET = (138, 43, 226) 14 | COLORS = (RED, ORANGE, YELLOW, GREEN, BLUE, INDIGO, VIOLET) 15 | 16 | while True: 17 | for color in COLORS: 18 | for i in range(numpix): 19 | strip.set_pixel(i, color[0], color[1], color[2]) 20 | time.sleep(0.01) 21 | strip.show() 22 | -------------------------------------------------------------------------------- /examples/thermometer.py: -------------------------------------------------------------------------------- 1 | import machine 2 | import time 3 | 4 | 5 | num_leds = 30 6 | 7 | 8 | sensor_temp = machine.ADC(4) 9 | blah = machine.ADC(3) # comment or uncomment this line to trigger / untrigger 10 | 11 | 12 | conversion_factor = 3.3 / 65535 13 | 14 | min_temp = 0 15 | max_temp = 30 16 | 17 | while True: 18 | reading = sensor_temp.read_u16() * conversion_factor 19 | temperature = 27 - (reading - 0.706)/0.001721 20 | print(temperature) 21 | time.sleep(0.5) 22 | -------------------------------------------------------------------------------- /pico_ws2812b.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benevpi/pico_python_ws2812b/d2c84512528b6c338b4f21e6c6c379ade2e1ce6c/pico_ws2812b.jpg -------------------------------------------------------------------------------- /ws2812b.py: -------------------------------------------------------------------------------- 1 | import array, time 2 | from machine import Pin 3 | import rp2 4 | 5 | @rp2.asm_pio(sideset_init=rp2.PIO.OUT_LOW, out_shiftdir=rp2.PIO.SHIFT_LEFT, autopull=True, pull_thresh=24) 6 | def ws2812(): 7 | T1 = 2 8 | T2 = 5 9 | T3 = 3 10 | wrap_target() 11 | label("bitloop") 12 | out(x, 1) .side(0) [T3 - 1] 13 | jmp(not_x, "do_zero") .side(1) [T1 - 1] 14 | jmp("bitloop") .side(1) [T2 - 1] 15 | label("do_zero") 16 | nop() .side(0) [T2 - 1] 17 | wrap() 18 | 19 | #delay here is the reset time. You need a pause to reset the LED strip back to the initial LED 20 | #however, if you have quite a bit of processing to do before the next time you update the strip 21 | #you could put in delay=0 (or a lower delay) 22 | class ws2812b: 23 | def __init__(self, num_leds, state_machine, pin, delay=0.001): 24 | self.pixels = array.array("I", [0 for _ in range(num_leds)]) 25 | self.sm = rp2.StateMachine(state_machine, ws2812, freq=8000000, sideset_base=Pin(pin)) 26 | self.sm.active(1) 27 | self.num_leds = num_leds 28 | self.delay = delay 29 | self.brightnessvalue = 255 30 | 31 | # Set the overal value to adjust brightness when updating leds 32 | def brightness(self, brightness = None): 33 | if brightness == None: 34 | return self.brightnessvalue 35 | else: 36 | if (brightness < 1): 37 | brightness = 1 38 | if (brightness > 255): 39 | brightness = 255 40 | self.brightnessvalue = brightness 41 | 42 | # Create a gradient with two RGB colors between "pixel1" and "pixel2" (inclusive) 43 | def set_pixel_line_gradient(self, pixel1, pixel2, left_red, left_green, left_blue, right_red, right_green, right_blue): 44 | if pixel2 - pixel1 == 0: return 45 | 46 | right_pixel = max(pixel1, pixel2) 47 | left_pixel = min(pixel1, pixel2) 48 | 49 | for i in range(right_pixel - left_pixel + 1): 50 | fraction = i / (right_pixel - left_pixel) 51 | red = round((right_red - left_red) * fraction + left_red) 52 | green = round((right_green - left_green) * fraction + left_green) 53 | blue = round((right_blue - left_blue) * fraction + left_blue) 54 | 55 | self.set_pixel(left_pixel + i, red, green, blue) 56 | 57 | # Set an array of pixels starting from "pixel1" to "pixel2" to the desired color. 58 | def set_pixel_line(self, pixel1, pixel2, red, green, blue): 59 | for i in range(pixel1, pixel2+1): 60 | self.set_pixel(i, red, green, blue) 61 | 62 | def set_pixel(self, pixel_num, red, green, blue): 63 | # Adjust color values with brightnesslevel 64 | blue = round(blue * (self.brightness() / 255)) 65 | red = round(red * (self.brightness() / 255)) 66 | green = round(green * (self.brightness() / 255)) 67 | 68 | self.pixels[pixel_num] = blue | red << 8 | green << 16 69 | 70 | # rotate x pixels to the left 71 | def rotate_left(self, num_of_pixels): 72 | if num_of_pixels == None: 73 | num_of_pixels = 1 74 | self.pixels = self.pixels[num_of_pixels:] + self.pixels[:num_of_pixels] 75 | 76 | # rotate x pixels to the right 77 | def rotate_right(self, num_of_pixels): 78 | if num_of_pixels == None: 79 | num_of_pixels = 1 80 | num_of_pixels = -1 * num_of_pixels 81 | self.pixels = self.pixels[num_of_pixels:] + self.pixels[:num_of_pixels] 82 | 83 | def show(self): 84 | for i in range(self.num_leds): 85 | self.sm.put(self.pixels[i],8) 86 | time.sleep(self.delay) 87 | 88 | def fill(self, red, green, blue): 89 | for i in range(self.num_leds): 90 | self.set_pixel(i, red, green, blue) 91 | time.sleep(self.delay) 92 | --------------------------------------------------------------------------------