Dans cet article, je vais tenter de comparer 2 technologies de LCD ou du moins, 2 manières de piloter un écran LCD avec le Raspberry PI.
Mon article concerne aussi bien les Raspberry PI A/B/A+/B+/B2/B3/0 … autant dire toutes.
En effet, je vais utiliser, vous l’aurez compris les GPIOs du Raspberry PI
Le besoin
Le Raspberry est un appareil qui a révolutionné le monde de l’embarqué pour les néophytes. Il permet de faire énormément de petits ou moyens projets ou solutions, il permet même de créer des produits complets de manière très simple…
Cependant, dans énormément de cas, il manque souvent un écran, ne serait-ce que pour afficher l’adresse IP (quand on est en DHCP) ou connaître le statut et l’état de l’appareil.
A moins de passer par un moniteur HDMI, cette tâche n’est pas si évidente qu’on pourrait le penser.
Je ne parlerai pas non plus dans cet article des écrans TFT (promis j’en parle prochainement) qui eux ont un rôle plus avancé. Non, je veux parler des petits (ou gros) écrans LCD…
Bon ok, je parle de ceux la :
Oui ceux-là. On en voit dans tous les tutoriels.
En fait, il en existe de toutes les tailles, les formes (mouais… carré ou rectangulaire quoi) , en 2 lignes de 8, 2 lignes de 20, 4 lignes de 20 etc ….et toutes les couleurs (bleu sur blanc, noir sur blanc, blanc sur noir, jaune pipi …) afin de s’adapter le mieux possible à votre produit.
Le HD44780
Quand on parle de ce type d’écran, on devrait plutôt dire contrôleur, le HD44780 qui existe depuis de nombreuses années et qui est je pense le plus répandu et le moins cher.
Malgré tout ces avantages, je trouve que l’interface (bus datas) de cet écran commence à être obsolète et assez lourd.
En effet, au minimum, pour piloter cet écran, il vous faudra utiliser 7 GPIOs (en mode 4bits) et 11 GPIOs (en mode 8bits) de votre Raspberry PI. Autant dire que sur les premières versions des Raspberry A/B, vous mangez la moitié des GPIOs juste pour afficher environ 32 caractères.
Voilà l’exemple d’un montage.
Personnellement, face à ce montage, je trouve que l’affichage d’un caractère est assez cher payé (pas en € mais en ressource utilisé).
Tiens, d’ailleurs combien coûte un écran LCD à base de HD44780. Hé bien, la réponse est : ça dépend mais les premiers prix (petit format) commence à environ 2€.
Le ST7032
Je vais vous présenter un autre contrôleur existant, le ST7032, qui est, aussi, beaucoup utilisé sur les écrans LCD mais qui utilise une interface plus évoluée, j’ai nommé l’I2C.
Niveau choix, dans les écrans, j’avoue qu’il existe beaucoup moins de modèles que le HD44780 mais les formats les plus classiques existent et répondent à la plupart des besoins.
Je pense, d’ailleurs, que c’est le seul inconvénient de ce contrôleur (avec le prix un peu…).
Les avantages
Les avantages de ce contrôleur sont directement lié aux avantages de l’interface I2C. Donc, voici les avantages de cette technologie sur les bus datas:
- Seulement 2 pattes pour le flot de données (SCL « la clock », SDA « les datas »)
- Les 2 pattes sont « collaboratives » . c’est à dire que l’on peut les réutiliser pour d’autres appareils I2C
L’I2C fonctionne en mode Maître/Esclave comme sur le schéma suivant:
Le maître, c’est le Raspberry et l’esclave, l’écran. Mais sur le même bus, vous pouvez intégrer une horloge RTC sauvegardé, des capteurs etc…
Chaque esclave est en fait muni d’une adresse I2C. Si le maître pose une question à une adresse, seul l’appareil concerné répondra et les autres seront en attente.
Je simplifie volontairement mais vous pouvez aller consulter le wiki de l’interface I2C si vous êtes curieux.
Bref… avec cette technologie d’écran, vous ne prenez pas en otage les GPIOs de votre Raspberry PI !!!
Vous n’aurez besoin que des pattes suivantes :
- SDA
- SCL
- GND
- 3.3 ou 5V en fonction des modèles
- le RST de l’écran vers le 3.3 du raspberry
- 1 GPIO pour piloter le backlight
Concernant la patte qui va piloter le backlight, je fais un peu le violent car je le connecte directement au Raspberry (avec une petite résistance quand même). Cependant j’ai vu que les GPIOs du Raspberry pouvait fournir entre 2 et 16mA. Cela fait 1 an que mon écran a été installé, pour le moment pas de souci mais il est bien entendu préférable de passer par un transistor…
Concernant le prix (~= 2-3€):
C’est parfois un peu plus cher mais surtout moins répandu :
sinon une boutique qui en vend : BuyDisplay
Bon ok, passons au code alors:
Le code
Pré-requis:
- il faut installer la librairie wiringpi (pour le pilotage des GPIOs) apt-get install wiringpi
- il faut installer le module i2c-dev dans /etc/modules
- Dans /etc/modprobe.d/raspi-blacklist.conf il faut enlever la blacklist i2c-bcm2708
- il faut installer les outils i2c : sudo apt-get install i2c-tools
Méthode en C
[pastacode lang= »c » manual= »%23include%20%3Cstdio.h%3E%0A%23include%20%3Cstdlib.h%3E%0A%23include%20%3Cstring.h%3E%0A%23include%20%3Ctime.h%3E%0A%23include%20%3Cunistd.h%3E%0A%23include%20%3Csys%2Ftypes.h%3E%0A%23include%20%3Csys%2Fsocket.h%3E%0A%23include%20%3Csys%2Fioctl.h%3E%0A%23include%20%3Cnetinet%2Fin.h%3E%0A%23include%20%3Cnet%2Fif.h%3E%0A%23include%20%3Carpa%2Finet.h%3E%0A%23include%20%3Clinux%2Fi2c-dev.h%3E%0A%23include%20%3Cfcntl.h%3E%0A%23include%20%3Csys%2Fioctl.h%3E%0A%0A%23include%20%3CwiringPi.h%3E%0A%0A%23define%20LCD_ADDRESS%20(0x3e)%0A%23define%20LCD_CONTRAST%20100%0A%0A%23define%20LCD_RS_CMD%20(0x00)%0A%23define%20LCD_RS_DATA%20(0x40)%0A%23define%20LCD_CMD_CLEAR%20(0x01)%0A%23define%20LCD_CMD_HOME%20(0x03) » message= »En-tête » highlight= » » provider= »manual »/]
Voici les inclusions
[pastacode lang= »c » manual= »const%20int%20backlight%20%3D%2018%3B%0A%0Avoid%20LCD_init(int%20fd)%3B%0Avoid%20LCD_write(unsigned%20char%20rs%2C%20unsigned%20char%20data%2C%20int%20fd)%3B%0Avoid%20LCD_clear(int%20fd)%3B%0Avoid%20LCD_setCursor(unsigned%20char%20col%2C%20unsigned%20char%20row%2C%20int%20fd)%3B%0Avoid%20LCD_putc(unsigned%20char%20c%2C%20int%20fd)%3B%0Avoid%20LCD_puts(char%20*str%2C%20int%20fd)%3B » message= »Déclaration des fonctions » highlight= » » provider= »manual »/]
les fonctions
[pastacode lang= »c » manual= »void%20LCD_init(int%20fd)%0A%7B%0A%20usleep(40)%3B%0A%20%2F%2F%20Function%20Set.8bit%20bus%20mode%2C%202-line%20mode%2Cnormal%20font%2Cnormal%20instruction%20mode.%0A%20%20%20%20LCD_write(LCD_RS_CMD%2C%200b00111000%2C%20fd)%3B%0A%20%20%20%20%2F%2F%20Function%20Set.extension%20instruction%20mode..%0A%20%20%20%20LCD_write(LCD_RS_CMD%2C%200b00111001%2C%20fd)%3B%0A%20%20%20%20%2F%2F%20Internal%20OSC%20frequency(extension%20instruction%20mode)…%0A%20%20%20%20LCD_write(LCD_RS_CMD%2C%200b00010100%2C%20fd)%3B%0A%20%20%20%20%2F%2F%20Contrast%20set(extension%20instruction%20mode)……….4bit…%0A%20%20%20%20LCD_write(LCD_RS_CMD%2C%200b01110000%20%7C%20(LCD_CONTRAST%20%26%200xF)%2C%20fd)%3B%0A%20%20%20%20%2F%2F%20Power%2FICON%2FContrast%20set(extension%20instruction%20mode).%0A%20%20%20%20%2F%2F%20….%20On%2Cbooster%20On%2C………2bit…%0A%20%20%20%20LCD_write(LCD_RS_CMD%2C%200b01011100%20%7C%20((LCD_CONTRAST%20%3E%3E%204)%20%26%200×3)%2C%20fd)%3B%0A%20%20%20%20%2F%2F%20Follower%20control.internal%20follower%20on%2C%20%0A%20%20%20%20LCD_write(LCD_RS_CMD%2C%200b01101100%2C%20fd)%3B%0A%20%20%20%20%2F%2F%20…..%0A%20%20%20%20usleep(300)%3B%0A%20%20%20%20%0A%20%20%20%20%2F%2F%20Function%20Set.normal%20instruction%20mode.%0A%20%20%20%20LCD_write(LCD_RS_CMD%2C%200b00111000%2C%20fd)%3B%0A%20%20%20%20%2F%2F%20Display%20On%2FOff.Display%20On….%0A%20%20%20%20LCD_write(LCD_RS_CMD%2C%200b00001100%2C%20fd)%3B%0A%20%20%20%20%2F%2F%20Clear%20Display.%0A%20%20%20%20LCD_write(LCD_RS_CMD%2C%200b00001100%2C%20fd)%3B%0A%20%20%20%20%2F%2F%20…..%0A%20%20%20%20usleep(2)%3B%0A%7D%0A%0Avoid%20LCD_write(unsigned%20char%20rs%2C%20unsigned%20char%20data%2C%20int%20fd)%0A%7B%0A%20%20%20%20unsigned%20char%20buf%5B2%5D%3B%0A%20%0A%20%20%20%20if%20(rs%20%3D%3D%20LCD_RS_CMD%20%7C%7C%20rs%20%3D%3D%20LCD_RS_DATA)%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%2F%2F%20LCD_RS_CMD%20……….LCD_RS_DATA%20………%0A%20%20%20%20%20%20%20%20%0A%20%20buf%5B0%5D%20%3D%20rs%3B%0A%20%20buf%5B1%5D%20%3D%20data%3B%0A%20%20if%20(write(fd%2C%20buf%2C%202)%20!%3D%202)%0A%20%20%7B%0A%20%20%20printf(%22Error%20writeing%20to%20i2c%20slave1%5Cn%22)%3B%0A%20%20%7D%20%20%20%20%20%20%20%20%0A%20%20%20%20%7D%0A%20%20%20%20else%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%2F%2F%20rs….LCD_RS_CMD%2CLCD_RS_DATA………..%0A%20%20%20%20%7D%0A%7D%0A%0Avoid%20LCD_clear(int%20fd)%0A%7B%0A%20%20%20%20LCD_write(LCD_RS_CMD%2C%20LCD_CMD_CLEAR%2C%20fd)%3B%0A%20%20%20%20usleep(2)%3B%0A%20%20%20%20LCD_write(LCD_RS_CMD%2C%20LCD_CMD_HOME%2C%20fd)%3B%0A%20%20%20%20usleep(2)%3B%0A%7D%0A%0Avoid%20LCD_setCursor(unsigned%20char%20col%2C%20unsigned%20char%20row%2C%20int%20fd)%0A%7B%0A%20%20%20%20unsigned%20char%20offset%5B%5D%20%3D%20%7B0x00%2C%200×40%7D%3B%0A%20%20%20%20%0A%20%20%20%20if%20(row%20%3E%201)%20%20%20%20row%20%3D%201%3B%0A%20%20%20%20if%20(col%20%3E%2016)%20%20%20%20col%20%3D%2016%3B%0A%20%20%20%20%0A%20%20%20%20LCD_write(LCD_RS_CMD%2C%200×80%20%7C%20(col%20%2B%20offset%5Brow%5D)%2C%20fd)%3B%0A%7D%0A%0Avoid%20LCD_putc(unsigned%20char%20c%2C%20int%20fd)%0A%7B%0A%20%20%20%20LCD_write(LCD_RS_DATA%2C%20c%2C%20fd)%3B%0A%7D%0A%0Avoid%20LCD_puts(char%20*str%2C%20int%20fd)%0A%7B%0A%20%20%20%20int%20i%3B%0A%20%20%20%20for%20(i%20%3D%200%3B%20i%20%3C%2016%3B%20i%2B%2B)%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20if%20(str%5Bi%5D%20%3D%3D%200×00)%0A%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20break%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20else%0A%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20LCD_putc((unsigned%20int)str%5Bi%5D%2C%20fd)%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%7D » message= »les fonctions » highlight= » » provider= »manual »/]
le programme principal
[pastacode lang= »c » manual= »int%20main(int%20argc%2C%20char%20**argv)%0A%7B%0A%20int%20lcd%3B%20%20%20%20%20%20%20%2F%2F%20…………%0A%20char%20*i2cFileName%20%3D%20%22%2Fdev%2Fi2c-1%22%3B%20%2F%2F%20I2C……….%0A%20int%20lcdAddress%20%3D%20LCD_ADDRESS%3B%20%20%2F%2F%20I2C%20LCD%20……%0A%20wiringPiSetupGpio()%3B%0A%20pinMode(butPin%2C%20INPUT)%3B%20%20%20%20%20%20%2F%2F%20Set%20button%20as%20INPUT%20%0A%20pinMode(backlight%2COUTPUT)%3B%20%20%20%0A%20pullUpDnControl(butPin%2C%20PUD_DOWN)%3B%0A%20%0A%20%2F%2Fprintf(%22*****%20start%20i2c%20lcd%20test%20program%20*****%5Cn%22)%3B%0A%20%0A%20%2F%2F%20I2C….Read%2FWrite……..%0A%20if%20((lcd%20%3D%20open(i2cFileName%2C%20O_RDWR))%20%3C%200)%0A%20%7B%0A%20%20printf(%22Faild%20to%20open%20i2c%20port%5Cn%22)%3B%0A%20%20exit(1)%3B%0A%20%7D%0A%20%0A%20%2F%2F%20………..%0A%20if%20(ioctl(lcd%2C%20I2C_SLAVE%2C%20lcdAddress)%20%3C%200)%0A%20%7B%0A%20%20printf(%22Unable%20to%20get%20bus%20access%20to%20talk%20to%20slave%5Cn%22)%3B%0A%20%20exit(1)%3B%0A%20%7D%0A%20%0A%20usleep(100)%3B%0A%0A%20%2F%2F%20LCD….%0A%20LCD_init(lcd)%3B%0A%20%0A%20%2F%2F%20……..%0A%20%20%20%20LCD_setCursor(0%2C%200%2C%20lcd)%3B%0A%20%20%20%20LCD_puts(%22INIT%20…%22%2C%20lcd)%3B%0A%7D » message= »le programme principal » highlight= » » provider= »manual »/]
[pastacode lang= »c » manual= »%09%20gcc%20-o%20lcd%20i2c_lcd.c%20-l%20wiringpi » message= »Makefile » highlight= » » provider= »manual »/]
Méthode en bash
[pastacode lang= »c » manual= »%23!%2Fbin%2Fbash%0Afunction%20usage%20%7B%0A%20%20%20%20echo%20%22Usage%3A%20%240%20%5B-ic%5D%20%5B-p%20pos%5D%20message%22%20%3E%20%2Fdev%2Fstderr%3B%0A%20%20%20%20echo%20%22%20-i%20%3A%20LCD%20init%2C%20-c%20%3A%20Clear%20Screen%22%20%3E%20%2Fdev%2Fstderr%0A%20%20%20%20echo%20%22%20-p%20%3A%20position%20(0%3Atop%20left%2C%2040%3Abottom%20left)%22%20%3E%20%2Fdev%2Fstderr%0A%20%20%20%20exit%201%0A%7D%0A%5B%20%24%23%20%3D%200%20%5D%20%26%26%20usage%0A%0Awhile%20getopts%20%22icp%3A%22%20flag%3B%20do%0A%20%20%20%20case%20%24flag%20in%0A%09%5C%3F)%20usage%20%3B%3B%0A%09i)%20%20i2cset%20-y%201%200x3e%200%200×38%200×39%200×14%200×78%200x5e%200x6c%20i%0A%09%20%20%20%20sleep%200.25%0A%09%20%20%20%20i2cset%20-y%201%200x3e%200%200x0c%200×01%200×06%20i%0A%09%20%20%20%20sleep%200.05%0A%09%20%20%20%20%3B%3B%0A%09c)%20%20i2cset%20-y%201%200x3e%200%200×01%20%3B%3B%0A%09p)%20%20i2cset%20-y%201%200x3e%200%20%24((OPTARG%2B128))%20%3B%3B%0A%20%20%20%20esac%0Adone%0Ashift%20%24((OPTIND-1))%0A%5B%20%24%23%20%3D%200%20%5D%20%26%26%20exit%0A%0ALANG%3DC%0AMSG%3D%60echo%20-n%20%22%241%22%20%7C%20perl%20-pe%20’%24_%3Djoin%22%20%22%2Cmap%7Bord%20%7Dsplit%2F%2F’%60%0A%23echo%20%24MSG%0Ai2cset%20-y%201%200x3e%200×40%20%24MSG%20i%0A » message= » » highlight= » » provider= »manual »/]
Conclusion
Voici comment intégrer un écran LCD en I2C sur votre Raspberry PI. Je trouve personnellement que cette méthode est plus élégante que l’autre méthode (sur le plan pratique et visuel).
Bien entendu, si vous n’avez pas besoin d’utiliser les autres GPIOs disponibles du Raspberry PI, l’intérêt reste plus limité.
Mais désormais, vous n’aurez plus d’excuse pour ne pas économiser les GPIOs de votre Raspberry PI.