Affichage des articles dont le libellé est Pico. Afficher tous les articles
Affichage des articles dont le libellé est Pico. Afficher tous les articles

mercredi 9 juillet 2025

MIDI IN avec le Raspberry Pi Pico (Micropython)

Dans cet article, nous allons recevoir, au moyen d'un Raspberry Pi Pico programmé en Micropython, les messages MIDI générés par un clavier musical.

Il s'agit de la suite logique de mon précédent article (publié il y a presque deux ans...mieux vaut tard que jamais!) qui traitait de l'émission d'un signal MIDI.

 



Le circuit

J'ai utilisé l'interface MIDI dont j'avais parlée dans cet article. Le circuit permettant la réception de messages MIDI par un microcontrôleur nécessite l'utilisation d'un optocoupleur, afin d'éviter les boucles de masse. Plusieurs options sont possibles; j'ai choisi le H11L1 après avoir vu dans un forum de discussion qu'il s'agissait d'un bon choix pour un microcontrôleur utilisant un niveau logique de 3,3 V. Le schéma du circuit recommandé par la MIDI association peut être consulté ici.

  • La broche 1 du H11L1 est branchée à une résistance de 220 Ω, qui est elle-même connectée à la broche 4 du connecteur MIDI (DIN-5).
  • La broche 2 du H11L1 est branchée à la broche 5 du connecteur MIDI (DIN-5).
  • De plus, une diode pour petits signaux 1N914 est branchée entre les broches 1 et 2 du H11L1.
  • La broche 3 du H11L1 n'est pas connectée.
  • La broche 4 du H11L1 est reliée à l'entrée RX (UART) du Raspeberry Pi Pico, ainsi qu'à une résistance pull-up de 470 Ω qui est elle-même reliée à l'alimentation 3,3 V.
  • La broche 5 du H11L1 est reliée à la masse GND.
  • La broche 6 du H11L1 est reliée à l'alimentation 3,3 V.
(Attention, si l'optocoupleur que vous utilisez n'est pas un H11L1, son brochage pourrait être différent.)

Un câble MIDI relie le connecteur femelle DIN-5 à la sortie MIDI OUT du clavier musical alors que, du côté Raspberry Pi Pico, l'information arrivera par la broche GP5 du Raspberry Pi Pico. 

Numéro des broches du connecteur DIN-5


Script #1: affichage brut des données reçues

Ce premier exemple est volontairement minimaliste: il se contente d'afficher dans la console de Thonny tous les messages MIDI reçus en provenance du clavier musical.

La communication UART est d'abord initialisée (ligne #12). Nous utilisons le bus UART 1, qui est associé aux broches GP4 (TX) et GP5 (RX). Dans ce cas, seule la broche de réception (GP5) sera utile. La vitesse de la communication est réglée à 31 250 bauds, tel que requis par le protocole MIDI.

Ensuite, si nous recevons un message UART, nous l'affichons en format hexadécimal.

Lors de la mise à l'essai d'une première version de ce script, j'ai eu la surprise de voir s'afficher à l'écran une quantité effarante de données alors que je n'avais encore appuyé sur aucune des touches du clavier musical. Les valeurs affichées étaient 0xF8 et 0xFE qui correspondent respectivement à "Timing Clock" et "Active Sensing".  Les messages de type "Timing Clock" servent à synchroniser deux instruments MIDI pour qu'ils soient au même tempo, alors que les messages "Active Sensing" permettent de vérifier constamment qu'un appareil MIDI est toujours branché et actif. La ligne #17 du script désactive donc l'affichage de tous ces messages de type "System Real Time" pour éviter que les données générées par les actions du musicien soient noyées dans un océan de données répétitives inutiles. (Certains claviers MIDI n'émettent pas ces messages)

Affichage de messages "System Real Time"

Voici donc le script en micropython:

-

-

Voyons ce qui est affiché à l'écran lorsque j'appuie sur la note "Do2" de mon clavier:

Appui sur la touche Do2 du clavier musical

 

Trois octets sont envoyées par le clavier:

Le nombre hexadécimal 0x90 représente un message "Note On" sur le canal 1. Il indique que nous avons appuyé sur une touche du clavier. Il existe 16 canaux, qui sont officiellement numérotés de 1 à 16, mais nous les numérotons de 0 à 15 dans un programme. Le nombre hexadécimal 0x91 aurait signifié un message "Note On" sur le canal 2, le nombre hexadécimal 0x92 aurait signifié un message "Note On" sur le canal 3, et ainsi de suite jusqu'à 0x9F, qui représente un "Note On" sur le canal 16.

Un message "Note On" est toujours suivi de deux octets supplémentaires: un nombre qui représente le numéro de la note jouée, et un nombre qui représente la vélocité avec laquelle la touche a été enfoncée.

Ici, nous pouvons constater que j'ai joué la note numéro 0x24 en hexadécimal (ou 36 en décimal), qui correspond à un Do du 2e octave (cette page, qui énumère la signification des différents numéros de notes, peut s'avérer bien utile). Finalement,la vélocité de cette note était de 0x4d (ce qui correspond à 77 en décimal). Ce nombre serait plus grand si j'avais appuyé plus fort sur la touche du clavier.

Voyons maintenant ce qui s'affiche lorsque je relâche la touche de clavier que j'avais enfoncée.

Relâchement de la touche Do2 du clavier musical
 

