Alors que je travaillais encore sur la roulette à bande LED, j'ai eu l'idée d'une autre utilisation pour ces luminaires universels. En un clin d'œil, j'ai créé un thermomètre à partir d'une bande LED d'un mètre de long avec 60 LED Neopixel. La construction est si simple que le projet convient très bien aux débutants en matière de microcontrôleurs : dans le cas le plus simple, seules quatre pièces sont nécessaires. Je vous montre la procédure dans ce nouvel épisode de la série.
MicroPython sur ESP8266, ESP32 et Raspberry Pi Pico
aujourd'hui
Le thermomètre à bande LED
Le programme du thermomètre est bien sûr écrit en MicroPython et de manière à pouvoir fonctionner sans modification sur tous les contrôleurs mentionnés dans le titre. Avec deux boutons supplémentaires, qui ne sont toutefois utilisés que pour la gravure du micrologiciel, même le plus petit représentant de la famille ESP8266, l'ESP8266-01S, peut servir d'unité de commande pour la bande LED. Le programme d'exploitation du thermomètre est adapté à ce contrôleur avec ses deux broches GPIO : GPIO0 commande les LED de la bande, tandis que GPIO2 réalise la connexion bus à un fil vers le DS18B20. Comme la carte de l'ESP8266-01S ne contient pas de convertisseur de tension de 5 V à 3,3 V, nous avons besoin d'un circuit externe. La connexion à l'USB doit également être assurée par un adaptateur USB-TTL externe. Cela complète la liste de tout le matériel nécessaire.
Matériel
| 1 | ESP32 Dev Kit C sans soudure ou ESP32 Dev Kit C V4 non soudé ou Module ESP32 NodeMCU Carte de développement WiFi avec CP2102 ou Module ESP8266 01S esp-01S Wlan WiFi avec adaptateur pour plaque d'essai ou D1 Mini V3 NodeMCU avec ESP8266-12F ou NodeMCU Lua Lolin V3 Module ESP8266 ESP-12F WIFI Wifi Development Board avec CH340 ou NodeMCU Lua Amica Module V2 ESP8266 ESP-12F WIFI Carte de développement Wifi avec CP2102 ou D1 Mini V4 Module WLAN NodeMCU ESP8266EX avec connexion USB-C compatible avec Arduino ou |
| 1 | |
| 1 | DS18B20 Capteur de température numérique TO92 ou Câble de 1 m Capteur de température numérique DS18B20 en acier inoxydable |
| 1 | Résistance 10 kΩ |
| 2 | En option pour ESP8266-01S Boutons, par exemple module de boutons KY-004 |
| 1 | en cas d'utilisation d'un ESP8266-01S |
| 1 | en cas d'utilisation d'un ESP8266-01S |
| 1 |
Comme le montrent les schémas ci-dessous, la configuration est plus simple à réaliser avec un ESP32 ou un ESP8266. Avec l'ESP8266-01S, vous avez besoin d'un convertisseur de 5 V à 3,3 V et également pour Pour graver le micrologiciel, deux boutons sont nécessaires, car la petite carte ne dispose ni d'un système de gravure automatique, comme ses grandes sœurs, ni d'un régulateur de tension intégré. En revanche, la résistance de rappel à la ligne de signal du DS18B20 n'est pas nécessaire. Pour la connexion à l'USB, un adaptateur USB-TTL est également nécessaire, mais celui-ci n'est utilisé que pendant la phase de développement du programme et ensuite pour graver le programme d'exploitation ledstrip_thermo.py.
Pour un fonctionnement à long terme, la bande LED doit être alimentée en 5 V à partir d'un bloc d'alimentation, la consommation électrique maximale du contrôleur et des LED étant d'environ 80 à 120 mA. Certaines cartes ESP8266 acceptent des tensions externes via le connecteur Vin, mais ne fournissent pas les 5 V du connecteur USB. Les cartes ESP32 et le Raspberry Pi Pico , cela fonctionne. Avec ces contrôleurs, la bande LED peut donc être alimentée directement par USB. Si vous souhaitez utiliser l'appareil fini indépendamment du PC, vous ne pouvez guère éviter d'utiliser un bloc d'alimentation, à moins d'utiliser une batterie Li en combinaison avec un support de batterie approprié. Celui-ci fournit également 5 V et 3,3 V avecune capacité de charge de 1 A chacun. Avec une charge, le circuit fonctionne environ 24 heures.
Voici maintenant les schémas de câblage.

