Dans le précédent article technique « Smart Display RS485 Introduction », nous avons présenté les principes de base de l'interface RS485 et du protocole Modbus. Dans cet article, nous allons approfondir plusieurs techniques couramment utilisées pour le développement avec Smart Display à travers un exemple comportant plusieurs pages, notamment :
- Comment changer de page à l'aide du Button widget.
- Comment mettre à jour les valeurs des widgets après un changement de page.
- Comment générer des signaux sonores de différentes durées avec le buzzer.
- Comment utiliser le Graph widget.
Matériel nécessaire
- Un Smart Display équipé d'une interface RS485. Dans cet exemple, nous utilisons un Smart Display de 3.5".
- Arduino (Uno ou Mega2560).
- Carte d'extension RS485 pour Arduino (Lien vers DFRobot).
- Potentiomètre (VR).
Câblage
- Potentiomètre : connecter Vcc à 5V, GND à GND et la sortie à l'entrée A0 de l'Arduino.
- Connecter la borne A de la carte d'extension RS485 à RS485+ du Smart Display.
- Connecter la borne B de la carte d'extension RS485 à RS485- du Smart Display.
Présentation de l'exemple
Ce projet comporte trois pages, entre lesquelles il est possible de naviguer à l'aide du Button widget. Le contenu et les fonctions de chaque page sont décrits ci-dessous.
Page 1 :
Un bouton situé à droite permet de passer à la page suivante. Dans la partie inférieure, un Horizontal Slider permet de régler la luminosité de l'écran. L'aperçu de la page est présenté ci-dessous.

Page 2 :
Un bouton situé à gauche permet de revenir à la page précédente, tandis qu'un bouton situé à droite permet de passer à la page suivante. Trois boutons placés dans la partie inférieure permettent également de générer des signaux sonores de durée courte, moyenne ou longue.

Page 3 :
Un bouton situé à gauche permet de revenir à la page précédente. Un potentiomètre est utilisé pour simuler une entrée analogique, et les variations de la valeur sont affichées à l'aide du Graph widget.

Comme cet exemple utilise une carte d'extension RS485, il est nécessaire d'installer la bibliothèque requise via le Library Manager avant de commencer la programmation.

Création du contenu des pages
Commencez par créer le contenu des pages à l'aide de GUI Builder. Le texte peut être saisi directement dans le Text widget de chaque page ; il n'est donc pas nécessaire de le définir dans le programme.

La configuration détaillée des widgets est présentée dans le tableau ci-dessous :

Vous pouvez choisir le modèle de Smart Display en fonction du matériel disponible et utiliser différents widgets pour créer l'interface souhaitée. Il est toutefois essentiel que le widget ID et le type de chaque page correspondent aux définitions utilisées dans le programme. Pour simplifier la mise en œuvre, il est recommandé de créer le contenu des pages en suivant les widget IDs et les types indiqués dans ce tableau.
Passons maintenant à la partie programmation.
Explication du programme d'exemple
(1) Fichiers inclus
Après avoir téléchargé la bibliothèque ModbusMaster, veillez à l'inclure à l'aide de la directive #include :

Pour faciliter leur gestion, certaines constantes associées au Smart Display ont également été regroupées dans le fichier SmartDisplayModbus.h. Veillez à inclure également ce fichier.
(2) Conversion du Widget ID en adresse de registre
Dans l'article précédent, nous avons présenté la méthode permettant de convertir un widget ID en adresse de registre correspondante :

Ce tableau avait toutefois été défini à une époque où chaque page pouvait contenir au maximum 10 widgets. Désormais, chaque page peut comporter jusqu'à 64 widgets. Le tableau reste valable pour les 10 premiers widgets, mais à partir du 11e widget, il est nécessaire d'utiliser une nouvelle zone de registres. Nous avons donc défini les macros suivantes :

Pour simplifier l'utilisation, nous définissons une fonction permettant d'effectuer les opérations de lecture et d'écriture à partir du widget ID. La conversion vers l'adresse de registre correspondante est effectuée directement dans cette fonction.

(3) Widget ID et conception de l'interface graphique
Lors de la création du contenu des pages avec GUI Builder, nous avons indiqué que les widget IDs devaient rester cohérents. Les constantes correspondant aux widget IDs sont donc définies dans le programme comme suit :

Ces constantes permettent d'identifier plus facilement les différents types de widgets et de les faire correspondre à la conception réelle des pages. Si la conception de l'interface graphique est modifiée ultérieurement, pensez également à vérifier ces valeurs afin d'éviter toute incohérence.
(4) Buzzer
Pour piloter le buzzer, le firmware utilise un compteur afin de générer un délai déterminé, puis envoie un signal 0/1 au buzzer. D'autres compteurs permettent de contrôler les durées d'activation et de désactivation du signal. Pour générer un signal sonore, il est nécessaire d'écrire dans quatre registres :

