[arduino] LCD et customs caractères

J’exhume un viel article de 2006 qui cause des customs caractères sur les afficheurs lcd.
Parce que ces derniers ne proposent pas forcément la totalité des caractères ascii propres au Français, j’avais redessiné les quelques caractères qui n’étaient pas dans la table du lcd dont je disposais à l’époque.
Ça c’est pas mal arrangé (techniquement) depuis et heureusement, avec la sortie de bibliothèques pour la gestion d’afficheurs lcd (même si la mode est plutôt aux afficheurs graphiques plutôt que de caractères).
Si l’article n’a plus toute sa fraicheur, il permet néanmoins de récupérer quelques dessins de caractères et l’appli qui va bien pour dessiner les votre (lien en bas de page).

design Version 1 design Version 2

Sur tous les afficheurs LCD, une mémoire graphique (CGROM) contient les dessins des différents caractères utilisables à l’écran, 192 au total.
Pour des raisons de marché, et de globalisation, la majeure partie des fabricants de lcd, n’intègrent à leur lcd que les caractères ASCII standards, sans accents, les caractères grecs et quelques caractères (katana) japonais.
Pour les autres malheureux, les fabricants ont inclus une zone mémoire adressable, dédiée à à la création de caractères, la CGRAM (Caracter Generator…).
Cette zone n’est pas gigantesque, il n’est pas question de redessiner la totalité des caractères…. non juste 8.

Sur les LCD, les caractères sont définis sur une matrice de 5×8, 5 cases sur l’horizontale et 8 sur la verticale.
Un caractère est donc une table de 8 chiffres, 8 octets. On peut customiser 8 caractères, soit au total 64 octets nécessaires pour cette opération.
Une zone mémoire de 64 octets est dédiée à cette opération, son adresse mémoire dans la CGRAM commence à l’adresse 64 (0×40 en hexa) et se termine donc à 127 (0x7F en hexa).

Pour écrire un caractère dans la CGRAM, on donne la commande avec l’adresse dans la CGRAM et on écrit la suite de 8 chiffres.
Pour écrire les 8 caractères d’un coups, il n’est pas nécessaire de donner les 8 adresses, ces adresses étant successives, il suffit d’envoyer les 64 chiffres.
Pour quitter le mode, il suffit de revenir en mode commande en envoyant un « retour à la home ».

Dans le cas d’Arduino :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void DefineCustomCaracters(void) {
    // { "é", "è", "ê", "à", "â", "û", "ù", "ç" }
    int customCars[8][8] = {{0x82,0x8C,0x80,0x8E,0x91,0x9F,0x90,0x8E},{136,134,128,142,145,159,144,142},{132,138,128,142,145,159,144,142},{136,134,128,143,145,147,141,128},{132,138,128,143,145,147,141,128},{132,138,128,145,145,147,141,128},{136,134,128,145,145,147,141,128},{128,142,144,144,145,142,130,140}};
    int i, j;
    // aller à l'adresse de début
    LcdCommandWrite(0x40);
    // ecrire les données à la suite
    for (i=0; i<=7; i++) {
        for (j=0; j<=7; j++) {
            LcdDataWrite(customCars[i][j]);
            delay(10);
        }
    }
    LcdCommandWrite(0x1);
}

Les caractères personnalisés portent les codes ASCII de 0 à 7, donc pour utiliser ces caractères, il faut les appeler.
Problème : ici, nos caractères spéciaux sont les accents qui ont un code ASCII. Dans la table de référence de l’écran LCD, ce code correspond à un katana (un caractère Japonais), il faut donc opérer une substitution des codes pour afficher la bonne lettre.
Si vous avez compté un peu, 8 caractères perso, c’est pas suffisant pour mettre tous les caractères accentués.
àâéèêëîïôöùûüet la fameuse cédille du c [ç].
Certes tous ces caractères ne sont pas très fréquents, néanmoins il va falloir opérer des choix.
Si il y a choix, ça signifie, que certains caractères ne seront pas visibles, il faut donc aussi prévoir les substitutions vers le caractère original (j’entends par là, pour le [ë ], remplacer par [e]) afin d’éviter l’affichage de caractères japonais.

Dans la table des caractères du LCD que j’utilise (il est ultra standard, vient de chez Conrad et est fabriqué par anag vision, chez data modul la font table est la même), on trouve quelques caractères allemands, (le [ä] a ümlaut, le [ü] u umlaut le [ö] o ümlaut), qu’on peut aussi trouver dans la langue française (en fait le [ü] seulement comme dans « aigüe » ). Les codes ASCII de ces caractères ne correspondent pas au code de la table de référence. Il faut rectifier la chose.

La carte Arduino, renvoie pour le caractère [ä], le code 164, qu’il faut substituer par le code 225 (ref du LCD), pour un affichage correcte du caractère. On opère de la sorte pour chaque caractère.
J’ai fait la chose de façon empirique (à la main), j’ai écrit un petit bout de programme pour afficher un caractère sur le lcd est son code dans la fenêtre de debug de l’IDE d’Arduino… un peu longué mais j’ai l’ensemble des codes.

