Rubans de LED Neopixel WS2812B et WS2813
Ce tutoriel explique comment mettre en oeuvre un ruban de LED WS2812B ou WS2813 avec MicroPython.
Matériel requis
- Une carte d’extension de base Grove, utile seulement si le ruban Neopixel est piloté via broche numérique et équipé d’un connecteur Grove ;
- La carte NUCLEO-WB55 :
- Un ruban de LED RGB WS2812B Grove ; un anneau de LED RGB Grove ou tout autre dispositif avec un contrôleur de la famille WS28xxx.
Description : Un ruban de led WS2812B ou WS2813, dit Neopixel est constitué d’une succession de LED RGB adressables. On peut définir l’intensité et la couleur de chaque LED via le contrôleur WS28xxx. Les afficheur Neopixel peuvent être gérés par la NUCLEO-WB55 selon deux protocoles :
- Soit en les connectant au bus SPI ;
- Soit en les connectant à une broche numérique exploitant un pilote spécifique disponible (au moins) depuis la révision 1.17 du firmware MicroPython.
Nous allons tour à tour présenter ces deux alternatives de montage.
1. Ruban Neopixel connecté au bus SPI
Le montage
La connectique du ruban de LED WS2812B ou WS2813 est illustrée par le schéma ci-dessous :