Pour régler la durée du signal sonore, nous utilisons une fonction à laquelle SMARTDISPLAY_BUZZER_HIGH est transmis en tant que paramètre. Un exemple de cette fonction est présenté ci-dessous :

Le buzzer n'est activé que lorsque la valeur de SMARTDISPLAY_BUZZER_ACTIVE est différente de celle écrite précédemment. Cette valeur est donc conservée en tant que variable static dans la fonction, puis inversée avant chaque nouvel appel.
Enfin, dans la fonction de gestion de la page, il est possible de générer des signaux sonores de différentes durées en fonction de l'état des boutons :

(5) Changement de page
Avant de changer de page, il est nécessaire de passer en CONFIG_MODE. Une fois la nouvelle page définie, le système repasse en DISPLAY_MODE. Lors d'un changement de page, le Smart Display recharge tous les widgets de la nouvelle page. Afin d'éviter toute opération de lecture ou d'écriture avant la fin de ce chargement, il est recommandé d'ajouter un court délai. La durée nécessaire dépend de la complexité de la page. Si un comportement anormal est constaté après un changement de page, il est possible d'augmenter ce délai afin de vérifier si le problème est résolu.

Après un changement de page, les widgets de la nouvelle page sont chargés avec leurs valeurs par défaut. Nous mettons donc en place un processus permettant de gérer le changement de page, de mémoriser les valeurs des widgets et de les restaurer lorsque cela est nécessaire.
Nous définissons tout d'abord un pointeur de fonction pour la gestion des pages. Cela permet de créer une table des pages et d'associer à chacune d'elles une fonction de traitement :

Nous créons ensuite la table des pages :

La constante MAX_WIDGETS_PER_PAGE définit le nombre de widgets dont les valeurs doivent être mémorisées pour chaque page. Si des widgets supplémentaires sont ajoutés ultérieurement, cette valeur doit être mise à jour en conséquence.
Le changement de page et le traitement des widgets sont ensuite gérés dans la fonction loop() :

Si la page actuelle _curPage est différente de la page suivante _nextPage, le flag de changement de page newPage est défini sur true. La fonction de gestion de la page peut ainsi déterminer qu'une initialisation est nécessaire. Prenons Page0 comme exemple :

Si le paramètre init est défini sur true, cela signifie que la page vient d'être chargée. Dans ce cas, la valeur de WIDGET_P0_BUTTON_NEXT est définie sur 0. Lors du passage à une nouvelle page, la valeur par défaut du bouton est 0. Nous souhaitons exécuter une commande spécifique — dans cet exemple, passer à PAGE_1 — uniquement lorsque le bouton est actionné, c'est-à-dire lorsque sa valeur passe de 0 à 1. Il est donc nécessaire de réinitialiser la valeur à 0, car elle peut avoir été précédemment modifiée à 1.
Lors de son chargement, le Slider widget est lui aussi initialisé à 0. Toutefois, si la luminosité a déjà été modifiée, il est nécessaire de restaurer la valeur de luminosité actuelle _brightness.
Dans les autres cas (lorsque init est false), les widgets sont traités en fonction des changements de leurs valeurs. Enfin, les valeurs de tous les widgets sont mémorisées afin de servir de référence lors du cycle de traitement suivant.
La fonction suivante est utilisée pour définir la page suivante _nextPage :

À l'exception du premier appel, la fonction de gestion de la page vérifie les valeurs des widgets à chaque exécution. Lorsqu'elle détecte que la valeur d'un bouton est passée de 0 à 1, elle appelle la fonction suivante afin de demander un changement de page :

(6) Graph Widget
Le Graph widget permet de représenter graphiquement les valeurs qui lui sont transmises. Dans cet exemple, un potentiomètre connecté à l'entrée A0 est utilisé pour simuler une entrée analogique, et les variations de la valeur sont affichées à l'aide du Graph widget. La plage d'entrée analogique de l'Arduino étant comprise entre 0 et 1023, tandis que le Graph widget accepte des valeurs comprises entre 0 et 100, la fonction map() est utilisée pour adapter la plage de valeurs.
Le Graph widget est conçu pour actualiser l'affichage uniquement lorsque la valeur change. Pour obtenir un effet de mise à jour périodique, une méthode simple consiste à vérifier la valeur à intervalles réguliers. Si la nouvelle valeur est identique à la précédente, elle est légèrement modifiée en ajoutant ou en soustrayant 1. Le Graph widget détecte ainsi un changement de valeur et actualise l'affichage, ce qui permet d'obtenir un effet de mise à jour dynamique à intervalles réguliers.

Conclusion
Cette présentation du programme d'exemple permet de mieux comprendre les différentes techniques mises en œuvre. Cet exemple peut également servir de base pour de futurs projets et contribuer à réduire le temps de développement. Le programme complet peut être téléchargé à partir du lien suivant : Modbus-MultiPageOperation sur GitHub.
Pour plus d'informations sur la communication RS485 et le protocole Modbus, vous pouvez également consulter notre article précédent : Introduction au RS485 pour Smart Display.