J’ai écrit une petite fonction pour Arduino, qui se charge de substituer les codes de caractère.
Arduino est basé sur le langage C. En C, la modification d’une variable définie extérieurement à une fonction, ne peut se faire qu’en modifiant le pointeur de de la variable… oui, là je vois bien que certains ont décroché… c’est pas grave.
Un pointeur de variable en C, est en fait l’adresse où est stockée en mémoire la valeur de cette variable.
Le contenu du pointeur (de la valeur pointée) s’écrit en C « *mavariable ». Donc la fonction agit sur le contenu du pointeur pas sur la variable elle même, d’où l’écriture un peu bizarre…
L’important à retenir de ce script, est qu’il fonctionne, voilà tout :).

La substitution des caractères se fait dans la fonction d’écriture du caractère sur le LCD (lcdDataWrite), au début.
On envoie à la fonction, l’adresse de la variable pointée (&value).

1
2
3
4
5
void LcdDataWrite(int value) {
    ...
    // gestion des customs
    gestionCustomCars(&amp;value);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void gestionCustomCars (int *val) {
if (*val == 160) *val=3; // à
if (*val == 162) *val=4; // â
if (*val == 164) *val=225; //ä correspondance dans la font table du lcd
if (*val == 167) *val=7; // ç
if (*val == 168) *val=1; // è
if (*val == 169) *val=0; // é
if (*val == 170) *val=2; // ê
if (*val == 174) *val=105; // î > i
if (*val == 175) *val=105; // ï > i
if (*val == 180) *val=111; // ô > o
if (*val == 182) *val=239; // ö correspondance dans la font table du lcd
if (*val == 185) *val=6; // ù
if (*val == 187) *val=5; // û
if (*val == 188) *val=245; // ü correspondance dans la font table du lcd
}

Remarques concernant le design des lettres.
La lettre [e] est dessinée sur un carré de 5×5, la matrice est de 8 pixels de haut, mais le dessin commence sur la ligne 2 (en partant du bas), il ne nous reste donc que deux pixels en haut pour dessiner l’accent.C’est suffisant, excepté que l’accent est collé à la lettre ce qui est assez disgracieux et surtout pas très lisible.

Dans la première version, il a fallu décaler d’un pixel vers le bas, le dessin de la lettre. Si individuellement la lettre est bien équilibrée, dans un mot le décalage d’un pixel vers le bas, donne l’impression que la lettre tombe… J’ai tenté plusieurs dessins pour un [e] accentué mais 5 pixels de haut semble être le minimum pour une bonne lisibilité de la lettre (il y a 3 horizontales espacées d’1 pixel minimum).

Voici les tables de chiffres

1
2
3
4
5
6
7
8
9
é= {130,140,128,142,145,159,144,142}
è= {136,134,128,142,145,159,144,142}
ê= {132,138,128,142,145,159,144,142}
à= {136,134,128,142,129,143,145,143}
â= {132,138,128,142,129,143,145,143}
î= {132,138,128,140,132,132,132,142}
ô= {132,138,128,142,145,145,145,142}
ù= {136,134,128,145,145,145,147,141}
û= {132,138,128,145,145,145,147,141}

Version 1
design Version 1

Dans la version 2, le dessin de l’accent a été modifié, et collé à la lettre pour la laisser à la même hauteur. C’est un peu moins orthodoxe mais la lisibilité est conservée et la lettre à sa place. Dans un mot, on n’obtient plus cet effet de « chute » de la lettre.
Le cas du [u] et du [a] a été réglé en diminuant la hauteur du caractère de 1 pixel. Il a fallu modifier la forme du [a] mais le résultat reste lisible. Idem pour le [î] (i accent circonflex). On obtient au final une typo un peu disparate mais les caractères s’affichent correctement (en hauteur) placées dans un mot.

En fouillant plus avantt chez les fabricants d’écrans LCD, j’ai dégoté chez FarnellInOne un fabricant qui dispose d’un LCD avec une « font table » française. Le modèle est le BTHQ 42003AV-SRE-06 W.C. (KS 0073) de chez Batron. Le dessin des lettres est légèrement différent du mien, peut-être prefererez-vous vous inspirer de leur font table (je n’ai plus lien, mais Google est votre amis ! et chez Farnell, on trouve les datasheets des composants)

Voici les tables de chiffres

1
2
3
4
5
6
7
8
9
é= {130,132,142,145,159,144,142,128}
è= {136,132,142,145,159,144,142,128}
ê= {132,138,142,145,159,144,142,128}
à= {136,134,128,142,145,147,141,128}
â= {132,138,128,142,145,147,141,128}
î= {132,138,128,140,132,132,142,128}
ô= {132,138,128,142,145,145,142,128}
ù= {136,134,128,145,145,147,141,128}
û= {132,138,128,145,145,147,141,128}

Version 2
design Version 2

Le script Arduino (.zip) .Le zip contient la version 2 du design des lettres, et le schéma de câblage du LCD sur la carte Arduino (tiré du tuto sur le site Arduino).

googlage :
Une appli qui permet de convertir en chiffre un dessin de lettre, Un article sur le même site.


À propos de cet article