Lorsque nous relâchons une touche, un instrument MIDI doit générer un message "Note Off". Certains instruments émettent un véritable message Note Off qui correspond à 0x80. D'autres émettent plutôt un "Note On" avec une vélocité de 0. C'est ce que vous pouvez constater sur la saisie d'écran ci-dessus: en relâchant la touche Do2 que j'avais enfoncée, le clavier musical a émis le message 0x90 (Note On), suivi du numéro de la note correspondant à la touche relâchée (0x24), et d'une vélocité nulle (0x0).

La saisie d'écran ci-dessous, réalisée avec un clavier différent, montre les données reçues lorsque la touche "Do2" est d'abord appuyée, puis ensuite relâchée (ce clavier émet un véritable message "Note Off" de 0x80).

Do2 enfoncée, puis relâchée, sur un autre clavier

 

Script #2: Interprétation des messages reçus

Dans ce deuxième exemple, je fais un effort pour présenter les données d'une façon plus compréhensible pour un être humain. Pour simplifier les choses, je me limite aux messages de type Note On ou Note Off reçues sur le canal 1 (0x80 ou 0x90). Je n'afficherai donc pas de message de type "program change", "pitch bend", etc.): le script ne réagit qu'aux touches enfoncées ou relâchées.

Cette fois, le numéro de la note s'affiche en valeur décimale, et le script détermine s'il s'agit d'un do, ou d'un sol, etc. 

La vélocité s'affiche également en valeur décimale, et le script indique si la touche a été enfoncée (note On) ou relâchée.


-

-

Et ensuite?

Maintenant que vous maîtrisez les bases de la réception d'un message MIDI, vous pourriez transformer votre Raspberry Pi Pico en un mini synthétiseur; pour ce faire, vous pourriez vous référer à cet article sur la production d'un son au moyen du Raspberry Pi Pico. 


À lire également:


Yves Pelletier



mardi 5 septembre 2023

MIDI OUT avec le Raspberry Pi Pico (Micropython)

Ce projet consiste à utiliser un Raspberry Pi Pico programmé en Micropython, afin d'envoyer des instructions MIDI à un clavier musical. Le synthétiseur du clavier jouera la musique ayant préalablement été programmée dans le Raspberry Pi Pico.

Circuit

La norme MIDI (Musical Instrument Digital Interface) a été mise au point au début des années 1980 afin de permettre la communication entre divers instruments de musique électronique.

À l'origine, tous les appareils communiquaient en utilisant un niveau logique de 5 V mais puisque le Raspberry Pi Pico (comme la majorité des microcontrôleurs actuels) utilise plutôt un niveau logique de 3,3 V, nous utiliserons le circuit que je vous ai présenté dans le récent article intitulé Fabrication d'un module MIDI (IN et OUT) pour microcontrôleur 3,3 V.