La sortie MOSI du SPI1 est utilisée pour envoyer les données au contrôleur WS2812B ou ou WS2813
Ruban de Led | NUCLEO-WB55 |
---|---|
5V | 5V |
D0 | D11 |
GND | GND |
Le code MicroPython pour allumer toutes les LED en rouge
Les scripts présentés ci-après sont disponibles dans la zone de téléchargement.
Il faut récupérer et ajouter le fichier ws2812bstm32.py dans le répertoire du périphérique PYBLASH. Editez maintenant le script main.py et collez-y le code qui suit :
# Ce code a été adapté à partir de 'https://github.com/JanBednarik/micropython-ws2812'.
# Objet du script :
# Programmer un ruban de LED piloté par un contrôleur WS2812.
# Il s'agit d'allumer toute les LED du ruban en rouge.
# Cet exemple utilise un contrôleur SPI paramétré avec un débit (baudrate) de 4000000 bauds/s
from machine import SPI
import ws2812bstm32 # Bibliothèque pour gérer le ruban de LED
from time import sleep_ms
# Le WS2812 est connecté au MOSI du bus SPI
spi = SPI(1)
led_number = const(30)
sleep_ms(1000)
# Initialisation dyu ruban de LED
# Pour le STM32WB55 le débit DOIT être de 4000000 bauds
strip = ws2812bstm32.WS2812B(spi_bus=1, ledNumber=led_number, intensity=0.5, baudrate=4000000)
# Efface le ruban
strip.clear()
strip.show()
# Allume toutes les LED en rouge
for index in range(0, led_number):
strip.put_pixel(index, 255, 0, 0)
strip.show()
sleep_ms(2000)
# Allume / éteint les LED en séquence
for index in range(0, led_number):
if index != 0:
strip.clean(index-1)
strip.put_pixel(index, 0, 0, 255)
strip.show()
sleep_ms(500)
strip.clean(index)
strip.show()
sleep_ms(500)
Le code MicroPython pour afficher un drapeau et le faire défiler
# Ce code a été adapté à partir de 'https://github.com/JanBednarik/micropython-ws2812'.
# Objet du script :
# Programmer un ruban de LED piloté par un contrôleur WS2812.
# Il s'agit d'afficher un drapeau et le faire défiler sur le ruban.
# Cet exemple utilise un contrôleur SPI paramétré avec un débit (baudrate) de 4000000 bauds/s
from machine import SPI
import ws2812bstm32 # Bibliothèque pour gérer le ruban de LED
from time import sleep_ms
french_flag = [
(0,0,250), (0,0,250), (0,0,250),
(250,250,250), (250,250,250), (250,250,250),
(250,0,0), (250,0,0), (250,0,0)]
italien_flag = [
(0,250,0), (0,250,0), (0,250,0),
(250,250,250), (250,250,250), (250,250,250),
(250,0,0), (250,0,0), (250,0,0)]
def dual_flag(leds, data0, data1, num_led, t, display):
i = 0
while i < num_led:
if (i + len(data0)) < num_led:
for d in data0:
leds.put_pixel(i, d[0], d[1], d[2])
if display:
leds.show()
sleep_ms(t)
i+=1
if not display:
leds.show()
i+=1
else:
break
if (i + len(data1)) < num_led:
for d in data1:
leds.put_pixel(i, d[0], d[1], d[2])
if display:
leds.show()
sleep_ms(t)
i+=1
if not display:
leds.show()
i+=1
else:
break
def flag_move(leds, data, num_led, t):
i = 0
while i < num_led:
if (i + len(data)) < num_led:
if i != 0:
leds.clean(i-1)
j = i
for d in data:
leds.put_pixel(j, d[0], d[1], d[2])
j+=1
leds.show()
sleep_ms(t)
i+=1
else:
break
led_number = const(16)
# Initialise le ruban de LED
# Le WS2812 est connecté au MOSI du bus SPI
# Pour le STM32WB55 le baudrate DOIT être 4000000
strip = ws2812bstm32.WS2812B(spi_bus=1, ledNumber=led_number, intensity=0.5, baudrate=4000000)
# Efface le ruban
strip.clear()
strip.show()
# Affiche deux drapeaux
dual_flag(strip, french_flag, italien_flag, led_number, 500, True)
while True:
# Effacement du drapeau
strip.clear()
strip.show()
# Décalage du drapeau
flag_move(strip, french_flag, led_number, 500)
# Effacement du drapeau
strip.clear()
strip.show()
# Décalage du drapeau
flag_move(strip, italien_flag, led_number, 500)
Pour aller plus loin
D’autres exemples sont disponibles dans l’archive téléchargeable MODULES.zip.
2. Ruban Neopixel connecté à une broche numérique
Le montage
On utilise un ruban Neopixel étanche éuipé d’un connecteur Grove, avec 60 LED RGB en série. Connectez le ruban à l’une des broches numériques du Grove Base Shield (dans notre cas, on a choisi la broche D2
), lui même installé sur la NUCLEO-WB55.
Le code MicroPython pour afficher et faire défiler des drapeaux italiens et français
Les scripts présentés ci-après sont disponibles dans la zone de téléchargement.
Il faut récupérer et ajouter le fichier neopixel.py dans le répertoire du périphérique PYBLASH. Editez maintenant le script main.py et collez-y le code qui suit :
# Objet du script : Jeux de lumière avec un ruban Neopixel étanche de Grove (60 LED RGB)
# Nécessite également une NUCLEO-WB55 et un Grove Base Shield.
# Source : Christophe PRIOUZEAU, STMicroelectronics
import machine
import time
# Pour gérer le ruban de LED
import neopixel
class StripLED:
def __init__(self, pin_number, ledNumber, intensity=0.5):
self._pin = pin_number
self._ledNumber = ledNumber
self._intensity = intensity
self._strip = neopixel.NeoPixel(machine.Pin(self._pin), self._ledNumber)
self.french_flag = [
(0,0,250), (0,0,250), (0,0,250),
(250,250,250), (250,250,250), (250,250,250),
(250,0,0), (250,0,0), (250,0,0)]
self.italian_flag = [
(0,250,0), (0,250,0), (0,250,0),
(250,250,250), (250,250,250), (250,250,250),
(250,0,0), (250,0,0), (250,0,0)]
def _set_to_zero(self, addr):
if addr < self._ledNumber:
self._strip[addr] = (0,0,0)
def _color_intensity(self, color):
#print("[debug] [%d, %.2f] %d" % (color, self._intensity, int(color * self._intensity) ))
return int(color * self._intensity)
def set_led(self, addr, red, green, blue):
if addr < self._ledNumber:
self._strip[addr] = (self._color_intensity(red), self._color_intensity(green), self._color_intensity(blue))
def _flag_move(self, data, num_led, t):
i = 0
while i < (num_led+1):
if (i + len(data)) < (num_led+1):
if i != 0:
self._set_to_zero(i-1)
j = i
for d in data:
self.set_led(j, d[0], d[1], d[2])
j+=1
self._strip.write()
time.sleep_ms(t)
i+=1
else:
break
def clear(self):
for i in range(0, self._ledNumber):
self._set_to_zero(i)
self._strip.write()
def get_max_led(self):
return self._ledNumber
def french_flag_move(self, t):
self._flag_move(self.french_flag, self._ledNumber, t)
def italian_flag_move(self, t):
self._flag_move(self.italian_flag, self._ledNumber, t)
def move_dual(self, t):
self._dual_flag(self.french_flag, self.italian_flag, t)
def _dual_flag(self, data0, data1, t):
i = 0
while i < (self._ledNumber+1):
if (i + len(data0)) < (self._ledNumber+1):
for d in data0:
self.set_led(i, d[0], d[1], d[2])
self._strip.write()
time.sleep_ms(t)
i+=1
i+=1
else:
break
if (i + len(data1)) < (self._ledNumber+1):
for d in data1:
self.set_led(i, d[0], d[1], d[2])
self._strip.write()
time.sleep_ms(t)
i+=1
i+=1
else:
break
# -------------------------------------
# MAIN
# -------------------------------------
_NB_LED_RGB = const(60) # Nombre de LED RGB sur le ruban
_INTENSITE_LED = 0.1 # Luminosité des LED (entre 0 et 1)
if __name__ == '__main__':
# Ruban de LED connecté à D2 sur le Grove Base Shield
strip_led = StripLED(pin_number='D2', ledNumber = _NB_LED_RGB, intensity= _INTENSITE_LED)
# Fait défiler un drapeau français au long du ruban
strip_led.clear()
strip_led.french_flag_move(500)
# Fait défiler un drapeau italien au long du ruban
strip_led.clear()
strip_led.italian_flag_move(500)
# "Mappe" selon un cycle le ruban en alternant un drapeau français et un drapeau italien
while True:
strip_led.clear()
strip_led.move_dual(100)
time.sleep(4)