Nous allons maintenant brancher un Raspberry Pi Pico à un écran tactile SPI 240 X 320 muni d'un contrôleur ILI9341 (pour l'affichage) et d'un contrôleur XPT2046 (capteur tactile). Le Raspberry Pi Pico sera programmé en MicroPython.
Connexions de l'écran au Raspberry Pi Pico
Le module comporte un total de 18 broches:
- 2 broches pour l'alimentation (VCC et GND)
- 7 broches pour l'affichage
- 5 broches pour le capteur tactile (celles dont le nom débute par "T_")
- De l'autre côté de la carte, 4 broches pour le lecteur de carte SD (que je n'ai pas utilisé)
Il serait tout à fait acceptable de brancher l'afficheur et le capteur tactile (XPT2046) sur le même bus SPI. Toutefois, l'auteur de la bibliothèque que nous allons utiliser fait remarquer que l'affichage supporte une vitesse de communication beaucoup plus rapide que le capteur tactile. Pour cette raison, il suggère de brancher l'afficheur et le capteur tactile sur deux bus SPI différents, et c'est ce que j'ai fait (affichage sur le bus SPI0 et détection du touché sur le bus SPI1).
Ça représente beaucoup de fils à connecter... De gauche à droite sur l'écran du schéma ci-dessous:
- Broche T_IRQ de l'écran : Broche GP2 du RP Pico
- Broche T_DO de l'écran: Broche GP8 du RP Pico
- Broche T_DIN de l'écran: Broche GP11 du RP Pico
- Broche T_CS de l'écran: Broche GP12 du RP Pico
- Broche T_CLK de l'écran: Broche GP10 du RP Pico
- Broche SDO (MISO) de l'écran: Broche GP4 du RP Pico (probablement pas nécessaire)
- Broche LED de l'écran: Sortie 3,3 V du RP Pico
- Broche SCK de l'écran: Broche GP6 du RP Pico
- Broche SDI (MOSI) de l'écran: Broche GP7 du RP Pico
- Broche DC de l'écran: Broche GP13 du RP Pico
- Broche RESET de l'écran: Broche GP14 du RP Pico
- Broche CS de l'écran: Broche GP15 du RP Pico
- Broche GND de l'écran: Broche GND du RP Pico
- Broche VCC de l'écran: Sortie 3,3 V du RP Pico
Installation des bibliothèques
J'ai utilisé les bibliothèques MicroPython offertes par rdagger.
Pour que les scripts que je présente plus loin dans cet article fonctionnent correctement, tous les fichiers suivants doivent être copiés dans le Raspberry Pi Pico:
- ili9341.py (gestion de l'affichage)
- xpt2046.py (gestion du capteur tactile)
- xglcd_font.py (pour affichage de texte)
- Unispace12x24.c, à l'intérieur du répertoire "fonts"
Le dépôt github présente une bonne quantité de scripts en MicroPython qui montrent comment afficher du texte, des formes géométriques, des images et des animations sur l'écran (il s'agit des 11 fichiers dont le titre débute par "demo"). Mais puisqu'il n'y a aucun exemple simple montrant comment utiliser la bibliothèque xpt2046.py, c'est sur cet aspect que je vais insister.
Routine de calibration
Lorsqu'on touche l'écran, le capteur tactile envoie au Raspberry Pi Pico deux valeurs qui sont proportionnelles à la position (horizontale et verticale) qui a été touchée. Ces valeurs brutes doivent toutefois être transformées si on désire qu'elles correspondent aux coordonnées des pixels sur l'écran.
Pour compliquer les choses, les valeurs générées ne sont pas identiques d'un écran à l'autre. Pour cette raison, il est utile d'exécuter une routine comme celle qui est présentée ci-dessous, afin de connaître les valeurs propres à l'écran que nous utilisons.
Le script ci-dessous invite l'utilisateur à toucher tour à tour chacun des 4 coins de l'écran.
- x_min (coordonnée x lorsqu'on touche le bord gauche de l'écran)
- x_max (coordonnée x lorsqu'on touche le bord droit de l'écran)
- y_min (coordonnée y lorsqu'on touche le haut de l'écran)
- y_max (coordonnée y lorsqu'on touche le bas de l'écran)
''' | |
Routine de calibration d'un écran tactile | |
ILI9341 branché à un Raspberry Pi Pico. | |
Plus d'infos: | |
https://electroniqueamateur.blogspot.com/2021/06/utilisation-dun-ecran-tactile-tft-spi.html | |
''' | |
from machine import Pin, SPI | |
import ili9341 | |
from xglcd_font import XglcdFont | |
from xpt2046 import Touch | |
minX = maxX = minY = maxY = 500 | |
def dessine_fleche(etape): | |
if (etape == 1): # coin supérieur gauche | |
display.draw_line(0, 0, 40, 40, ili9341.color565(255, 255, 255)) | |
display.draw_line(0, 0, 0, 20, ili9341.color565(255, 255, 255)) | |
display.draw_line(0, 0, 20, 0, ili9341.color565(255, 255, 255)) | |
if (etape == 2): # coin supérieur droit | |
display.draw_line(239, 0, 199, 40, ili9341.color565(255, 255, 255)) | |
display.draw_line(239, 0, 239, 20, ili9341.color565(255, 255, 255)) | |
display.draw_line(239, 0, 219, 0, ili9341.color565(255, 255, 255)) | |
if (etape == 3): # coin inférieur gauche | |
display.draw_line(0, 319, 40, 279, ili9341.color565(255, 255, 255)) | |
display.draw_line(0, 319, 0, 299, ili9341.color565(255, 255, 255)) | |
display.draw_line(0, 319, 20, 319, ili9341.color565(255, 255, 255)) | |
if (etape == 4): # coin inférieur droit | |
display.draw_line(239, 319, 199, 279, ili9341.color565(255, 255, 255)) | |
display.draw_line(239, 319, 239, 299, ili9341.color565(255, 255, 255)) | |
display.draw_line(239, 319, 219, 319, ili9341.color565(255, 255, 255)) | |
def routine_touch(x, y): | |
global minX, maxX, minY, maxY | |
global etape | |
if (etape < 6): | |
# obtention des valeurs brutes | |
rawX = xptTouch.send_command(xptTouch.GET_X) | |
rawY = xptTouch.send_command(xptTouch.GET_Y) | |
if rawX != 0: | |
if rawX > maxX: | |
maxX = rawX | |
elif rawX < minX: | |
minX = rawX | |
if rawY != 0: | |
if rawY > maxY: | |
maxY = rawY | |
elif rawY < minY: | |
minY = rawY | |
if etape < 5: | |
print("Etape " + str(etape) + " : " + str(rawX) + "," + str(rawY)) | |
etape = etape + 1 | |
#effacage de toutes les fleches | |
display.fill_rectangle(0, 0, 41, 41, ili9341.color565(0, 0, 0)) | |
display.fill_rectangle(199, 0, 41, 41, ili9341.color565(0, 0, 0)) | |
display.fill_rectangle(0, 279, 41, 41, ili9341.color565(0, 0, 0)) | |
display.fill_rectangle(199, 279, 41, 41, ili9341.color565(0, 0, 0)) | |
if etape < 5: | |
dessine_fleche(etape) | |
if etape == 5: | |
print("x_min: " + str(minX) + " , " + "x_max: " + str(maxX) + " , " + | |
"y_min: " + str(minY) + " , " + "y_max: " + str(maxY)) | |
display.fill_rectangle(0, 0, 240, 320, ili9341.color565(0, 0, 0)) | |
display.draw_text(20, 100, "x_min: " + str(minX), unispace, | |
ili9341.color565(255, 255, 255)) | |
display.draw_text(20, 130, "x_max: " + str(maxX), unispace, | |
ili9341.color565(255, 255, 255)) | |
display.draw_text(20, 160, "y_min: " + str(minY), unispace, | |
ili9341.color565(255, 255, 255)) | |
display.draw_text(20, 190, "y_max: " + str(maxY), unispace, | |
ili9341.color565(255, 255, 255)) | |
# initialisation de l'affichage | |
spiTFT = SPI(0, baudrate=40000000, sck=Pin(6), mosi=Pin(7)) | |
display = ili9341.Display(spiTFT, dc=Pin(13), cs=Pin(15), rst=Pin(14)) | |
#initialisation du capteur tactile | |
spiXPT = SPI(1, baudrate=1000000,sck=Pin(10), mosi=Pin(11), miso=Pin(8)) | |
xptTouch = Touch(spiXPT, cs=Pin(12), int_pin=Pin(2), | |
int_handler=routine_touch, | |
x_min=0, x_max=2200, y_min=0, y_max=2200) | |
# chargement de la police de caractères | |
unispace = XglcdFont('fonts/Unispace12x24.c', 12, 24) | |
# instructions à l'écran | |
display.draw_text(30, 130, 'Touchez le bout', unispace, | |
ili9341.color565(255, 255, 255)) | |
display.draw_text(50, 160, 'de la fleche', unispace, | |
ili9341.color565(255, 255, 255)) | |
etape = 1 | |
dessine_fleche(etape) | |
while True: | |
pass | |
Vérification de la calibration
Voici maintenant un script minimaliste qui permet de vérifier rapidement la qualité de la calibration: avant de l'utiliser, c'est important de modifier le contenu de la ligne 29 pour qu'il corresponde aux valeurs trouvées au moyen du script de calibration.
Lorsque vous exécutez ce script, un point blanc est tracé chaque fois que vous touchez l'écran. Si la calibration est correcte, le point devrait se tracer à la position touchée.
-
''' | |
Vérification de la calibration d'un écran | |
tactile ILI9341 branché à un Raspberry Pi Pico. | |
Un point est tracé là où on touche l'écran. | |
Plus d'infos: | |
https://electroniqueamateur.blogspot.com/2021/06/utilisation-dun-ecran-tactile-tft-spi.html | |
''' | |
from machine import Pin, SPI | |
import ili9341 | |
from xglcd_font import XglcdFont | |
from xpt2046 import Touch | |
# routine exécutée lorsqu'on touche l'écran | |
def routine_touch(x, y): | |
display.fill_circle(x, y, 2, ili9341.color565(255, 255, 255)) | |
# initialisation de l'affichage | |
spiTFT = SPI(0, baudrate=40000000, sck=Pin(6), mosi=Pin(7)) | |
display = ili9341.Display(spiTFT, dc=Pin(13), cs=Pin(15), rst=Pin(14)) | |
# initialisation du capteur tactiel | |
spiXPT = SPI(1, baudrate=1000000,sck=Pin(10), mosi=Pin(11), miso=Pin(8)) | |
# il est important d'écrire les valeurs de x_min, x_max, y_min et y_max obtenues | |
# grâce au script calibration.py: | |
xptTouch = Touch(spiXPT, cs=Pin(12), int_pin=Pin(2), | |
int_handler=routine_touch, | |
x_min=128, x_max=1919, y_min=224, y_max=1963) | |
# chargement de la police de caractères | |
unispace = XglcdFont('fonts/Unispace12x24.c', 12, 24) | |
# instructions à l'écran | |
display.draw_text(30, 150, "Touchez l'ecran", unispace, | |
ili9341.color565(255, 255, 255)) | |
while True: | |
pass | |
-
Script: un exemple avec des boutons
Voici finalement un exemple dans lequel deux boutons apparaissent à l'écran. Lorsqu'on touche le bouton de gauche, un cercle vert est affichée, alors que c'est un rectangle rouge qui s'affiche lorsqu'on clique sur le bouton de droite. Encore une fois, pour que ça fonctionne bien, c'est important d'écrire vos paramètres de calibration à la ligne 68 du script.
''' | |
Exemple d'utilisation de l'écran tactile ILI9341 | |
avec un Raspberry Pi Pico. | |
Des boutons à l'écran peuvent être touchés pour | |
afficher des formes géométriques. | |
Plus d'informations: | |
https://electroniqueamateur.blogspot.com/2021/06/utilisation-dun-ecran-tactile-tft-spi.html | |
''' | |
from machine import Pin, SPI | |
# Pour les 3 fichiers ci-dessous: | |
# https://github.com/rdagger/micropython-ili9341 | |
import ili9341 | |
from xglcd_font import XglcdFont | |
from xpt2046 import Touch | |
# définition de quelques couleurs | |
rouge = ili9341.color565(255, 0, 0) | |
vert = ili9341.color565(0,255, 0) | |
bleu = ili9341.color565(0,0, 255) | |
blanc = ili9341.color565(255, 255, 255) | |
noir = ili9341.color565(0,0,0) | |
# position des boutons | |
bouton1 = (20, 170, 120, 40) # x, y, largeur, hauteur | |
bouton2 = (175, 170, 120, 40) | |
# c'est la routine qui est déclanchée lorsque l'écran | |
# envoie un signal sur la broche "interrupt" | |
def routine_touch(x, y): | |
# inversion des coordonnées x et y (car mode paysage) | |
x, y = y, x | |
y = 240 - y | |
# a-t-on cliqué sur le premier bouton? | |
if ((x > bouton1[0]) and (x < bouton1[0] + bouton1[2]) | |
and (y > bouton1[1]) and (y < bouton1[1] + bouton1[3])): | |
# on efface le dessin précédent | |
display.fill_rectangle(0, 0, 320, 150, noir) | |
# on affiche le dessin choisi | |
display.fill_circle(160, 80, 60, vert) | |
# a-t-on cliqué sur le deuxième bouton? | |
if ((x > bouton2[0]) and (x < bouton2[0] + bouton2[2]) | |
and (y > bouton2[1]) and (y < bouton2[1] + bouton2[3])): | |
# on efface le dessin précédent | |
display.fill_rectangle(0, 0, 320, 150, noir) | |
# on affiche le dessin choisi | |
display.fill_rectangle(60, 40, 200, 100, rouge) | |
# initialisation de l'affichage en mode paysage (rotation 90) | |
spiTFT = SPI(0, baudrate=40000000, sck=Pin(6), mosi=Pin(7)) | |
display = ili9341.Display(spiTFT, dc=Pin(13), cs=Pin(15), rst=Pin(14), | |
width=320, height=240, rotation = 90) | |
spiXPT = SPI(1, baudrate=1000000,sck=Pin(10), mosi=Pin(11), miso=Pin(8)) | |
#initialisation du capteur tactile | |
xptTouch = Touch(spiXPT, cs=Pin(12), int_pin=Pin(2), | |
int_handler = routine_touch, | |
x_min=128, x_max=1919, y_min=224, y_max=1963) | |
# (x_min, x_max, y_min et y_max sont les valeurs ajustées pour mon écran) | |
# chargement de la police de caractère | |
unispace = XglcdFont('fonts/Unispace12x24.c', 12, 24) | |
# Affichage du message initial | |
display.draw_text(0, 50, 'Veuillez faire votre choix', unispace, | |
ili9341.color565(255, 128, 0)) | |
#dessin du premier bouton | |
display.fill_rectangle(bouton1[0], bouton1[1], bouton1[2], bouton1[3], rouge) | |
display.draw_rectangle(bouton1[0], bouton1[1], bouton1[2], bouton1[3], blanc) | |
display.draw_text(bouton1[0]+20, bouton1[1]+6, 'Cercle', unispace, blanc,rouge) | |
#dessin du deuxième bouton | |
display.fill_rectangle(bouton2[0], bouton2[1], bouton2[2], bouton2[3], bleu) | |
display.draw_rectangle(bouton2[0], bouton2[1], bouton2[2], bouton2[3], blanc) | |
display.draw_text(bouton2[0]+4, bouton2[1]+6, 'Rectangle', unispace, blanc,bleu) | |
while True: | |
pass | |
À lire également
Le même écran tactile peut être utilisé avec un ESP32, un ESP8266 ou une STM32 Blue Pill (toutes ces cartes ont été programmées avec l'IDE Arduino).
D'autre part, nous avons déjà exploré l'utilisation d'autres afficheurs avec le Raspberry Pi Pico programmé en MicroPython:
Yves Pelletier (Facebook)
Bonsoir!! Merci pour ce super post, ça m'a beaucoup aidé !! Mais j'ai un problème que je n'arrive pas à résoudre : l'axe Y de l'affichage est inversé. lorsque je lance le programme pour vérifier l'étalonnage en cliquant sur le haut, le cercle apparaît en bas. En haut à gauche (x, y) = 147, 1854 --- En haut à droite = 1903, 1839 --- En bas à gauche = 123, 70 --- En bas à droite = 1903, 93. Qu'est-ce qui pourrait faire cela et comment le résoudre ? Merci beaucoup d'avance!!
RépondreSupprimer