SOMMAIRE

Dans ce tutorial, nous allons voir comment utiliser un afficheur LCD 2*16. Nous apprendrons comment effectuer

  • les branchements
  • l'initialisation avec un PIC
  • l'ajout de nouveaux caractères dans la memoire du LCD.

L'afficheur LCD que nous utilisons dans notre projet est un afficheur 2 lignes de 16 caractères avec un contrôleur intégré compatible HD44780 standard. Il possède trois mémoires :

  • Une DDRAM qui contient les codes ascii des caractères affichés
  • Une CGROM qui contient la table ascii des caractères
  • Une CGRAM pour définir nos propres symboles

LCD
Afficheur LCD 16 caractères * 2 lignes, rétroéclairé

Dans une première partie nous allons décrire le fonctionnement de l'afficheur puis son initialisation, et pour terminer nous expliquerons les différentes routines d'affichage et comment elle sont utilisées.

1. Fonctionnement

Le schéma de branchement du lcd est le suivant:

LCD


Nous pouvons voir sur ce schéma que la patte RW du lcd est à la masse, nous allons donc uniquement écrire des données vers le lcd, et jamais en lire.

; LCD TRIS
BANK1
movlw b'11000000'
movwf tris_lcd ;ts les ports en sortie

De plus les pattes D0-D3 du lcd ne sont pas connectées, il est utilisé en mode 4 bits.

Voici comment une donnée est envoyée au lcd en mode 4 bits:

LCD


Les quatre bits de poids fort de l'octet à envoyer sont mis sur B0-B3 (D4-D7) puis on déclenche un pulse sur E. Ensuite on refait la même opération avec les 4 octets de poids faible. Le bit RS permet de définir si l'on travaille sur une commande ou sur une donnée de l'afficheur.

 

RS
Action
0
Commande
1
Donnée

Nous commençons par définir des petites fonctions qui seront appelées fréquemment. Voici la fonction qui permet de réaliser une impulsion sur E :

e_pulse:
nop
nop
bsf port_lcd,e
nop
nop
bcf port_lcd,e
return

Entre chaque commande, un temps est nécessaire pour que le lcd traite la donnée. Ce temps est égal à 50 ┬Ás ou 1,5 ms selon les instructions. Le quartz de la maquette est de 3,27 Mhz. Le temps d'un cycle est donc de 4 / 3,2768 = 1,22 µs. Nous avons écrit deux fonctions permettant de réaliser ces attentes :


;---------------------------------------------------------------------------
; Attend environ 50 us
;---------------------------------------------------------------------------
 
busy: ; nb = 6 * n + 5 = 41 cycles = 50 us
movlw 6
movwf temp_busy
attd_boucle:
nop
nop
nop
decfsz temp_busy,F
goto attd_boucle
return
 
 
;---------------------------------------------------------------------------
; Patience... Patience.... 1,5 ms
;---------------------------------------------------------------------------
 
big_busy:
movlw d'29'
movwf temp2
attd_boucle2:
call busy
decfsz temp2,F
goto attd_boucle2
return

Voici le code à utiliser pour envoyer une commande au lcd:

; Display On/Off Control
movlw b'00000000'
movwf port_lcd ;4 bits de poids fort sur B0-B3
call e_pulse ;donne une impulsion sur E
movlw b'00001100'
movwf port_lcd ;4 bits de poids faible sur B0-B3
call e_pulse ;donne une impulsion sur E
 
call busy ;attend 50┬Ás que la commande soit prise en compte

Pour envoyer une donnée, le code est quasiment le même, il faut juste prendre garde à mettre à 1 le bit RS. Par exemple pour afficher un nombre entre 0 et 9, on envoie pour les 4 bits de poids fort qui correspondent à la colonne des chiffres de la table de caractères, et la ligne correspond à la valeur du chiffre :

movlw b'00000011' ;colonne des chiffres de la table de car.
movwf port_lcd
bsf port_lcd,rs ;rs = 1 pour une donnée
call e_pulse
 
movf chiffre,w ;chiffre entre 0 et 9
movwf port_lcd
bsf port_lcd,rs
call e_pulse
 
call busy

 

2. Initialisation

L'initialisation du lcd consiste à envoyer plusieurs commandes à la suite définies par le tableau suivant:

LCD

Avant toute chose, il faut attendre 30 ms pour que le lcd se réveille. Puis la première commande permet au lcd de comprendre qu'il travaille sur 4 bits :

