NeoPixel example
This documents Python example code for the 50mm 12 NeoPixel (WS2812B) Ring connected to a BBC micro:bit through the micro:bit Python Editor.
Assumptions
- This example code uses the micro:bit Python NeoPixel library with initialization np = neopixel.NeoPixel(pin2, 12)to initialize $12$ NeoPixels connected toDIonpin2. The NeoPixel library works onpin0,pin1, orpin2.pin2is the nearest clippable micro:bit pin to the3VandGNDclippable pins.
- The 50mm 12 NeoPixel (WS2812B) Ring mounting holes are 2mm diameter on the corners of a 32mm square.
- The 50mm 12 NeoPixel (WS2812B) Ring electrical connector has 4 solder-pad connections that are on 0.1” centers and are ≈2.54mm × ≈1.27mm. The pins are:
| Pin | Signal | I/O | Notes | 
|---|---|---|---|
| 1 | DI | I | DI (input) | 
| 2 | 5V | +V | +5-7V | 
| 3 | GND | ⏚ | 0V | 
| 4 | DO | O | DO (output to further NeoPixel strands) | 

- NeoPixels can take RGB values on $[0, 255]$, but saturate at brightness levels $> 30$. Limiting each color to $30$ also limits the current needed to $\approx 12\%$ of the $60$ ma quoted as the maximum for a WS2812B NeoPixel (or $7$ ma).
- To limit the RGB color values to $< 30$ the example code uses the compressfunction to compress values on $[0, 1)$ to generate integers up to a maximum value on an exponential scale such that smaller values cover a larger part of the range and larger values cover a smaller part of the range. This is shown on a Desmos graph.
- The example code includes random_lightsandchase_lightsfunctions.- random_lightscreates $12$ random colors with- compressed RGB color values $< 30$ then uses the unbiased Fisher-Yates (aka Knuth) algorithm to shuffle them every- delayms.
- chase_lightscreates $12$ colors scaled by $\frac{i}{12}$ for $i$ on $[\negthinspace[ 0, 12 )\negthinspace)$ with- compressed RGB color values $< 30$ then rotates them every- delayms.
 
- The example event loop sets random NeoPixels and shuffles them every delayms untilbutton_ais pressed, then sets chasing NeoPixels everydelayms untilbutton_ais pressed, then repeats.
Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# Imports go at the top
from microbit import *
import math, neopixel, random
np = neopixel.NeoPixel(pin2, 12)
n, delay, maximum = 12, 200, 30
# https://stackoverflow.com/a/2450976/17467335
# The de-facto unbiased shuffle algorithm is the Fisher-Yates
# (aka Knuth) Shuffle.
# See https://github.com/coolaj86/knuth-shuffle.
def shuffle(array):
    """Return array shuffled in place with the unbiased Fisher-Yates
    (aka Knuth) algorithm."""
    current_index = len(array)
    # While there remain elements to shuffle...
    while 0 != current_index:
        # Pick a remaining element...
        random_index = int(random.random() * current_index)
        current_index -= 1
        # And swap it with the current element.
        array[current_index], array[random_index] = \
            array[random_index], array[current_index]
    return array
def compress(x, scale=1):
    """Return x on [0, 1) exponentially compressed, scaled to scale,
    and floored."""
    # https://www.desmos.com/calculator/gdcw7rndv2
    # The compression factor of 4 is good. It must be greater than e
    # for color[j] > 0.
    return int(math.exp(4 * (x - 1)) * scale)
def random_lights(n=12, maximum=30):
    """Return n random leds with maximum brightness (< 256)."""
    leds, color = [tuple(), ] * n, [0, ] * 3
    for i in range(len(leds)):
        for j in range(len(color)):
            color[j] = compress(random.random(), maximum)
        leds[i] = tuple(color)
    return leds
def chase_lights(rot, color=(102, 51, 153, ), n=12, maximum=30):
    """Return n leds of color divided over n steps scaled by maximum
    rotated by rot."""
    leds = [tuple(), ] * n
    for i in range(len(leds)):
        scaled = [ compress(c / 255 * i / n, maximum) for c in color ]
        leds[i] = tuple(scaled)
    # Rotate by rot.
    return leds[rot: ] + leds[: rot]
# Code in a 'while True:' loop repeats forever
while True:
    # Set random leds and shuffle every delay ms until button_a pressed.
    leds = random_lights(n, maximum)
    while not button_a.was_pressed():
        leds = shuffle(leds)
        for j in range(len(leds)):
            np[j] = leds[j]
        np.show()
        sleep(delay)
    # Set chasing leds every delay ms until button_a pressed.
    chase = 0
    while not button_a.was_pressed():
        leds = chase_lights(chase, (0, 255, 0, ))   # chase green leds
        for j in range(len(leds)):
            np[j] = leds[j]
        np.show()
        sleep(delay)
        chase = (chase + 1) % 12
1234567890123456789012345678901234567890123456789012345678901234567890
Links
| Link | Description | 
|---|---|
| https://www.desmos.com/calculator/gdcw7rndv2 | Desmos exponential compression graph | 
| https://universal-solder.ca/12-led-ring-ws2812b-rgb-addressable-50mm/ | 50mm 12 NeoPixel (WS2812B) Ring available from Universal Solder | 
| https://photos.app.goo.gl/hWqZB8di2HHBCWo19 | A 50mm 12 NeoPixel (WS2812B) Ring with soldered 0.1” headers and wired through a KS0360 Keyestudio Sensor Shield V2 | 
| https://photos.app.goo.gl/zHPtcBgjWh99wYCZ6 | micro:bit examples videos (NeoPixel Ring & Snake) | 
| https://tech.microbit.org/hardware/edgeconnector/ | micro:bit pinouts | 
| https://microbit-micropython.readthedocs.io/en/v2-docs/neopixel.html | micro:bit Python NeoPixel | 
| https://docs.python.org/3.4/ | Python 3.4 documentation | 
#microbit #embedded #Python
