Ressources nécessaires
Tout au long de ce chapitre, nous aurons besoin, pour communiquer favorablement avec l'afficheur, d'une classe nommée seriallib
qui est spécialisée dans la communication série, sachant que l'afficheur se connecte à l'aide d'une prise USB
Comme son nom l'indique, une interface USB est aussi une interface série . Pour tous vos développements, vous aurez
donc besoin d'intégrer à la fois le fichier en-tête et le fichier de définition de cette classe serialib . Enfin, pour
bien maîtriser toutes les fonctionnalités de l'afficheur, je vous donne le document concernant l'ensemble des balises. Tout ceci se
trouve dans les liens ci-dessous :
Document sur l'afficheur AM-03127-LED Fichier de
déclaration de la classe serialib serialib.h Fichier
de déclaration de la classe serialib serialib.cpp
Premières expériences
Pour notre premier développement, je vous propose de connecter l'afficheur sur un simple PC classique. Dans un programme
rudimentaire, nous allons envoyer une trame sous forme de chaîne de caractères avec déjà toutes les bonnes balises qui nous
servira à vérifier la validité de la connexion. Ce message affichera sur la première page de l'afficheur soit bonjour ,
soit salut , avec un texte défilant en vert et un temps d'affichage fixe de 2 secondes.
Description de la trame
Je vous invite à regarder le document concernant l'afficheur AM-03127-LCD . La trame à envoyer est une chaîne de
caractères avec un certain nombre de balises. Voici quelques remarques que nous pouvons faire sur la constitution de cette trame
:
Identification de l'afficheur : Il est possible de connecter plusieurs afficheurs sur la liaison série, il faut donc
pouvoir choisir celui avec lequel nous devons communiquer. Chaque afficheur possède donc un identifiant qui d'origine est à 01 .
Nous pouvons également communiquer avec l'ensemble des afficheurs sur une même liaison série broadcast en
donnant comme identifiant la valeur 00 tout le monde . L'ossature minimum de la trame est donc la
suivante :
<IDXX> . . . CS <E>
La première balise <ID>
pour IDentifiant comporte le numéro de l'afficheur avec
lequel communiquer.
La dernière balise <E>
pour End termine systématiquement toute trame quelque soit
ce que vous désirez faire.
La somme de contrôle CS évalue le contenu de la trame placé entre les deux balises
précédentes. Le contrôle ici est de type XOR codé sur un simple octet mais traduit à l'aide de deux caractères
consécutifs donnant les valeurs hexadécimales équivalentes toute la trame est une chaîne de caratères .
Ainsi, si vous désirez communiquer avec le premier afficheur de la liste :
<ID01> . . . CS <E>
Afficher un message : L'une des fonctions principales d'un afficheur est bien entendu d'afficher le message de votre
choix. Voici la trame minimale que vous devez placer entre les deux balises d'identification et de fin :
<Ln><Pn><FX><MX><WX><FY>Votre message
Ligne de l'afficheur <L.>
pour Ligne : l'afficheur que nous utilisons ne possède
qu'une seule ligne, donc la valeur numérique à spécifier sera toujours 1 .
Page de l'afficheur <P.>
pour Page : Il est possible d'afficher jusqu'à 26 pages
sur un même afficheur. Ces pages seront lues les unes à la suite des autres. Pour identifier la page sur laquelle nous
désirons proposer un nouveau message, vous devez spécifier une des lettres de l'alphabet A ... Z .
Fonction d'apparition du message <F.>
: Il existe plusieurs façons d'afficher votre message :
immédiatement, en le faisant défiler vers la droite ou vers la gauche, en le faisant apparaître depuis la partie haute de
l'afficheur, etc.
Méthode d'affichage <M.>
: Il est possible d'afficher le message normalement ou avec un
clignotement plus ou moins rapide.
Temps d'apparition du message <W.>
pour Wait : Vous spécifiez à l'aide d'un chiffre
le temps de lecture de la page en cours.
Disparition du message <F.>
: Comme pour le faire apparaître, vous devez spécifier sa disparition
avec la même balise que précédemment.
Autres balises utiles pour la gestion des messages : Il possible de rajouter une balise à votre message qui offre
une fonctionnalité supplémentaire. Voici les balises que nous pouvons rajouter :
<AX>
: Modifie la police d'affichage, les caractères seront plus ou moins gros.
<BX>
: Émet un son plus ou moins long sur la page en cours.
<CX>
: Choisit une couleur pour le message : pour cet afficheur, toutes les couleurs proposées ne
sont pas pris en compte.
<KX>
: Permet d'intégrer une date ou une heure préformatée.
<UXX>
: Permet de rajouter des caractères avec des accents.
<NX>
: Permet de placer le message non plus à gauche par défaut mais à partir d'une
colonne spécifique.
Organisation des pages affichées <Tn>
: Il est possible de spécifier toutes les pages qui vont
être affichées, à partir de quel moment et dans quel ordre vous désirez les faire apparaître.
Supprimer une page <DLXPn>
: Vous pouvez supprimer le contenu actuel d'une page. Attention,
cela ne veut pas dire qu'elle ne sera plus affichée. Si vous ne désirez plus la voir du tout, il est nécessaire de passer pas
la commande d'organisation des pages.
Supprimer une organisation de pages <DTn>
: Il est possible d'avoir plusieurs organisations de
pages. À tout moment, vous pouvez supprimer une organisation spécifique. Vous pouvez même supprimer toutes les organisations.
Vous pouvez alors utiliser une page par défaut. Par contre, dans ce cas là, une seule page est visible.
Tout supprimer <D*>
: Si vous désirez retrouver votre afficheur tel qu'il était au départ, vous
pouvez grâce à cette balise, tout effacer.
Proposer une page par défaut <RPn>
: Si vous ne dérirez avoir qu'une seule page d'afficher,
vous pouvez utiliser cette commande.
Agir sur la luminosité globale de l'afficheur <BX>
: Enfin, vous pouvez contrôler la
luminosité de l'afficheur suivant quatre valeurs possibles de 25% à 100% .
Afficher un message de bienvenue qui dure deux secondes avec un défilement et de couleur verte
Après avoir pris connaissance avec les différents éléments qui constituent la trame à envoyer à l'afficheur, je vous propose de
réaliser notre premier programme extrêmement simple qui permet d'afficher un message de bienvenue.
N'oubliez pas qu'en mode console, il est systématiquement nécessaire d'intégrer dans votre projet la classe serialib .
Pour l'utiliser correctement, il suffit de créer un objet par défaut de cette classe. Il faut ensuite ouvrir la
connexion série USB , à l'aide de la méthode Open() de cet objet. Cette
méthode attend deux arguments. Le premier concerne le device correspondant à la connexion de l'afficheur sur le port USB . Ici, il s'agit de la valeur /dev/ttyUSB0 même valeur pour un PC
classique ou pour le pcDuino . Le deuxième permet de spécifier la vitesse de transmission série l'afficheur est
réglé à 9600 bauds . Si l'ouverture sur le port USB se passe correctement, la
méthode renvoie la valeur 1 . Enfin, pour envoyer la trame de votre choix, il suffit de faire appel à la méthode WriteString() .
Après toutes ces considérations, vous pouvez maintenant mettre en oeuvre votre programme. Vous testerez les deux trames
ci-dessous elles seront intégrées en dur dans le code :
<ID01><L1><PA><FE><MA><WC><FE><CE>bonjour11<E>
<ID01><L1><PA><FE><MA><WC><FE><CE>salut0F<E>
Vous testerez votre programme à la fois avec un PC classique, mais aussi sur la carte pcDuino. main.cpp
Il ne faut le visualiser qu'après avoir codé
#include "serialib.h"
#include <iostream>
using namespace std;
int main()
{
serialib usb;
int connexion = usb.Open("/dev/ttyUSB0", 9600);
if (connexion==1)
{
cout << "Afficheur connecté" << endl;
const char *trame = "<ID01><L1><PA><FE><MA><WC><FE><CE>salut0F<E>";
usb.WriteString(trame);
usleep(50000); // il faut laisser le temps de la transmission avant la clôture (50 ms)
}
else cout << "Afficheur non connecté" << endl;
return 0;
}
Trames en ligne de commande
Au lieu de placer les trames directement dans le code, je vous propose maintenant de faire en sorte que la trame soit donnée en
paramètre à la suite du programme que vous exécutez dans le mode console. Par ailleurs, pour nous simplifier grandement la tâche,
nous allons faire en sorte de calculer systématiquement le checksum de la trame à étudier, ce qui nous servira pour
l'étude suivante.
Trame en ligne de commande
Nous allons tout simplement reprendre le programme précédent en plaçant cette fois-ci la chaîne de caractères correspondant à la
trame juste après la commande d'exécution comme cela vous est montré ci-dessous. Modifier votre code de telle sorte que le
programme soit capable de récupérer cette information en ligne de commande.
main.cpp
#include "serialib.h"
#include <iostream>
using namespace std;
int main(int nombre, char *options[])
{
if (nombre==2)
{
serialib usb;
int connexion = usb.Open("/dev/ttyUSB0", 9600);
if (connexion==1)
{
cout << "Afficheur connecté" << endl;
usb.WriteString(options[1]);
usleep(50000);
}
else cout << "Afficheur non connecté" << endl;
}
return 0;
}
Calcul du checksum
Je vous propose maintenant de réaliser un petit programme que calcule automatiquement le checksum d'une trame proposée en ligne
de commande sans tenir compte de l'en-tête et de l'en-queue de la trame .Je rappelle que la somme de
contrôle CS évalue le contenu de la trame placé entre les deux balises <ID01>
et <E>
. Le contrôle ici est de type XOR codé sur un simple octet mais traduit à l'aide de deux
caractères consécutifs donnant les valeurs hexadécimales équivalentes toute la trame est une chaîne de caratères .
main.cpp
##include <iostream>
using namespace std;
int main(int nombre, char *options[])
{
if (nombre==2)
{
string trame = options[1];
char calcul = 0;
for (char octet : trame) calcul^=octet;
char bas = calcul & 0b00001111;
char haut = (calcul & 0b11110000) >> 4;
bas = bas < 10 ? bas+=0x30 :bas+=0x41-10;
haut = haut < 10 ? haut+=0x30 : haut+=0x41-10;
string checksum = {haut, bas};
cout << "Checksum = " << checksum << endl;
}
return 0;
}
Afficher un message avec calcul automatique du checksum
Pour finir, nous allons cumuler les deux petites études précédentes afin de réaliser un programme qui permet d'exécuter une
trame passée en ligne de commande avec le calcul automatique du checksum . Le programme doit alors envoyer la trame
complète à l'afficheur. Je vous propose de structurer votre programme en fabriquant une fonction checksum() à part
afin de bien séparer les différents traitements.
main.cpp
#include "serialib.h"
#include <iostream>
using namespace std;
string checksum(string trame)
{
char calcul = 0;
for (char octet : trame) calcul^=octet;
char bas = calcul & 0b00001111;
char haut = (calcul & 0b11110000) >> 4;
bas = bas < 10 ? bas+=0x30 :bas+=0x41-10;
haut = haut < 10 ? haut+=0x30 : haut+=0x41-10;
return {haut, bas};
}
int main(int nombre, char *options[])
{
if (nombre==2)
{
serialib usb;
int connexion = usb.Open("/dev/ttyUSB0", 9600);
if (connexion==1)
{
cout << "Afficheur connecté" << endl;
string trame = "<ID01>";
trame += options[1];
trame += checksum(options[1]);
trame += "<E>";
usb.WriteString(trame.c_str());
usleep(50000);
}
else cout << "Afficheur non connecté" << endl;
}
}
Tester l'afficheur en envoyant les bonnes trames
Nous allons profiter du programme précédent pour tester notre afficheur. L'objectif de ce chapitre n'est pas de concevoir des
applications, mais simplement d'envoyer un ensemble de trames pour bien comprendre et maîtriser toutes les possibilités qu'offre
cet afficheur. Ainsi, nous pourrons gérer l'ensemble des pages à afficher, les différentes couleurs, les types d'affichage comme
le clignotement, le défilement vers la droite ou la gauche, le scrolling vertical, etc.
Ensemble des exercices proposés trames à retrouver .
Document sur l'afficheur AM-03127-LED
Afficher un message quelconque, clignotant, de couleur rouge qui s'affiche immédiatement sans défilement , qui
dure cinq secondes et qui défile ensuite vers la droite.
Trame :
<L1><PA><FA><MB><WF><FF><CB>Bienvenue
Afficher un message quelconque en gras pendant 4 seconde qui apparaît progressivement de la partie haute de l'écran sans
mouvement du message lui-même et qui disparaît progressivement de nouveau vers le haut de l'écran.
Trame :
<L1><PA><FD><MA><WE><FC><AB>Bienvenue
Afficher le caractère unique à pile au centre de l'afficheur. Cette lettre arrive de la gauche s'arrête au centre de
l'écran pendant deux secondes et s'en va également à gauche de l'écran.
Trame :
<L1><PA><FE><MA><WC><FE><N23><U60>
Afficher le message Première qui s'affiche à gauche de l'écran avec les mêmes propriétés que précédemment.
Trame :
<L1><PA><FE><MA><WC><FE>Premi<U68>re
Afficher le message Bienvenue de toutes les couleurs.
Trame :
<L1><PA><FE><MA><WC><FE><CS>Bienvenue
Afficher le message BA sur la deuxième page avec la première lettre en rouge et la suivante en vert.
Trame :
<L1><PB><FE><MA><WC><FE><CB>B<CE>A
Faire en sorte que les trois premières pages de l'afficheur soient opérationnelles pour que ces pages s'affichent
indéfiniment, il faut que l'année de début soit 00 et l'année de fin 99 .
Trame :
<TA>00000000009900000000ABC
Supprimer la troisième page.
Trame :
<DL1PC>
Tout supprimer.
Trame :
<D*>
Afficher la date d'aujourd'hui sur la première page et l'heure actuelle sur la deuxième page.
Trame :
<TA>00000000009900000000AB
<L1><PA><FE><MA><WC><FE><KD>
<L1><PB><FE><MA><WC><FE><KT>
Agir sur la luminosité de l'écran pour que l'éclairage soit seulement à 25% du maximum.
Trame :
<BC>
Programmes utilitaires
Maintenant que nous connaissons mieux le fonctionnement des trames ainsi que le comportement global de l'afficheur, nous allons
réaliser des programmes, toujours en mode console, qui nous permettrons d'afficher directement sans s'occuper des trames ,
un ou plusieurs messages proposés en ligne de commande. Au fur et à mesure de notre progression, nous rajouterons certaines
sophistications comme la prise compte de la couleur, le mode de transition, la durée du message, etc.
Choisir le nombre de pages à afficher
Pour notre tout premier exercice, je vous propose de réaliser un programme qui permet de choisir le nombre de pages à afficher
en suivant l'ordre normal d'affichage ABC...Z . Le nom du programme d'exécution doit s'appeler pages et le
nombre de page doit être passé en ligne de commande. Par exemple, pour que l'écran soit capable d'afficher trois pages, voici ce
que vous devez saisir :
main.cpp
#include "serialib.h"
#include <iostream>
#include <sstream>
using namespace std;
string checksum(string trame)
{
char calcul = 0;
for (char octet : trame) calcul^=octet;
char bas = calcul & 0b00001111;
char haut = (calcul & 0b11110000) >> 4;
bas = bas < 10 ? bas+=0x30 :bas+=0x41-10;
haut = haut < 10 ? haut+=0x30 : haut+=0x41-10;
return {haut, bas};
}
int main(int nombre, char *options[])
{
if (nombre==2)
{
serialib usb;
int connexion = usb.Open("/dev/ttyUSB0", 9600);
if (connexion==1)
{
cout << "Afficheur connecté" << endl;
string commande = "<TA>00000000009900000000";
istringstream saisie(options[1]);
int pages;
saisie >> pages;
for (int i=0; i<pages; i++) commande += 'A'+i;
ostringstream trame;
trame << "<ID01>" << commande << checksum(commande) << "<E>";
usb.WriteString(trame.str().c_str());
usleep(50000);
}
else cout << "Afficheur non connecté" << endl;
}
}
Afficher un message passé en ligne de commande
Dans notre deuxième projet, nous allons réaliser un programme rudimentaire qui permet d'afficher le message passé en ligne de
commande sans plus aucune trame sur la première page de l'afficheur, avec une couleur verte. Le mode de
transition doit rester classique, c'est-à-dire avec un décalage vers la gauche pour l'apparition et la disparition du message,
toutefois avec une vitesse un petit peu plus lente que d'habitude.
main.cpp
#include "serialib.h"
#include <iostream>
#include <sstream>
using namespace std;
string checksum(string trame)
{
char calcul = 0;
for (char octet : trame) calcul^=octet;
char bas = calcul & 0b00001111;
char haut = (calcul & 0b11110000) >> 4;
bas = bas < 10 ? bas+=0x30 :bas+=0x41-10;
haut = haut < 10 ? haut+=0x30 : haut+=0x41-10;
return {haut, bas};
}
int main(int nombre, char *options[])
{
if (nombre==2)
{
serialib usb;
int connexion = usb.Open("/dev/ttyUSB0", 9600);
if (connexion==1)
{
cout << "Afficheur connecté" << endl;
string commande = "<L1><PA><FE><MQ><WC><FE><CE>";
commande += options[1];
ostringstream trame;
trame << "<ID01>" << commande << checksum(commande) << "<E>";
usb.WriteString(trame.str().c_str());
usleep(50000);
}
else cout << "Afficheur non connecté" << endl;
}
}
Afficher un seul message sur la page de son choix
Nous reprenons le projet précédent, mais cette fois-ci nous devons spécifier la page dans lequel le message doit s'afficher à
la suite du message . Par ailleurs, nous ne prennons pas en compte le choix de la couleur par défaut c'est la
couleur orange qui est prise en compte .
main.cpp
#include "serialib.h"
#include <iostream>
#include <sstream>
using namespace std;
string checksum(string trame)
{
char calcul = 0;
for (char octet : trame) calcul^=octet;
char bas = calcul & 0b00001111;
char haut = (calcul & 0b11110000) >> 4;
bas = bas < 10 ? bas+=0x30 :bas+=0x41-10;
haut = haut < 10 ? haut+=0x30 : haut+=0x41-10;
return {haut, bas};
}
int main(int nombre, char *options[])
{
if (nombre==3)
{
serialib usb;
int connexion = usb.Open("/dev/ttyUSB0", 9600);
if (connexion==1)
{
cout << "Afficheur connecté" << endl;
istringstream saisie(options[2]);
int page;
saisie >> page;
char lettre = 'A'+page-1;
ostringstream commande;
commande << "<L1><P" << lettre << "><FE><MA><WC><FE>" << options[1];
ostringstream trame;
trame << "<ID01>" << commande.str() << checksum(commande.str()) << "<E>";
usb.WriteString(trame.str().c_str());
usleep(50000);
}
else cout << "Afficheur non connecté" << endl;
}
}
Afficher plusieurs messages
Pour ce dernier exercice, vous allez mettre en oeuvre un programme qui permet d'afficher un ou plusieurs messages passés en
ligne de commande. Dans ce cas de figure, seuls les messages proposés doivent s'afficher. Ainsi, si vous ne prévoyez qu'un seul
message, seule la première page doit être active. Par ailleurs, les messages seront tous multicolores.
Pour que votre programme soit bien structuré, en plus de la fonction checksum() , je vous propose de mettre au point
plusieurs fonctions spécialisées.
void envoyerTrame(string commande)
: Cette fonction s'occupe d'envoyer la trame complète à l'afficheur à partir
de la commande spécialisée.
int nombrePages(char *nombre)
: Cette fonction envoie à l'afficheur la bonne trame qui permet d'afficher que les
messages proposés. La fonction retourne le nombre de page que l'utilisateur à saisi.
void affichePage(int page, string message)
: Cette fonction envoie le message requis sur la bonne page de
l'afficheur.
main.cpp
#include "serialib.h"
#include <iostream>
#include <sstream>
using namespace std;
serialib usb; // variable globale
string checksum(string trame)
{
char calcul = 0;
for (char octet : trame) calcul^=octet;
char bas = calcul & 0b00001111;
char haut = (calcul & 0b11110000) >> 4;
bas = bas < 10 ? bas+=0x30 :bas+=0x41-10;
haut = haut < 10 ? haut+=0x30 : haut+=0x41-10;
return {haut, bas};
}
void envoyerTrame(string commande)
{
ostringstream trame;
trame << "<ID01>" << commande << checksum(commande) << "<E>";
usb.WriteString(trame.str().c_str());
usleep(100000); // Attente de 1/10ème de seconde entre chaque trame
}
int nombrePages(char *nombre)
{
string commande = "<TA>00000000009900000000";
istringstream saisie(nombre);
int pages;
saisie >> pages;
for (int i=0; i<pages; i++) commande += 'A'+i;
envoyerTrame(commande);
return pages;
}
void affichePage(int page, string message)
{
char lettre = 'A'+page;
ostringstream commande;
commande << "<L1><P" << lettre << "><FE><MA><WC><FE><CS>" << message;
envoyerTrame(commande.str());
}
int main(int nombre, char *options[])
{
if (nombre>2)
{
int connexion = usb.Open("/dev/ttyUSB0", 9600);
if (connexion==1)
{
cout << "Afficheur connecté" << endl;
int nombre = nombrePages(options[1]);
for (int page=0; page<nombre; page++)
affichePage(page, options[2+page]);
}
else cout << "Afficheur non connecté" << endl;
}
}