Le circuit est très simple et peut être rapidement monté sur une breadboard. Le seul composant "spécialisé" étant un connecteur DIN-5 femelle dans lequel sera inséré le câble MIDI branché au clavier­. La numérotation des broches de ce connecteur est présenté sur la photographie ci-dessous.

  • Une résistance de 10 Ω est insérée entre la broche GP4 du Raspberry Pi Pico et la broche numéro 5 du connecteur DIN-5 femelle.
  • La broche 2 du connecteur DIN-5 femelle est branchée à une des broches GND du Raspberry Pi Pico.
  • Une résistance de 33 Ω est insérée entre la broche 4 du connecteur DIN-5 femelle et la sortie 3,3 V du Raspberry Pi Pico.  Attention: on recommande une résistance de 0,5 W.  (Pour cette raison, j'ai plutôt utilisé deux résistances de 68 Ω en parallèle)­.

Ce circuit est inspiré des recommandations de la MIDI Association.

Un câble MIDI est inséré dans le connecteur DIN5, et l'autre extrémité du câble est inséré dans le jack MIDI IN du clavier musical.

Script en Micropython #1

Commençons par présenter un script très simple, en Micropython, pour illustrer la procédure: il se contente de ne jouer qu'une seule note.

Les spécifications du protocole MIDI imposent une communication série à une vitesse de 31 250 bauds. Cette vitesse est réglée au début du programme (ligne #15) lorsque nous initialisons le bus UART #1 du Raspberry Pi, qui est lié aux broches GP4 (TX) et GP5 (RX). Dans ce projet, nous n'utilisons que la broche GP4, qui sert à la transmission des données (GP5 serait utile si nous devions recevoir des données, ce qui n'est pas le cas ici).

À la ligne #18, nous réglons le "programme" du synthétiseur, c'est à dire le timbre qui sera utilisé. La norme "General MIDI" définit 128 timbres correspondant à l'imitation d'un instrument de musique. Par exemple, le timbre numéro 57 correspond à un son de trompette. De plus, vous disposez de 16 canaux, chacun de ces canaux pouvant être réglé à son propre timbre (sauf le canal 10, qui est réservé aux percussions).

À la ligne #18, donc, nous assignons un son de trompette au canal 1.  Pour ce faire, nous envoyons un premier octet qui envoie l'instruction "program change" ainsi que le numéro du canal auquel il faut assigner ce timbre:

  • Le nombre hexadécimal C0 modifie le timbre du canal 1
  • Le nombre hexadécimal C1 modifie le timbre du canal 2
  • Le nombre hexadécimal C2 modifie le timbre du canal 3
  • ...
  • Le nombre hexadécimal CF change le timbre du canal 16

Vous l'avez peut-être remarqué: la numérotation officielle des canaux, qui s'adresse aux musiciens plutôt qu'aux programmeurs, va du canal 1 au canal 16 mais dans un programme, nous utilisons les numéros 0 à 15...

Cette instruction est suivie d'un deuxième octet (ligne #19) qui contient le numéro du timbre. Ici encore, les timbres sont officiellement numérotés de 1 à 128 mais nos programmes utilisent une numérotation de 0 à 127. Pour cette raison, nous envoyons "56" parce que la trompette est l'instrument numéro 57!

Pour jouer une note, nous envoyons un message de type "Note On":

  • Le nombre hexadécimal 90 joue une note dans le canal 1
  • Le nombre hexadécimal 91  joue une note dans le canal 2
  • Le nombre hexadécimal 92  joue une note dans le canal 3
  • ...
  • Le nombre hexadécimal 9F  joue une note dans le canal 16

À la ligne #22, nous avons donc envoyé l'instruction 90, en hexadécimal, afin de jouer une note dans le canal 1. 

Il faut aussi lui indiquer quelle note il faut jouer (ligne #23). Le Do4, par exemple, correspond au numéro 60 (voir cette page pour tous les numéros de notes).

Ensuite (ligne #24), il faut envoyer un troisième octet qui indique la vélocité de la note. Plus ce nombre est élevé, plus le volume du son est élevé. 127 représente le maximum.

Nous maintenons ensuite cette note pendant 2 secondes (ligne #26).

En MIDI, il faut envoyer une instruction qui demande explicitement de cesser de jouer la note: c'est le message "note off", qui est très similaire  au message "note on", sauf qu'on remplace le 9 par un 8:

  • Le nombre hexadécimal 80 interrompt une note dans le canal 1
  • Le nombre hexadécimal 81  interrompt une note dans le canal 2
  • Le nombre hexadécimal 82  interrompt une note dans le canal 3
  • ...
  • Le nombre hexadécimal 8F  interrompt une note dans le canal 16

La ligne #29 envoie donc un message "note off" au canal 1.

Il faut ensuite spécifier le numéro de la note qu'on désire interrompre, et il est bien sûr important d'utiliser le même numéro que celui a servi dans le message "note on"! À la ligne #30, nous interrompons la note numéro 60, qui est le do4 qui joue depuis maintenant 2 secondes.

Nous spécifions finalement la vélocité, qui est typiquement nulle pour un message de type "note off". (ligne #31).  (Notez qu'un message "note on" de vélocité nulle aurait eu le même effet qu'on message "note off".)

-

-

Script en Micropython #2

Ce deuxième script joue une mélodie à la basse dans le canal #1, tout en jouant de la batterie dans le canal #10. Ça joue en boucle jusqu'à l'interruption du programme.

-

-

Bibliothèque Micropython-midi-library

Pour des applications plus sérieuses, vous serez peut-être intéressés par la Micropython-midi-library de sensai7. 


À lire également


Yves Pelletier

mardi 29 août 2023

Magnétomètre/boussole HMC5883L et Raspberry Pi Pico (Micropython)

Dans cet article, nous utilisons un module HMC5883L relié à un Raspberry Pi Pico programmé en Micropython, afin de fabriquer une boussole électronique.


Le circuit intégré HMC5883L de la compagnie Honeywell permet de mesurer les 3 composantes (x, y, z) du champ magnétique dans lequel il se trouve. Il existe sur le marché plusieurs module ("breakout") faciles à connecter à un microcontrôleur. Celui que j'ai utilisé comporte 5 connecteurs identifiés VCC, GND, SCL, SDA et DRDY.


Installation du pilote micropython-rp2040-hmc5883l

Il existe quelques sur github quelques pilotes destinés à l'utilisation d'un module HMC5883L, qui semblent tous à peu près identiques. J'ai choisi micropython-rp2040-hmc5883l par SindormirNet. Il faut copier le fichier hmc5883l.py dans la mémoire du Raspberry Pi Pico.


Connexions

J'ai branché le module HMC5883L au Raspberry Pi Pico de cette façon:

  • Broche VCC du module HMC5883L: sortie 3,3 V du Raspberry Pi Pico
  • Broche GND du module HCM5883L: une des broches GND du Raspberry Pi Pico
  • Broche SCL du module HMC5883L: broche GP1 du Raspberry Pi Pico
  • Broche SDA du module HMC5883L: broche GP0 du Raspberry Pi Pico
  • Broche DRDY du module HMC5883L: pas branché


Script #1 (affichage dans la console)

La bibliothèque hmc5883l.py comporte une méthode "heading" qui calcule l'angle de l'axe x du capteur par rapport au nord...dans l'hypothèse extrêmement optimiste que le capteur ne nécessitera pas de calibration.

Dans les faits, le capteur qui mesure la composante dans la direction x n'aura probablement pas la même sensibilité que celui qui mesure la composante dans la direction y, et un champ magnétique nul ne produira pas nécessairement une mesure nulle.

Le script ci-dessous comporte donc une routine qui sert à calibrer les capteurs: on demande à l'utilisateur de faire tourner le module HMC5883L dans un plan horizontal sur au moins un tour complet. Pendant cette rotation, le script garde en mémoire la valeur maximale et la valeur minimale mesurées par le capteur x et par le capteur y. Les mesures brutes sont ensuite recalculées de façon à atténuer les imperfections des capteurs.

Pour que la direction soit affichée en fonction du nord géographique et non en fonction du nord magnétique, il faut que vous écriviez dans le script la valeur de la déclinaison magnétique là où vous êtes (variable "declinaison", à la ligne 18).

-

-

Boussole autonome

J'ai ensuite ajouté un écran OLED à mon circuit, de façon à obtenir une boussole parfaitement autonome qui ne dépend pas d'un ordinateur pour afficher ses mesures.

Il s'agit d'un écran OLED spi de 128 par 64 pixels.


J'ai branché l'écran OLED au Raspberry Pi Pico de cette façon:

  • Broche GND de l'écran: broche GND du Raspberry Pi Pico
  • Broche VCC de l'écran: sortie 3,3 V du Raspberry Pi Pico
  • Broche DO de l'écran: broche GP6 du Raspberry Pi Pico
  • Broche DI de l'écran: broche GP7 du Raspberry Pi Pico
  • Broche RES de l'écran: broche GP14 du Raspberry Pi Pico
  • Broche DC de l'écran: broche GP15 du Raspberry Pi Pico
  • Broche CS de l'écran: broche GP5 du Raspberry Pi Pico

Script #2 (boussole autonome)

Ce script affiche à l'écran OLED un plan cartésien (qui doit être aligné avec celui qui est imprimé sur le module HMC5883L), et une "aiguille de boussole" qui pointe obstinément vers le nord. Encore une fois, pour qu'elle pointe vers le nord géographique, vous devez modifier la valeur de la variable "declinaison" à la ligne 24, pour qu'elle reflète la valeur de la déclinaison magnétique là où vous êtes.


-

-


À lire également:


Yves Pelletier


lundi 24 juillet 2023

Contrôler un Raspberry Pi Pico avec une télécommande de téléviseur (Micropython)

Dans bien des situations, une télécommande à infrarouge constitue une bonne façon d'interagir avec le dispositif électronique que vous avez fabriqué. Dans cet article, je vous explique comment communiquer avec un Raspberry Pi Pico (programmé en Micropython) avec une télécommande à infrarouge conçue pour un téléviseur.


La télécommande

C'est généralement facile de trouver une vieille télécommande à infrarouge. Il y a quelques années,  il y en avait quatre sur ma table de salon: une pour le téléviseur, une pour le lecteur de DVD, une pour le lecteur de cassettes VHS, et une autre pour la chaîne stéréo... Au cours des années, les appareils ont été remplacés ou mis au rancart, mais la télécommande est demeurée fonctionnelle.


Lorsque vous appuyez sur un des boutons de la télécommande, une LED à infrarouge se met à clignoter. Puisqu'il s'agit d'infrarouge et non de lumière visible, vous ne pouvez pas percevoir ce clignotement à l'oeil nu. Par contre, si vous regardez la LED à travers la caméra de votre téléphone, vous devriez la voir s'allumer lorsque vous appuyez sur un des boutons (il s'agit d'une façon rapide et efficace de vérifier qu'une vieille télécommande fonctionne encore).


Ce signal infrarouge transporte un message. Ce qui vient compliquer les choses, c'est qu'il existe un grand nombre de protocoles (NEC, Sony. RC-5, RC-6, Samsung, Panasonic, etc), et la bibliothèque Micropython que nous allons utiliser ne supporte qu'un certain nombre de ces protocoles.

Le récepteur

Pour capter le signal optique émis par la télécommande et le transformer en un signal électrique pouvant être interprété par le Raspberry Pi Pico, vous aurez besoin d'un composant spécialement conçu à cette fin. Pour la rédaction de cet article, j'ai utilisé le TSOP4838 fabriqué par la compagnie Vishay. Une autre option consiste à récupérer le récepteur à l'intérieur d'un vieux téléviseur qui ne fonctionne plus (ce sera possiblement un autre modèle et vous devrez donc faire quelques recherches ou expérimentations).

Le TSOP4838 comporte 3 broches: OUT (le signal de sortie), GND et VCC. 

La façon la plus simple de brancher le TSOP4838 au Raspberry Pi Pico est celle-ci:

  • Broche OUT du  TSOP4838: Broche GP16 du Raspberry Pi Pico
  • Broche GND du TSOP4838: Broche GND du Raspberry Pi Pico
  • Broche VCC du TSOP4838: Broche 3,3 V du Raspberry Pi Pico

Pour améliorer la stabilité du circuit, on peut aussi ajouter une résistance de 100 Ω entre la broche VCC du TSOP4838 et la sortie 3,3 V du Raspberry Pi Pico, ainsi qu'un condensateur de 0,1 µF entre GND et VCC. J'ai testé les deux options sans constater la moindre différence dans le comportement du circuit.


Installation de la bibliothèque micropython_ir 

Nous utiliserons la bilbliothèque micropython_ir mise au point par Peter Hinch. Tout le répertoire "ir_rx" qui doit être copié dans la mémoire du Raspberry Pi Pico.



Identification du protocole utilisé par la télécommande

Pour écrire votre programme en Micropython, il est important de savoir quel est le protocole utilisé par votre télécommande. Si vous ne le connaissez pas, la bibliothèque micropython_ir vous offre deux façon de le découvrir:

Option 1, vous écrivez ceci dans la console REPL:

    from ir_rx.acquire import test
    test()

Option 2, vous écrivez ceci dans la console REPL:

    from ir_rx.test import test

... puis vous choisissez le protocole que vous désirez tester en écrivant test() pour tester le protocole NEC 8 bit, test(1) pour tester le protocole NEC 16 bits, etc.

Je dois dire que j'ai été un peu déçu par le manque d'efficacité de ces tests. L'option 2 s'interrompt généralement en affichant "unknown protocol" avant même que j'aie eu le temps d'appuyer sur un bouton de la télécommande.

L'option 1 me retourne beaucoup de messages d'erreurs, mais lorsque je sélectionne le protocole qui correspond à ma télécommande, des lignes montrant les valeurs hexadécimales de Data, Addr et Ctrl sont affichées (je suggère de maintenir le bouton enfoncé un certain temps, ça permet d'afficher plusieurs lignes consécutives qui sont plus faciles à repérer parmi les lignes qui affichent une erreur).

Ainsi, parmi les télécommandes que j'ai testées, j'en ai trouvé une qui fonctionne selon le protocole "Sony 20 bits", et une autre qui utilise le protocole "Samsung". Comme je le disais plus haut, plusieurs protocoles ne sont pas supportés pour l'instant. Par exemple, ma télécommande Hitachi qui m'avait été bien utile dans certains projets Arduino ne peut pas être utilisée avec micropython_ir.


Exemples de scripts

Une fois que vous connaissez le protocole utilisé par votre télécommande, c'est assez facile d'écrire un programme qui accomplira une action différente selon le bouton qui est enfoncé.

Voici, par exemple, un script qui affiche dans la console les valeurs hexadécimales associées aux boutons de ma télécommande Samsung. Les valeurs de Data et de Addr me permettent de savoir quel bouton de la télécommande a été enfoncé, et je peux ensuite modifier ce programme pour que le Raspberry Pi Pico effectue la tâche qui correspond à ce bouton (allumer une LED, faire tourner un robot vers la droite, etc.).

-

-

Le script ci-dessous est identique, mais pour ma télécommande Sony.

-

-


À lire également:

Yves Pelletier

mardi 18 juillet 2023

Matrice de LEDs RGB 16 X 16 WS2812B et Raspberry Pi Pico (Micropython)

Ce projet consiste à utiliser un Raspberry Pi Pico programmé en Micropython afin de contrôler une matrice de forme carrée comportant 256 LEDs RGB de type Neopixel (contrôleur WS2812B).


Connexions

Le verso de la matrice de LEDs comporte 8 connecteurs mais ils ne sont pas tous nécessaires. Le groupe de 3 fils du côté gauche de la photo (dont un fil porte la mention DOUT) ne sont utiles que lorsque vous désirez brancher plusieurs matrices à la queue-leu-leu.


Si vous n'en utilisez qu'une seule (256 LEDs, c'est déjà pas mal!) vous n'avez besoin que de 4 connexions:

Les deux fils situés au centre (un noir et un rouge) servent à l'alimentation des LEDs. Il faut une tension continue de 5 V, et l'alimentation doit être capable de fournir quelques ampères.

Dans le groupe de trois fils qu'on voit à droite sur la photo, le fil blanc (GND) doit être branché à une des broches GND du Raspberry Pi Pico, alors que le fil vert (DIN), qui transmettra l'information servant à contrôler la couleur et l'intensité de chaque LED sera branché à une broche du Raspberry Pi Pico de votre choix, que nous définirons à l'intérieur de notre programme en Micropython (j'ai utilisé la broche GP15 du Raspberry Pi Pico).

Installation de la bibliothèque NeoPixel

Pour réaliser ce projet, j'ai utilisé le pilote pi_pico_neopixel. Le fichier neopixel.py doit être copié dans le Raspberry Pi Pico.


Exemple 1: lignes mouvantes


Dans ce premier script en micropython, les 16 LEDs d'une même ligne s'allument avec la même couleur, et la couleur est différente pour chaque ligne. Un effet d'animation provoque un déplacement des lignes.


-

-

Le constructeur (ligne 18) requiert 3 paramètres: le nombre de LEDs (dans mon cas, il y en a 256), le numéro d'ID de la machine d'état PIO utilisée par la bibliothèque, et le numéro de la broche du Raspberry Pi Pico à laquelle nous avons branché la matrice de LEDs (dans mon cas, c'était la broche GP15).

pixels = Neopixel(nombre_de_LEDs, 1, broche)

Lorsqu'on veut régler les paramètres d'une seule LED, on utilise la méthode set_pixel. Pour cet exemple, toutefois, il était plus pratique d'utiliser la méthode set_pixel_line, qui permet de régler un groupe de LEDs adjacentes, à la condition qu'elles soient toutes de la même couleur.

set_pixel_line(numéro de la première LED, numéro de la dernière LED, couleur RGB)

Sur une matrice bidimensionnelle, la numérotation des LEDs est un peu problématique car la matrice est constituée d'un ruban linéaire disposé en zigag. Par exemple, les LEDs de la première ligne sont numérotées de 0 à 15 en allant de la gauche vers la droite. Celles de la deuxième ligne sont numérotés de 16 à 31, mais en allant de la droite vers la gauche.

Pour cet exemple, puisque toutes les LEDs situées sur une même ligne ont la même couleur, il s'agit d'assigner la couleur rouge aux LEDs 0 à 15, la couleur orange aux LEDs 16 à 31, etc.

La couleur RGB est une liste de 3 nombres entiers situés entre 0 et 255: le premier nombre indique la quantité de rouge, le deuxième indique la quantité de vert, et le troisième indique la quantité de bleu.

Finalement, pour que vos nouveaux réglages soient visibles, il est important de terminer avec la méthode show (ligne 31).

Exemple 2: promeneurs aléatoires


Dans ce deuxième exemple: 6 points de couleurs différentes se déplacent au hasard. À chaque itération, le "promeneur" peut bouger vers une position adjacente, mais bien sûr il ne peut pas sortir des limites de la matrice.


-

-

Chacun des 6 promeneurs est décrit par 2 caractéristiques: sa couleur et sa position (lignes 34 à 39).

Cette fois, il est essentiel de désigner les positions au moyen de coordonnées x et y (numéro de la colonne et numéro de la ligne): la fonction xy_a_nombre calcule le numéro de la LED à partir de ces deux coordonnées.


À lire aussi

J'ai également écrit un article sur l'utilisation de cette matrice de LEDs avec une carte Arduino, et un autre avec les cartes ESP32 et ESP8266.

Mes autres articles concernant la programmation du Raspberry Pi Pico en Micropython se trouvent dans la dernière moitié de cette page.


Yves Pelletier

samedi 15 juillet 2023

Utilisation d'un codeur rotatif avec le Raspberry Pi Pico (Micropython)

À première vue, un codeur rotatif (rotary encoder) ressemble à un potentiomètre: il s'agit d'un bouton que l'utilisateur peut tourner afin de contrôler un appareil (modifier le volume sonore, par exemple).

Contrairement au potentiomètre, toutefois, le codeur rotatif produit un signal purement numérique. Deux interrupteurs s'ouvrent et se ferment à mesure qu'on tourne le bouton. Ces deux interrupteurs sont placés en quadrature, c'est à dire qu'ils sont décalés dans le temps l'un par rapport à l'autre, ce qui permet de déduire le sens de la rotation du bouton.


Connexions du codeur rotatif au Rasberry Pi Pico

Pour la rédaction de ce tuto, j'ai utilisé un codeur rotatif de type KY-040: il s'agit d'un petit module qui comporte, en plus du codeur rotatif lui-même, des résistances de tirage 10 kΩ. Le module comporte 5 connecteurs: CLK et DT (clock et data) sont les deux interrupteurs en quadrature actionnés par la rotation du bouton, alors que SW (switch) est l'interrupteur qui est actionné lorsqu'on pousse sur le bouton. Les entrées + et GND servent à l'alimentation du module.

J'ai branché le codeur rotatif au Raspbery Pi Pico de la façon suivante:

  • Broche GND du codeur rotatif: une des broches GND du Raspberry Pi Pico
  • Broche + du codeur rotatif: sortie 3,3 V du Raspberry Pi Pico
  • Broche SW du codeur rotatif: broche GP15 du Raspberry Pi Pico *
  • Broche DT du codeur rotatif: broche GP 14 du Raspberry Pi Pico *
  • Broche CLK du codeur rotatif: broche GP 13 du Raspberry Pi Pico *
* Ces 3 broches seront définies dans notre programme en micropython, et vous pouvez donc les remplacer par d'autres broches au besoin.


Installation de la bibliothèque micropython "Rotary"

Mike Teachman a produit un excellent pilote Micropython pour l'utilisation d'un codeur rotatif. 

Deux fichiers de ce dépôt gitHub doivent être installés sur votre Raspberry Pi Pico: 
  • rotary.py 
  • rotary_irq_rp2.py

Script en micropython #1

-
-

Lorsque vous exécutez le programme ci-dessus avec Thonny, la console affiche la valeur du codeur chaque fois qu'elle change (donc lorsque vous tournez le bouton). L'état du bouton poussoir s'affiche également lorsque son état change (0 quand il est enfoncé, 1 quand il est relâché).



Le constructeur RotaryIRQ (lignes 17 à 22) comporte plusieurs arguments qui nous permettent de personnaliser le comportement de l'encodeur rotatif:
  • pin_num_clk : numéro de la broche du Raspberry Pi Pico reliée à la sortie CLK de l'encodeur.
  • pin_num_dt : numéro de la broche du Raspberry Pi Pico reliée à la sortie DT de l'encodeur.
  • min_val : valeur minimale générée par l'encodeur (par défaut: 0)
  • max_val : valeur maximale générée par l'encodeur (par défaut: 10)
  • incr : de quel incrément la valeur change à chaque 'click' pendant la rotation de l'encodeur. (par défaut: 1)
  • reverse: booléen indiquant pour quel sens de rotation les valeurs augmentent. À "False", la valeur augmente quand on tourne dans le sens antihoraire. À "True", la valeur augmente quand on tourne dans le sens horaire.
  • range_mode: détermine comment l'encodeur se comportera lorsque les limites min_val et max_val sont dépassées. Les trois valeurs possibles sont RotaryIRQ.RANGE_UNBOUNDED (aucune limite), RotaryIRQ.RANGE_BOUNDED (la valeur plafonne au résultat maximum lorsqu'on tente de le dépasser) et RotaryIRQ.RANGE_WRAP (la valeur retourne au minimum lorsqu'on dépasse le maximum).
  • pull_up: booléen qu'on règle à True pour activer les résistances pull-up internes du Raspberry Pi Pico si notre codeur rotatif ne comporte pas de résistances pull-up (ce qui n'est pas notre cas).
  • half_step: booléen qu'on peut régler à True pour activer la détection des demi-pas.
  • invert: booléen qu'on peut régler à True pour inverser les broches DT et CLK.
La seule contrainte un peu gênante que j'ai trouvée au pilote de Mike Teachman, c'est que la valeur initiale du codeur rotatif est nécessairement la valeur minimale. On peut imaginer des cas où il serait plus pertinent qu'au démarrage du programme, la valeur se situe à mi-chemin entre le minimum et le maximum, mais ça ne semble pas avoir été prévu.

Le pilote ne gère pas le signal généré par la sortie SW du module KY-040 (qui indique si l'utilisateur a enfoncé le bouton), mais c'est facile de le prendre en charge nous-mêmes dans notre script. Contrairement aux sorties CLK et DT, la sortie SW n'est munie d'aucune résistance de tirage, c'est pourquoi on active la résistance pull up interne de la broche 15 (ligne 26).

Script en micropython #2

-
-

Dans ce deuxième exemple, le codeur rotatif contrôle la luminosité de la LED embarquée du Raspberry Pi Pico. Cette LED est donc alimentée par un signal modulé en largeur d'impulsion (PWM). Les valeurs limites du codeur rotatif sont réglées à un minimum de 0 (rapport cyclique de 0%, LED complètement éteinte) et à un maximum de 65535 (rapport cyclique de 100%, LED allumée à pleine intensité). De plus, l'incrément a été réglé à 4000 pour qu'il ne soit pas nécessaire de faire accomplir au bouton des centaines de tours avant de commencer à constater un résultat...

Lorsque vous exécutez ce script, la LED devrait être éteinte au départ, mais elle devient de plus en plus brillante à mesure que vous tournez le bouton dans le sens horaire.

À lire également:

Ce blog comporte aussi un article sur l'utilisation d'un codeur rotatif avec une carte Arduino, et avec une carte STM 32 Nucleo programmée avec mbed.

Mes autres articles concernant la programmation du Raspberry Pi Pico en Micropython se trouvent dans la dernière moitié de cette page.


Yves Pelletier 


samedi 27 août 2022

Raspberry Pi Pico W: lire le contenu d'une page web (Micropython)

Dans cet article, nous utilisons un Raspberry Pi Pico W (programmé en Micropython) pour lire le contenu d'une page web. 


La page web que j'ai choisie à titre d'exemple sera... le blog "Électronique en Amateur" ! Nous allons faire en sorte que le Raspberry Pi Pico visite le blog et y trouve le titre de la publication la plus récente. Vous pourrez ensuite modifier ce script pour que votre Raspberry Pi Pico W affiche les conditions météorologique, les cours de la bourse, les résultats de votre équipe sportive préférée, etc.

La bibliothèque "urequests" de Micropython est spécialement conçue pour naviguer sur le web. On accède à la page web de cette façon:

page_web = urequests.get("http://electroniqueamateur.blogspot.com")

Tout le contenu html de la page est alors placé dans la chaîne de caractères (string) "page_web.text". 

Il reste ensuite ensuite à extraire de cette longue chaîne de caractères les informations qui nous intéressent. 

En affichant le code source de la page web, j'ai remarqué que le titre d'un article du blog est toujours précédé de ce tag html:

<h3 class='post-title entry-title' itemprop='name'>

Donc, en utilisant la méthode find pour localiser cette sous-chaîne à l'intérieure de la chaîne complète...

    position = page_web.text.find("<h3 class='post-title entry-title' itemprop='name'>")
    extrait = page_web.text[position:position + 300]

... j'obtiens une chaîne de 300 caractères qui contient, entre autres choses, le titre de l'article le plus récent du blog (qui s'intitule, au moment où j'écris ces lignes, "Dans un blog près de chez vous (24)"):


Mon extrait contient toutefois une grande quantité de caractères qui ne sont pas pertinents. On peut facilement omettre quelques dizaines de caractères au début de la chaîne. Ici, par exemple, ma chaîne débute 80 caractères plus loin:

    position = page_web.text.find("<h3 class='post-title entry-title' itemprop='name'>")
    extrait = page_web.text[position + 80:position + 300]

Le contenu de la variable "extrait" est maintenant:


L'url qui précède le titre de l'article n'aura pas toujours la même longueur, mais on peut détecter où il se termine en recherchant le caractère ">":

    position = extrait.find(">")
    extrait = extrait[position + 1:]

Le contenu de la variable "extrait" est maintenant:


...et il ne reste plus qu'à rechercher le caractère "<" pour retirer le texte superflu qui suit le titre de l'article:

    position = extrait.find("<")
    extrait = extrait[:position]

Maintenant, la variable "extrait" ne comporte plus que le titre désiré:



Voici le script complet:

-
-

... et le résultat affiché dans la console:



À lire également:

samedi 6 août 2022

Lire des fichiers mp3 avec Raspberry Pi Pico et VS1053 (micropython)

Dans un récent article sur l'utilisation d'un module I2S, je déplorais que le décodage du format mp3 ne soit pas supporté par le langage micropython pour l'instant. Une solution consiste à déléguer le décodage à un circuit intégré spécialement conçu pour cette tâche, comme le VS1053, qui peut décoder les principaux formats de fichiers musicaux: Ogg Vorbis, MP3, AAC, FLAC, WMA, MIDI...

Dans cet article, j'utilise un Raspberry Pi Pico (programmé en micropython) et un module VS1053 pour faire jouer les fichiers mp3 enregistrés sur une carte SD.


Module VS1053

Mon module VS1053 a été fabriqué par LCSOFT STUDIO et porte la mention "VS1003/1053 MP3 CODEC". Il existe d'autres modules VS1053 différents de celui-ci, mais j'imagine qu'ils sont équivalents. Je crois qu'il existe des modules VS1053 qui comportent un lecteur de carte SD intégré. Dans mon cas, j'ai dû utiliser un lecteur de carte SD en plus du module VS1053.


Connexions

Le module VS1053 et le module de carte SD partagent le même bus SPI.

Connexions du module VS1053:

  • Broche 5 V du module VS1053 : Broche VBUS du Raspberry Pi Pico 
  • Broche DGND du module VS1053: Broche GND du Raspberry Pi Pico
  • Broche MISO du module VS1053: Broche GP4 du Raspberry Pi Pico
  • Broche MOSI du module VS1053: Broche GP7 du Raspberry Pi Pico
  • Broche SCK du module VS1053: Broche GP6 du Raspberry Pi Pico
  • Broche DREQ du module VS1053: Broche GP10 du Raspberry Pi Pico
  • Broche XRST du module VS1053: Broche GP13 du Raspberry Pi Pico
  • Broche XCS du module VS1053: Broche GP12 du Raspberry Pi Pico
  • Broche XDCS du moudle VS1053: Broche GP11 du Raspberry Pi Pico

Connexions du module lecteur de carte SD:

  • GND du lecteur SD: Broche GND du Raspberry Pi Pico
  • +3.3 du lecteur SD: Sortie 3,3 V du Raspberry Pi Pico
  • Broche SCK du lecteur SD: broche GP6 du Raspberry Pi Pico
  • Broche MOSI du lecteur SD: broche GP7 du Raspberry Pi Pico
  • Broche MISO du lecteur SD: broche GP4 du Raspberry Pi Pico
  • Broche CS du lecteur SD: broche GP15 du Raspberry Pi Pico

Bibliothèques

Deux pilotes micropython sont nécessaires pour ce projet: micropython-vs1053 par Peter Hinch, et le pilote officiel pour la carte SD.

Les fichiers sdcard.py et  vs1053_syn.py devront être copiés dans la mémoire flash du Raspberry Pi Pico pour que le script ci-dessous fonctionne correctement.

Script

Voici un script qui exécute tous les fichiers mp3 qui se trouvent sur la carte SD. Comme vous pouvez le constater, il s'agit d'un script très court: les deux bibliothèques font tout le travail pour nous!

-

-

À lire également:

Yves Pelletier (Facebook)


jeudi 4 août 2022

Jouer de la musique (fichiers WAV) avec un Raspberry Pi Pico et un décodeur I2S (micropython)

Dans cet article, nous utilisons un Rasbperry Pi Pico programmé en micropython et un décodeur I2S UDA1334A pour jouer la musique stockée sous forme de fichiers .wav sur une carte SD.


Module I2S

I2S est le nom d'un protocole de communication série permettant de connecter entre eux des appareils audio numériques. Un décodeur I2S est un convertisseur numérique-analogique: il produit un signal analogique audio à partir des informations numériques que lui envoie le Raspberry Pi Pico

J'ai utilisé le décodeur I2S stéréo UDA1334A qui était fabriqué par Adafruit, mais qui ne l'est plus. Adafruit l'a remplacé par un nouveau modèle basé sur le MAX98357A, et il existe d'autres modules du même genre (basés sur le PCM5102). En principe, vous devriez obtenir des bons résultats avec tous ces modules, mais moi je n'ai testé que l'UDA1334A d'Adafruit.


Bibliothèques wavplayer.py et sdcard.py

Mike Teachman a placé sur github de nombreux exemples d'utilisation du I2S en micropython.  Dans le répertoire "examples", vous trouverez un script qui génère un simple signal sinusoïdal (particulièrement utile pour vérifier les connexions du module I2S et s'assurer qu'il fonctionne correctement), d'autres qui jouent un fichier .wav enregistré en mémoire flash ou sur une carte SD, etc.

Pour exécuter un fichier audio en format .wav, nous devons copier le fichier wavplayer.py de Mike Teachman dans la mémoire flash du Raspberry Pi Pico. Puisque les fichiers .wav sont souvent volumineux, nous aurons également besoin du pilote sdcard.py.


Connexions

J'ai utilisé les connexions proposées par Mike Teachman.

Connexions du module décodeur I2S:

  • Broche VIN du module I2S : Sortie 3,3 V du Raspberry Pi Pico
  • Broche GND du module I2S: Broche GND du Raspberry Pi Pico
  • Broche BCLK du module I2S: Broche GP16 du Raspberry Pi Pico
  • Broche WSEL du module I2S: Broche GP17 du Raspberry Pi Pico
  • Broche DIN du module I2S: Broche GP18 du Raspberry Pi Pico

(les autres broches du décodeur I2S peuvent être laissées déconnectées)

Connexions du module lecteur de carte SD:

  • GND du lecteur SD: Broche GND du Raspberry Pi Pico
  • +3.3 du lecteur SD: Sortie 3,3 V du Raspberry Pi Pico
  • Broche SCK du lecteur SD: broche GP14 du Raspberry Pi Pico
  • Broche MOSI du lecteur SD: broche GP15 du Raspberry Pi Pico
  • Broche MISO du lecteur SD: broche GP12 du Raspberry Pi Pico
  • Broche CS du lecteur SD: broche GP13 du Raspberry Pi Pico


Script

Voici un script qui joue l'un après l'autre tous les fichiers .wav enregistrés à la racine de la carte SD (avant de l'utiliser, il faut évidemment avoir préalablement enregistré quelques fichiers en format .wav sur la carte). Vous pouvez écouter le résultat en branchant un casque d'écoute à la sortie jack du module I2S.

-

-

Mais pas de mp3?

Tout ceci fonctionne très bien, mais je préférerais pouvoir jouer de la musique en format mp3: un fichier wav, ça prend beaucoup de place! Malheureusement, ça ne semble pas possible pour l'instant en Micropython.  CircuitPython, en revanche, supporte le décodage du format mp3; c'est assez tentant d'aller faire quelques essais de ce côté...


À lire également:

Yves Pelletier (Facebook)