Tirage de dés avec l'afficheur 8x8 pixels MAX7219
publication: 17 juin 2022 / mis à jour 11 juillet 2022
Appel à collaboration
Vous développez des montages, simples ou complexes avec ESP32 et ESP32forth.
Partagez-les ici sur ce site.
ESP32forth ne pourra se développer qu'avec la collaboration active de toutes les bonnes volontés.
Vos montages peuvent aider d'autres développeurs.
Les montages des autres développeurs peuvent vous aider.
Pour proposer un article ou un montage, cliquez ici
Listing complet: Dice roll on 8x8 LED matrix
Raccordement de l'afficheur LED 8x8 MAX7219
L'afficheur reçoit les signaux SPI depuis la carte ESP32 vi les fils vert jaune et orange:
L'afficheur MAX7219 est alimenté en 5V depuis une alimentation externe indépendante de celle de la carte ESP32: fils rouge et noir. Cette alimentation figure sur notre montage en rouge. Elle partage le connecteur GND avec le connecteur GND de la carte ESP32: fil noir.
Gestion de l'afficheur MAX7219
On commence par paramétrer notre port SPI:
\ define VSPI pins 19 constant VSPI_MISO 23 constant VSPI_MOSI 18 constant VSPI_SCLK 05 constant VSPI_CS \ define SPI port frequency 4000000 2 / constant SPI_FREQ
La ligne 19 constant VSPI_MISO
est nécessaire pour l'initialisation du
port SPI. Mais la ligne MISO (Master In Slave Out) ne sera pas câblée.
Les valeurs des constantes correspondant aux ports GPIO exploités sur la carte ESP32:
05 constant VSPI_CS
signifie que la ligne CS/SS est raccordée à la sortie GPIO5
sur la carte ESP32.
Puis on définit les mots permettant de communiquer avec l'afficheur LED 8x8 MAX7219:
\ select SPI vocabulary only FORTH SPI also \ initialize HSPI port : init.VSPI ( -- ) VSPI_CS OUTPUT pinMode VSPI_SCLK VSPI_MISO VSPI_MOSI VSPI_CS SPI.begin SPI_FREQ SPI.setFrequency ; \ send two bytes to MAX7219 thru SPI port : MAX7219.send ( c1 c2 -- ) 1 SPI.setHwCs swap 8 lshift + SPI.write16 0 SPI.setHwCs ; : MAX7219.normal ( -- ) $0c $01 MAX7219.send ; : MAX7219.shutdown ( -- ) $0c $00 MAX7219.send ; : MAX7219.intensity ( c -- ) $0a swap MAX7219.send ; : MAX7219.decode ( c -- ) $09 swap MAX7219.send ; : MAX7219.scan.limit ( c -- ) $0b swap MAX7219.send ; : MAX7219.set.digit ( cbits cdigit -- ) swap MAX7219.send ;
Le mot le plus important est MAX7219.send
. Il exploite une
variante du mot SPI.write
, le mot SPI.write16
, lequel
permet d'envoyer 2 octets successifs vers l'afficheur MAX7219.
Gestion des sprites à afficher
Notre afficheur MAX7218 est constitué de 8 rangées de LEDs, avec 8 LEDs par rangée. Ca tombe bien, un octet fait 8 bits. Il nous faut donc 8 octets pour afficher un motif 8x8, c'est à dire un sprite comme le nomment les développeurs de jeux vidéos.
\ *** Array with alphanumerics characters *** \ caracters ..0..9A..Z in array create DICE_SPRITES $00 c, $00 c, $00 c, $18 c, $18 c, $00 c, $00 c, $00 c, \ 1 $00 c, $00 c, $00 c, $c3 c, $c3 c, $00 c, $00 c, $00 c, \ 2 $00 c, $c0 c, $c0 c, $18 c, $18 c, $03 c, $03 c, $00 c, \ 3 $00 c, $c3 c, $c3 c, $00 c, $00 c, $c3 c, $c3 c, $00 c, \ 4 $00 c, $c3 c, $c3 c, $18 c, $18 c, $c3 c, $c3 c, $00 c, \ 5 $00 c, $db c, $db c, $00 c, $00 c, $db c, $db c, $00 c, \ 6
Ici, chaque ligne est un sprite. La première ligne est notre sprite 0, lequel est censé afficher le numéro 1 de notre dé.
Voici la manière dont est codée chaque sprite:
On dessine, dans un carré 8x8, notre sprite. Puis on pivote ce sprite et on encode chaque ligne en sa valeur hexadécimale: pixel éteint = 0, pixel allumé = 1. Dans notre figure, la seconde ligne sera 01111110 qui donne en hexadécimal la valeur $7e.
: getNum ( n ---) \ get nth caracters from CHARACTERS table 8 * DICE_SPRITES + ; \ Only for test encoding characters : tstChar ( n ---) getNum { addr } 8 0 do addr i + c@ dup hex <# # # #> cr type ." - " binary <# # # # # # # # # #> type decimal loop ;
Ici, le mot tstChar
nous permet de visualiser le bon codage de chaque sprite:
--> 2 tstChar 00 - 00000000 C0 - 11000000 C0 - 11000000 18 - 00011000 18 - 00011000 03 - 00000011 03 - 00000011 00 - 00000000 ok
Une fois chaque sprite défini, on peut en gérer l'affichage. C'est ce que fait le
mot disp.char
:
\ display a character from it address : disp.char { addr -- } 8 0 do addr i + c@ \ fetch character byte i 1+ MAX7219.set.digit \ send byte at addr i loop ; : dice ( n -- ) getNum disp.char ;
Le mot dice
récupère le numéro du sprite à afficher, qui nous le rappelons sont
numérotés de 0 à 5 (voir la vidéo).
On prépare ensuite la génération de nombres aléatoires. ESP32 intègre ce générateur aléatoire
au travers du registre RNG_DATA_REG
\ Random number data $3FF75144 constant RNG_DATA_REG \ get 32 bits random b=number : rnd ( -- x ) RNG_DATA_REG UL@ ; \ get random number in interval [0..n-1] : random ( n -- 0..n-1 ) rnd swap mod ;
Le mot random
est exécuté en le faisant précédé de la valeur maximale
à générer. Exemple: 6 random
génère un nombre entier aléatoire dans
l'intervalle [0..5].
Le mot before-dice
génère une petite animation qui précède le tirage de dé:
: before-dice ( -- )
5 0 do
8 0 do
$ff i 1+ MAX7219.set.digit j 10 * ms
$00 i 1+ MAX7219.set.digit
loop
8 0 do
$ff 7 i - 1+ MAX7219.set.digit j 10 * ms
$00 7 i - 1+ MAX7219.set.digit
loop
loop
;
Enfin, on construit le mot dice-roll
qui est utilisé pour le tirage de dé (voir vidéo):
: MAX7219.init ( -- ) init.VSPI MAX7219.normal $01 MAX7219.intensity $07 MAX7219.scan.limit $00 MAX7219.decode ; MAX7219.init : dice-roll ( -- ) before-dice 6 random dice ;
En vidéo, les étapes de contrôle du bon affichage des sprites, suivi de trois tirages de dé:
En conclusion, ce premier exemple d'utilisation du port SPI montre encore une fois la grande souplesse du langage FORTH.
Legal: site web personnel sans commerce / personal site without seling