;---------------------------------------------------------------------------
; Init lcd
;---------------------------------------------------------------------------
 
init_lcd:
call attend_init ;attd 30ms
 
; Function Set
movlw b'00000010' ;mode 4 bits
movwf port_lcd
call e_pulse
nop
nop
movlw b'00000010' ;mode 4 bits
movwf port_lcd
call e_pulse
nop
nop
movlw b'00001000' ;mode 4 bits
movwf port_lcd
call e_pulse
nop
nop
call busy

La seconde commande lui indique qu'il doit utiliser les deux lignes de l'afficheur :

; 2 lignes
movlw b'00000010'
movwf port_lcd
call e_pulse
movlw b'00001100'
movwf port_lcd
call e_pulse
 
call big_busy ;attend 1,5 ms

La prochaine commande autorise l'affichage et cache le curseur :

; Display On/Off Control
movlw b'00000000'
movwf port_lcd
call e_pulse
movlw b'00001100'
movwf port_lcd
call e_pulse
 
call busy

Puis nous effaçons l'afficheur :

; Display Clear
movlw b'00000000'
movwf port_lcd
call e_pulse
movlw b'00000001'
movwf port_lcd
call e_pulse
 
call big_busy

Et finalement on dit au curseur de s'incrémenter à chaque nouvelle donnée :

;Entry Mode Set
movlw b'00000000'
movwf port_lcd
call e_pulse
movlw b'00000110'
movwf port_lcd
call e_pulse
 
call busy

La seconde partie de l'initialisation consiste à écrire les deux caractères spéciaux dans la CGRAM de l'afficheur. Pour cela nous allons envoyer une commande pour se placer au début de cette zone mémoire et nous allons ensuite envoyer ligne par ligne nos caractères. Le premier caractère est un 'é' et le deuxième représente un petit sourire :) Ces caractères sont définis dans la mémoire programme et chaque ligne est récupérée grâce à un retlw.

load_chars:
movlw b'00000100' ;adresse en CGRAM 0x00
movwf port_lcd
call e_pulse
nop
nop
movlw b'00000000'
movwf port_lcd
call e_pulse
call busy
 
clrf ligne ;charge le char ligne par ligne
loop_ligne:
call get_ligne ;recupère la ligne
clrf port_lcd
movwf temp
btfsc temp,4
bsf port_lcd,0
bsf port_lcd,rs
call e_pulse
movf temp,W
movwf port_lcd
bsf port_lcd,rs
call e_pulse
call busy ;charge le nvo char dans la CGRAM

;ligne suivante
incf ligne,F
btfss ligne,4
goto loop_ligne
 
return
 
get_ligne: ;renvoie la ligne de l'index ligne
movlw 1
movwf PCLATH ;attention car ns sommes dans la bank1 du prgm
movf ligne,w
addwf PCL,F ;saute à PC + ligne
 
; Lettre 0 = e avec un tit accent
retlw b'00001100'
retlw b'00000000'
retlw b'00001110'
retlw b'00010001'
retlw b'00011111'
retlw b'00010000'
retlw b'00001110'
retlw b'00000000'
 
; Lettre 1 = :)
retlw b'00000000'
retlw b'00001010'
retlw b'00000000'
retlw b'00000000'
retlw b'00010001'
retlw b'00001110'
retlw b'00000000'
retlw b'00000000'

3. Routines d'affichages

Nous allons présenter les différentes routines d'affichage. La première permet d'afficher le caractère dont le code ascii est contenu dans la variable temp:
affich_char:

swapf temp,w
movwf port_lcd
bsf port_lcd,rs
call e_pulse ;dabord le MSB
 
movf temp,w
movwf port_lcd
bsf port_lcd,rs
call e_pulse ;puis le LSB
 
call busy ;attend un peu
return

Une autre routine permet d'afficher la consigne qui est entre 0 et 3. Son fonctionnement a déjà été expliqué plus haut:

;---------------------------------------------------------------------------
; Affiche la consigne
;---------------------------------------------------------------------------
 
affich_consigne:
movlw b'00000011' ;colonne des chiffres
movwf port_lcd
bsf port_lcd,rs
call e_pulse
 
movf consigne,w ; consigne = [0-3]
movwf port_lcd
bsf port_lcd,rs
call e_pulse
 
call busy
 
return

Pour afficher la valeur de l'adc, nous avons besoin de 3 chiffres hexadécimaux car le résultat étant sur 10 bits, le maximum correspond à 0x3FF en hexa. Pour convertir la valeur de l'adc en hexa, nous prenons simplement les blocs de 4 bits que nous utilisons comme index dans une table qui nous renvoie leur valeur en ascii:

get_hex_char: ;charge les chars dans w
movlw 0
movwf PCLATH
movf temp,w
addwf PCL,F ;ajoute la valeur au pc
 
retlw '0'
retlw '1'
retlw '2'
retlw '3'
retlw '4'
retlw '5'
retlw '6'
retlw '7'
retlw '8'
retlw '9'
retlw 'A'
retlw 'B'
retlw 'C'
retlw 'D'
retlw 'E'
retlw 'F'

Il suffit ensuite de découper la valeur en 3 blocs, récupérer les caractères ascii et les envoyer à l'afficheur:

;---------------------------------------------------------------------------
; Affiche la valeur de l'adc
;---------------------------------------------------------------------------
 
affich_adc:
movf ADRESH,w ; 4 bits de poids faible du 2eme octet
andlw b'00001111'
movwf temp
call get_hex_char
movwf temp
call affich_char

BANK1
swapf ADRESL,w ;4 bits de poids fort du 1er octet
BANK0
andlw b'00001111'
movwf temp
call get_hex_char
movwf temp
call affich_char

BANK1
movf ADRESL,w ; 4 bits de poids faible du 1er octet
BANK0
andlw b'00001111'
movwf temp
call get_hex_char
movwf temp
call affich_char

return

Nous avons choisi d'afficher sur la première ligne de l'afficheur le texte : " Bonne année! J  " (car le TP avait lieu à la rentrée) et sur la deuxième ligne " Cons=3 Lum=3FF ". Pour cela nous utilisons une fonction similaire à celle du dessus. Les codes ascii des caractères sont stockés dans la mémoire programme et une boucle les récupère un par un pour les envoyer à l'afficheur:

;---------------------------------------------------------------------------
; Affiche une chaine
;---------------------------------------------------------------------------
 
affich_chaine:
incf index_char,f
call get_char
movwf temp
 
movf temp,f
btfsc zero ;si char = 0, on a fini
return
 
call affich_char
 
goto affich_chaine ;continue av le char suivant
 
get_char: ;charge les chars dans w
movlw 0
movwf PCLATH
movf index_char,w
addwf PCL,F
 
retlw ' '
retlw 'B'
retlw 'o'
retlw 'n'
retlw 'n'
retlw 'e'
retlw ' '
retlw 'A'
retlw 'n'
retlw 'n'
retlw e_accent
retlw 'e'
retlw '!'
retlw ' '
retlw smiley
retlw 0
 
retlw ' '
retlw 'C'
retlw 'o'
retlw 'n'
retlw 's'
retlw '='
retlw 0
 
retlw ' '
retlw 'L'
retlw 'u'
retlw 'm'
retlw '='
retlw 0

Les constantes e_accent et smiley valent respectivement 0 et 1 et correspondent aux adresses de la CGRAM de l'afficheur. La valeur index_char correspond à l'index des caractères dans la table et cette valeur est définie par les deux fonctions:

;---------------------------------------------------------------------------
; Change la ligne de l'afficheur
;---------------------------------------------------------------------------
 
ligne1:
movlw b'00001000'
movwf port_lcd
call e_pulse
movlw b'00000000'
movwf port_lcd
call e_pulse
call big_busy
call big_busy
call busy

movlw -1
movwf index_char ;remet l'index ? 0 de la fonction affich_chaine

return
 
ligne2:
movlw b'00001100'
movwf port_lcd
call e_pulse
movlw b'00000000'
movwf port_lcd
call e_pulse
call big_busy
call big_busy
call busy
 
movlw d'15' ;remet l'index au debut de la deuxieme ligne
movwf index_char ;ie a " Lum =..."

return

La boucle principale du programme pour l'affichage est donc la suivante:

  call init_lcd ;comme son nom l'indique...
call load_chars ;charge les chars speciaux :)
call lcd_clear ;efface tt
(...)
call ligne1 ;change de ligne
call affich_chaine ;affiche la premiere ligne
 
boucle_principale:
(...)
call ligne2 ; on se place a la ligne 2
call affich_chaine ; affiche " Cons="
call affich_consigne ; affiche la valeur entre 0 et 3
call affich_chaine ; affiche " Lum="
call affich_adc ; affiche la valeur de l'adc en hexa
(...)
goto boucle_principale

J'espère que ce tutorial vous aura aidé. :)