Illustration 1: Thermomètre à LED ESP8266 D1 mini

Illustration 2: Thermomètre LED ESP32

Illustration 3: Thermomètre à LED ESP8266-01S

Illustration 4: Thermomètre LED - Raspi Pi Pico
Les schémas de câblage reflètent également le type de montage. Le montage avec l'ESP8266-01S est quelque peu chaotique en raison des composants supplémentaires. L'utilisation d'un support de batterie avec une batterie Li permet d'éviter l'utilisation du régulateur de tension de 5 V à 3,3 V. Tous les ESP sont équipés du micrologiciel 19.1.

Illustration 5: Structure avec ESP8266-01S
Le tout est très clair avec un ESP8266 NodeMcu V3.

Illustration 6: Structure avec ESP8266-NodeMcu V3
Le logiciel
Pour le flashage et la programmation de l'ESP32 :
Thonny ou
Pour afficher les signaux de bus
SALEAE – Logiciel d'analyse logique (64 bits) pour Windows 8, 10, 11
Firmware utilisé pour l'ESP32 :
Firmware utilisé pour l'ESP8266 :
ESP8266_GENERIC-FLASH_1M-20220618-v1.19.1.bin
Firmware utilisé pour le Raspberry Pi Pico (W) :
RPI_PICO_W-20240602-v1.23.0.uf2
Les programmes MicroPython pour le projet :
ledstrip_thermo.py: programme d'exploitation du thermomètre
MicroPython - Langage - Modules et programmes
Vous trouverez ici des instructions détaillées (version anglaise) pour l'installation de Thonny. Vous y trouverez également une description de la manière d'installer le micrologiciel Micropython (version du 25/01/2024) sur la puce ESP brûlé. Pour savoir comment mettre en service le Raspberry Pi Pico, rendez-vous ici.
MicroPython est un langage interprété. La principale différence avec l'IDE Arduino, où vous flashez toujours et exclusivement des programmes complets, est que vous ne devez flasher le firmware MicroPython qu'une seule fois au début sur l'ESP32 pour que le contrôleur comprenne les instructions MicroPython. Vous pouvez utiliser Thonny, µPyCraft ou esptool.py à cette fin. Pour Thonny, j'ai décrit le processus ici.
Une fois le micrologiciel flashé, vous pouvez facilement communiquer avec votre contrôleur, tester des commandes individuelles et voir immédiatement la réponse sans avoir à compiler et transférer tout un programme au préalable. C'est exactement ce qui me dérange dans l'IDE Arduino. On gagne énormément de temps lorsqu'on peut tester au préalable la syntaxe et le matériel, mais aussi essayer et affiner des fonctions et des parties entières du programme via la ligne de commande, avant de créer un programme à partir de là. À cette fin, j'aime créer régulièrement de petits programmes de test. Ils regroupent des commandes récurrentes sous forme de macros. Ces fragments de programme permettent parfois de développer des applications complètes.
démarrage automatique
Si vous souhaitez que le programme démarre automatiquement à la mise sous tension du contrôleur, copiez le texte du programme dans un nouveau fichier vierge. Enregistrez ce fichier sous le nom main.py dans l'espace de travail et téléchargez-le sur la puce ESP. Le programme démarrera automatiquement lors de la prochaine réinitialisation ou mise sous tension.
Tester les programmes
Les programmes sont lancés manuellement à partir de la fenêtre d'édition actuelle dans l'IDE Thonny à l'aide de la touche F5. Cela est plus rapide que de cliquer avec la souris sur le bouton Démarrer ou via le menu Exécuter. Seuls les modules utilisés dans le programme doivent se trouver dans la mémoire Flash de l'ESP32.
Encore une fois l'IDE Arduino entre-temps ?
Si vous souhaitez réutiliser le contrôleur avec l'IDE Arduino ultérieurement, il vous suffit de flasher le programme de la manière habituelle. Cependant, l'ESP32/ESP8266 aura alors oublié qu'il a déjà utilisé MicroPython. À l'inverse, toute puce Espressif contenant un programme compilé à partir de l'IDE Arduino ou le micrologiciel AT ou LUA ou ... peut être facilement équipée du micrologiciel MicroPython. La procédure est toujours celle décrite ici.
Le programme d'exploitation
Le programme est aussi clair que les structures. Grâce à En choisissant GPIO2 comme connexion bus à un fil et GPIO0 comme ligne bus de commande pour la bande Neopixel, le programme fonctionne sans modification sur tous les contrôleurs mentionnés ci-dessus. Les différentes unités fonctionnelles sont définies sous forme de fonctions.
Pour la famille ESP8266, j'ai souvent constaté que le contrôleur plantait peu après le démarrage. Cela semble être dû au fait qu'il tente d'établir une connexion avec un point d'accès via l'unité WLAN. Pour contourner ce problème, je désactive web-REPL immédiatement après avoir flashé un nouveau firmware. Cela a considérablement stabilisé le comportement au démarrage.
Les GPIO des 8266 ont également les désignations de LUA. Un tableau de conversion est très utile dans ce contexte lors de la programmation, notamment en ce qui concerne les différents niveaux de tension qui doivent être respectés lors du démarrage afin que le processus se déroule sans erreur. Passons maintenant en revue les parties du programme et leur fonction.
# ledstrip_thermo.py
# Après avoir flashé le firmware sur l'ESP8266 :
# import webrepl_setup
# > d pour désactiver
# Puis RST ; redémarrage !
# Pintranslator pour cartes ESP8266
#Broches LUA D0 D1 D2 D3 D4 D5 D6 D7 D8 RX TX
#Broches ESP8266 16 5 4 0 2 14 12 13 15 3 1
#Attention hi sc sd hihi lo hi hi
# utilisé DSLE
from machine import Pin
from time import sleep
from onewire import OneWire
from ds18x20 import DS18X20
from neopixel import NeoPixel
from sys import exit, platform
Pour les opérations d'importation, nous utilisons uniquement des modules intégrés dans le noyau MicroPython. Nous voulons adresser les broches GPIO, laisser le contrôleur en veille entre-temps, nous avons besoin du bus One-Wire pour le capteur de température DS18B20 et NeoPixel nous fournit un tableau pour les informations de couleur ainsi que la fonction write(), avec laquelle nous envoyons le contenu du tampon via le bus Neopixel.
dsPin=Pin(2) # ESP8266 (D4)
ds = DS18X20(OneWire(dsPin))
device = ds.scan()[0]
ds.convert_temp()
sleep(0,750)
imprimer(device,ds.read_temp(device))
GPIO2 devient notre connexion bus One-Wire. OneWire(dsPin) génère l'objet bus que nous transmettons immédiatement au constructeur de la classe DS18X20. La fonction scan() de l'objet DS18X20 recherche les composants sur le bus et, espérons-le, trouvera celui que nous recherchons, à savoir notre DS18B20. L'identifiant ROM du composant est un objet bytearray à huit valeurs qui est couvert dans une liste avec d'autres identifiants éventuels.
>>> ds.scan()
[bytearray(b'(\xffd\x0ei\x0f\x01>')]
Comme nous n'avons qu'un seul DS18B20 sur le bus, nous sélectionnons le 0e élément de la liste.
>>> ds.scan()[0]
bytearray(b'(\xffd\x0ei\x0f\x01>')
L'identifiant est utilisé pour adresser séparément les différentes puces sur le bus. convert_temp() ordonne à toutes les puces de démarrer une mesure. Après au moins 750 ms, nous pouvons récupérer le résultat à l'aide de la fonction read_temp(). L'identifiant correspondant du composant doit être transmis. Nous l'avons enregistré dans device.
led=broche(0,broche.OUT,value =0) # ESP8266 (D3)
numOfPix=60
np=NeoPixel(led,numOfPix)
pos0 = 20
maxTemp=39
minTemp=-20
temp=[0 for i dans range(60)]
Nous définissons le connecteur bus Neopixel GPIO0 comme sortie et fixons le niveau à 0. Le bus doit commander numOfPix = 60 LED. Le constructeur de la classe NeoPixel génère l'objet np. La LED numéro 20 indique le point zéro de l'échelle du thermomètre. Notre échelle s'étend donc de -20 °C (LED numéro 0) à 39 °C (LED numéro 59). Dans la liste temp, nous créons 60 éléments à l'aide d'une compréhension de liste, qui ont d'abord simplement la valeur 0. La liste reprendra plus tard la représentation en couleurs de l'échelle.
à partir de=(0,0,0)
vert=(0,64,0)
bleu foncé=(0,0,4)
bleu clair=(0,0,128)
rouge foncé=(4,0,0)
rouge clair=(128,0,0)
magenta =(2,0,2)
statered=0
stateblue=0
stategreen=0
Les valeurs de couleur pour les LED Neopixel sont indiquées pardes triplets. Les trois valeurs représentent les proportions de rouge, de vert et de bleu.
Les LED situées au-dessus de l'affichage de la température actuelle sont effacées (éteintes = (0,0,0)), le point zéro est représenté par un vert clair. Les dizaines dans la plage positive s'allument en rouge clair, dans la plage négative en bleu clair. Les valeurs intermédiaires sont représentées dans des couleurs plus sombres. Pour faciliter l'orientation, je laisse les cinq s'allumer en magenta foncé. Lorsque la température dépasse 40 °C, la LED supérieure doit clignoter, et lorsqu'elle est inférieure à -20 °C, c'est la LED inférieure qui clignote. Le point zéro est toujours allumé. Afin de pouvoir distinguer -1 °C de 0 °C, la LED zéro degré clignote dans ce dernier cas. J'utilise les trois variables d'état pour contrôler ces états.
def setScale() :
for i dans range(20) :
temp[i]=bleu foncé
for i dans range(21,60) :
temp[i]=rouge foncé
for i dans [0,10] :
temp[i]=
for i in [30,40,50] :
temp[i]=rouge clair
for i in range(5,60,10) :
temp[i]=magenta
temp[20]=vert
La fonction setScale() remplit la liste temp avec les valeurs de couleur. La plage négative est d'abord colorée en bleu foncé, la plage positive en rouge foncé. Les limites de plage et les valeurs de liste dans les instructions for correspondent aux numéros de place des LED dans la bande. Les niveaux de 10 sont ensuite remplacés par du bleu clair et du rouge clair. Je remplace les niveaux de 5, à partir du numéro de LED 5, par des niveaux de 10 jusqu'au numéro 55 en magenta foncé. Je définis enfin la place 20 sur vert.
def (température) :
t=min(température,maxTemp)
t=max(minTemp,t)
maxpix =int(t) + pos0
for i dans range(maxpix + 1):
np[i]=temp [i]
for i dans range(maxpix + 1,numOfPix) :
np[i]=à partir de
if t < 0:
np[pos0]=vert
np.écrire()
La fonction fillAndShow() est pour ainsi dire le cœur du programme, l'affichage de la température. Les valeurs de couleur de la liste temp sont transférées dans la mémoire tampon np de l'objet NeoPixel.
Informations générales :
La mémoire tampon de l'objet NeoPixel est en fait un tableau d'octets avec l'identifiant buf. Dans notre cas, elle peut être référencée avec np.buf. Le contenu se compose de groupes de trois éléments consécutifs pour chaque LED. Si np[2]=(1,2,3) la valeur de couleur pour la LED numéro 2 est transmise sous forme de tuple, puis la fonction cachée __setitem__() convertit le tuple en une séquence d'objets bytes et écrit les valeurs dans le bytearray np.buf. Si nous regardons le contenu de np.buf, nous constatons que l'ordre des octets a été modifié.
>>> np[2]=(1,2,3)
>>> np.buf
bytearray(b'\x00\x00\x80\x00\x00\x04\x02\x01\x03\x00\x00\x04\x00\x00\x04 …
Les valeurs RVB sont converties conformément à l'attribut np.ORDER.
>>> np.ORDER
(1, 0, 2, 3)
Si nous transmettons R=1, G=2 et B=3, les valeurs G, R, B sont enregistrées dans la mémoire tampon. Avec 3, une valeur blanche serait transmise, mais celle-ci n'est pas prise en charge par le type de LED utilisé.
Mais examinons maintenant de plus près la fonction fillAndShow(). Lors de l'appel, la valeur de température actuelle est transmise au paramètre température, qui doit se situer dans la plage autorisée afin que le programme ne soit pas interrompu par une erreur. t=min(température,maxTemp) garantit que t ne dépasse pas la température maximale affichable. min() renvoie la valeur minimale parmi les valeurs transmises. t=max(minTemp,t) est responsable du respect de la limite inférieure.
Il faut maintenant déterminer le numéro de la LED correspondant à la température en t. Nous prenons la partie entière de la valeur de la température et nivelons le point zéro de l'échelle Celsius sur la position 20 de la chaîne de LED. < span lang="DE" style="font-size: 10.0pt; font-family: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; color: black;">maxpix = int(t) + pos0
Nous remplissons ensuite le tampon jusqu'à la limite calculée avec le contenu de l'échelle.
for i dans range(maxpix + 1) :
np [i]=temp[i]
Nous réglons le reste des LED situées au-dessus sur off=0,0,0.
for i dans range(maxpix + 1,numOfPix):
np[i]=
Si la température est négative, nous activons également le point zéro. Ensuite, nous envoyons le contenu du tampon à l'écran.
if t < 0:
np[pos0]=vert
np.écrire()
Nous pouvons désactiver l'ensemble de la bande LED à l'aide de la fonction clearStrip(). Nous décrivons le tampon avec des tuples (0,0,0).
clearStrip() :
for i dans range(numOfPix) :
np[i]=à partir de
np.écrire()
Nous gérons les trois événements clignotants pour les températures supérieures et inférieures à la normale ainsi que pour 0 °C à l'aide des trois fonctions binkRed(), blinkBlue() et blinkGreen(). Elles ont toutes la même structure. Nous allons examiner de plus près la fonction blinkRed() à titre d'exemple.
def blinkRed():
global statered
if statered == 1:
np[numOfPix-1]=Extrait de
np.écrire()
statered = 0
else:
np[numOfPix-1]=rouge foncé
np.écrire()
statered = 1
La valeur de la variable statered est modifiée dans la procédure et doit être à nouveau disponible lors du prochain appel. Pour y parvenir, on peut utiliser des variables globales. Sans la déclaration global, la variable disparaîtrait dans le néant à la sortie de la fonction. Une autre façon de rendre la variable statique serait d'utiliser une fermeture. Suivez le lien si vous souhaitez en savoir plus à ce sujet. Pour les débutants, nous nous en tiendrons à la première solution, plus simple.
Si statered est égal à 1, la LED supérieure doit être éteinte. numOfPix a la valeur 60. La LED supérieure porte donc le numéro 59, car la numérotation commence à 0. Nous envoyons l'état (de toutes les LED !) à la bande avec np.write() et définissons statered sur 0.
Lors du prochain appel, la branche else est exécutée. Nous définissons le contenu de la LED supérieure sur rouge foncé, envoyons le tampon et attribuons la valeur 1 à statered.
Nous traitons de manière analogue la LED inférieure (numéro 0) et la LED du point zéro à la position pos0 = 20.
def blinkBlue():
global stateblue
if stateblue == 1:
np[0]=désactivé
np.écrire()
stateblue = 0
else:
np[0]=bleu clair
np.écrire()
stateblue = 1
def blinkGreen():
global stategreen
if stategreen == 1:
np[pos0]=à partir de
np.écrire()
stategreen = 0
else:
np[pos0]=vert
np.écrire()
stategreen = 1
Grâce à l'utilisation de fonctions, nous créons une vue d'ensemble dans le programme principal, qui ne comprend ainsi que 15 lignes.
Nous générons l'échelle du thermomètre et effaçons les LED, puis nous entrons dans la boucle principale.
setScale()
clearStrip()
La mesure de la valeur de température actuelle est déclenchée. Le contrôleur peut compter les moutons pendant une seconde, puis détermine la valeur entière de la température lue en arrondissant.
while 1:
ds.convert_temp()
sleep(1)
t =int(ds.read_temp(device) + 0,5)
imprimer(t,« C »)
fillAndShow(t)
if t < minTemp:
blinkBlue()
if t > maxTemp:
blinkRed()
if t == 0:
blinkGreen()
Nous pouvons supprimer la commande d'impression en mode production. fillAndShow() affiche la température sur la bande, comme décrit ci-dessus. Les constructions if nous permettent de traiter les cas particuliers.
Voici le listing complet du programme ledstrip_thermo.py:
# ledstrip_thermo.py
# Après avoir flashé le firmware sur l'ESP8266 :
# import webrepl_setup
# > d pour désactiver
# Puis RST ; redémarrage !
# Pintranslator pour cartes ESP8266
#Broches LUA D0 D1 D2 D3 D4 D5 D6 D7 D8 RX TX
#Broches ESP8266 16 5 4 0 2 14 12 13 15 3 1
#Attention hi sc sd hihi lo hi hi
# utilisé OLED DS LE
de machine import Pin
from time import sleep
from onewire import OneWire
from ds18x20 import DS18X20
from neopixel NeoPixel
from sys import exit, platform
touche=broche(0,broche.IN,Pin.PULL_UP)
dsPin=broche(2) # ESP8266 (D4)
ds = DS18X20(OneWire(dsPin))
device = ds.scan()[0]ds.convert_temp()
sleep(0,750)
imprimer(device,ds.read_temp(device))
led= (0,épingle.OUT,valeur=0) # ESP8266 (D3)
numOfPix=60
np=NeoPixel(led,numOfPix)
pos0 = 20
maxTemp=39
minTemp=-20
temp=[0 for i dans range(60)]
de=(0,0,0)
vert=(0,64,0)
bleu foncé=(0,0,4)
bleu clair=(0,0,128)
rouge foncé=(4,0,0)
rouge clair=(128,0,0
magenta=(2,0,2)
statered=0
stateblue=0
stategreen=0
def setScale() :
for i dans range(20) :
temp[i]=bleu foncé
for i dans range(21,60) :
temp[i]=rouge foncé
for i dans [0,10] :
temp[i]=bleu clair
for i in [30,40,50] :
temp[i]=rouge clair
for i dans range(5 ,60,10) :
temptemp[i]=magenta
temp[20]=vert
def fillAndShow(température) :
t=min(température,maxTemp)
t=max(minTemp,t)
maxpix = int(t) + pos0
for i in range(maxpix + 1) :
np[i]=temp[i]
for i in range(maxpix + 1,numOfPix) :
np[i]=à partir de
if t < 0:
np [pos0]=vert
np.write()
def clearStrip() :
for i dans range(numOfPix) :
np[i]=à partir de
np.écrire()
def blinkRed() :
global statered
if statered == 1:
np[numOfPix-1]=désactivé
np.écrire()
statered = 0
else:
np [numOfPix-1]=rouge foncé
np.écrire()
statered = 1
def blinkBlue():
global stateblue
if stateblue == 1:
np[0]=désactivé
np.écrire()
stateblue = 0
else:
np[0]=bleu clair
np.écrire()
stateblue = 1
def blinkGreen():
global stategreen
if stategreen == 1:
np[pos0]=à partir de
np.écrire()
stategreen = 0
else:
np[pos0]=vert
np.écrire()
stategreen = 1
setScale ()
clearStrip()
while 1:
ds.convert_temp()
sleep(1)
t=int(ds.read_temp(device) + 0,5)
imprimer(t,« C »)
fillAndShow(t)
if t < minTemp:
blinkBlue()
if t > maxTemp:
blinkRed()
if t == :
blinkGreen()
Pour être indépendants du PC et de l'USB, nous pouvons télécharger le programme sous le nom main.py dans la mémoire flash du contrôleur. Une alimentation de 5 V suffit désormais pour que le programme démarre automatiquement au prochain redémarrage ou après une réinitialisation.
Voici à quoi ressemble la partie autour du zéro en fonctionnement.

Illustration 7: affichage du thermomètre de -6 °C à 2 °C
Perspectives :
Le choix des couleurs pour les LED nous laisse plusieurs possibilités. On pourrait par exemple connecter un deuxième capteur pour la température extérieure au bus One-Wire et faire basculer l'affichage toutes les cinq secondes. En utilisant des couleurs différentes pour les deux zones, on pourrait facilement distinguer la température extérieure de la température intérieure.
L'utilisation d'un lecteur de carte SD et d'un RTC permet d'enregistrer les mesures avec précision pour une évaluation ultérieure.
Si nous utilisons la fonction Wi-Fi de nos contrôleurs, les données mesurées peuvent également être facilement transférées vers un téléphone portable, une tablette ou un serveur.
Nous vous souhaitons beaucoup de plaisir dans vos futures recherches, bricolages et programmations.






