Fréquencemètre à microcontrôleur PIC – Commande de l’afficheur LCD
L’afficheur est commandé par le HD44780 LCD controller. Pour le commander nous disposons des bornes suivantes:
RS = 0 instruction input, 1 data input,
R/W = 0 write to LCD, 1 read from LCD,
E = enable signal,
DB0 à DB7 = data bus line 0 (LSB) to line 7 (MSB).
L’afficheur comprend 2 lignes de 16 caractères:
- ligne 0 de 0×00 à 0x0F,
- ligne 1 de 0×40 à 0x4F.
L’afficheur peut être utilisé en mode 8 bits (8-bit interface) ou en mode 4 bits (8-bit interface). Dans ce dernier cas, seules les lignes DB4 à DB7 sont utilisées. Le quartet (nibble) de poids fort et écrit puis le quartet de poids faible. C’est cette dernière méthode qui est utilisée ici.
J’ai construit le module d’affichage pour qu’il soit entièrement réutilisable par une autre application. Il comprend un ensemble de routines utilisées au travers de macros. Il comprend les éléments suivants:
Définitions:
#define DECIMALPOINT '.' ; decimal symbol : dot, comma, … #define Number_notLeadingZero LCDOption,0x07 ; 1 = not leading zero ; NUMBER_FORMAT code #define END_FORMAT 0xFF #define DOT_FORMAT 0x2E #define NINE_FORMAT 0x39 #define ZERO_FORMAT 0x5A
Variables:
LCD_TEMP:1 ; LCD subroutines internal use
LCDOption:1 ; internal register don't use
LCDIndex:1 ; general purpose index
Macros:
IR_WRITE commande d’écriture d’instruction
BF_READ commande de lecture du busy flag
DR_WRITE commande d’écriture de data
DR_READ commande de lecture de data
LCDDisplay_NumberF <MSB_nombre>, <adresseFormat> afficher un nombre avec format
LCDDisplay_Textl <adresseTexte> afficher un texte
CURSOR_POS placer le curseur à la position indiquée dans le registre W
CURSOR_POS l <position> placer le curseur à la position indiquée en paramètre
LCDSet_Display_Control contrôle de l’afficheur: curseur ou non, clignotement
SET_NOT_LEADING_ZERO afficher les zéros
Tables:
TABLE_TEXT textes à afficher.
NUMBER_FORMAT format des nombres à afficher.
Attention à l’implantation de ces tables qui modifient PCL, registre de 8 bits, qui est l’adresse basse du compteur ordinal. Ces 2 tables de moins de 256 octets ont été placées pour cela à partir de l’adresse 0×01.
Description de TABLE_TEXT
La première instruction de la table modifie PCL.
Chaque texte commence par une étiquette, se termine par le retour de zéro binaire sous forme:
ETIQUETTE_TEXTE DT "TEXTE" RETLW 0
Ci-dessous TABLE_TEXT de notre programme.
;*****************************************************************************
; Text to display
; Relative character address is in W
;*****************************************************************************
TABLE_TEXT
addwf PCL ,F ; Jump to character pointed in W register
MOD_0
DT "NO IF" ; Note the zero termination.
retlw 0
MOD_1
DT "LO+IF" ; Note the zero termination.
retlw 0
MOD_2
DT "LO-IF" ; Note the zero termination.
retlw 0
MOD_3
DT "IF-LO" ; Note the zero termination.
retlw 0
MODE_LABEL
DT "MODE:"
retlw 0
IF_LABEL
DT "IF:"
retlw 0
UNDERFLOW_ERROR
DT "Underflow Error"
retlw 0
MHz_UNIT
DT "MHz"
retlw 0
TABLE_TEXT_END
retlw 0
;
IF ( (TABLE_TEXT & 0x0FF) >= (TABLE_TEXT_END & 0x0FF) )
MESSG "==============Warning - User Defined: Table 'TABLE_TEXT' crosses page boundary in computed jump=============="
ENDIF
Afficher un texte
L’affichage d’un texte se résume à une seule ligne qui utilise la macro LCDDisplay_Textl. Par exemple pour afficher l’unité de la fréquence:
LCDDisplay_Textl MHz_UNIT
Cas particulier de la traduction d’un code en texte
Ce cas se pose ici pour l’option MODE du setup qui propose 4 valeurs de 0 à 3. On affiche le code et sa traduction litérale. Ce problème se règle simplement en définissant une table intermédiaire ici appelée MOD_x (placé ici sous TABLE_TEXT) qui retourne l’adresse du texte à afficher dans le registre W. Le texte est affiché directement par la routine (et non la macro) LCDDisplayText de la façon suivante:
movf MODindex, w ; get address from TABLE_TEXT
call MOD_x ; return address MODE option text from TABLE_TEXT in W
call LCDDisplayText ; display text
Table intermédiaire MOD_x:
MOD_x ; MODindex is in W. Return TABLE_TEXT address into W register
addwf PCL ,F ; Jump to character pointed to in W register
retlw MOD_0 - TABLE_TEXT - 1
retlw MOD_1 - TABLE_TEXT - 1
retlw MOD_2 - TABLE_TEXT - 1
retlw MOD_3 - TABLE_TEXT - 1
Description de NUMBER_FORMAT
La première instruction de la table modifie PCL.
Chaque format commence par une étiquette, se termine par le retour de oxFF sous forme:
ETIQUETTE_FORMAT DT "FORMAT" RETLW 0xFF
Description du format
Le format sert à supprimer les zéros non significatifs, à indiquer la position du point décimal, à insérer des espaces pour séparer les milliers.
Z = supprime un zéro non significatif (leading zero). Dès qu’un chiffre différent de zéro est atteint ce code devient inactif.
. = point décimal, insère le caractère défini par DECIMALPOINT et inactive Z.
9 = insère le chiffre quel que soit sa valeur et inactive Z.
espace (valeur par défaut) = insère un espace.
L’affichage du nombre commence par la gauche (MSB) et s’arrête au dernier 9 s’il existe ou sinon au dernier Z. Le nombre doit être sous forme Décimal Codé Binaire étendu ( pas de nombre en ASCII).
Ci-dessous NUMBER_FORMAT de notre programme.
;*****************************************************************************
; Number format
; Relative format code address is in W
;*****************************************************************************
NUMBER_FORMAT
addwf PCL ,F ; Jump to character pointed in W register
FORMAT_MHz
DT "Z Z99.999 999" ; Note the FF termination.
retlw 0xFF
FORMAT_IF
DT "99.999" ; Note the FF termination.
retlw 0xFF
FORMAT_MOD
DT "9" ; Note the FF termination.
retlw 0xFF
NUMBER_FORMAT_END
retlw 0xFF
;
IF ( (NUMBER_FORMAT & 0x0FF) >= (NUMBER_FORMAT_END & 0x0FF) )
MESSG "==============Warning - User Defined: Table 'NUMBER_FORMAT' crosses page boundary in computed jump=============="
ENDIF
Ci-dessous la routine d’affichage d’un nombre.
;*****************************************************************************
; Display a number at cursor position using a table NUMBER_FORMAT
; Format sample: ZZZ Z9 or 99 or 9.999 or 9 999 999 ....
; Start address character must be in FSR
; Start address table NUMBER_FORMAT must be in W
; Number_notLeadingZero = 0 => Leading zeros are not displayed
; Number_notLeadingZero = 1 => zero is not Leading zero
;_______________________________________________________
; ASCII value x30 x31 x32 x33 x34 x35 x36 x37 x38 x39
; number 0 1 2 3 4 5 6 7 8 9
;_______________________________________________________
;*****************************************************************************
LCDDisplayNumberF
movwf LCDIndex ; Holds format address in table NUMBER_FORMAT
clrf LCDOption
LCDDisplayNumberFLoop
; is leading Zero ?
movfw LCDIndex
call NUMBER_FORMAT
xorlw 0x5A ; Check if "Z" format
btfsc STATUS, Z
goto Z_format ; yes, ====>
; is nine ?
movfw LCDIndex
call NUMBER_FORMAT
xorlw 0x39 ; Check if "9" format
btfsc STATUS, Z
goto nine_format ; yes, ====>
; is dot ?
movfw LCDIndex
call NUMBER_FORMAT
xorlw 0x2E ; Check if "." format
btfsc STATUS, Z
goto dot_format ; yes, ====>
; is end ?
movfw LCDIndex
call NUMBER_FORMAT
xorlw 0xFF ; Check if at end of format
btfsc STATUS, Z
goto LCDDisplayNumberFEnd ; yes, end =====================>
space_format ; default
btfss Number_notLeadingZero ; is a number 1 to 9 already displayed ?
goto nextIndexFormat ; no, no space to insert
movlw ' ' ; yes, insert a space
call LCDputChar4 ; Display character
goto nextIndexFormat
dot_format
SET_NOT_LEADING_ZERO ; to avoid future Z format
movlw DECIMALPOINT ; insert decimal point
call LCDputChar4 ; Display character
goto nextIndexFormat
nine_format
SET_NOT_LEADING_ZERO ; to avoid future Z format
goto displayASCII
Z_format
btfsc Number_notLeadingZero ; is a number 1 to 9 already displayed ?
goto displayASCII ; yes, display digit
movf INDF, f ; INDF -> INDF, set STATUS bit Z
btfsc STATUS, Z
goto nextDigit ; yes digit = 0, leading zero not displayed
SET_NOT_LEADING_ZERO ; no, display digit and avoid future Z format
displayASCII
movf INDF,W ; Digit -> W
iorlw 030h ; ASCII value mask
call LCDputChar4 ; Display character
nextDigit
incf FSR, f
nextIndexFormat
incf LCDIndex,f ; Point to next character
goto LCDDisplayNumberFLoop
LCDDisplayNumberFEnd
return
Afficher un nombre
L’affichage d’un nombre se résume à une seule ligne qui utilise la macro LCDDisplay_NumberF, par exemple pour afficher la fréquence mesurée:
LCDDisplay_NumberF BCD9, FORMAT_MHz
Télécharger le fichier Kicad du schèma .
Télécharger les fichiers source et hexa du fréquencemètre .
Liens
Fréquencemètre à microcontrôleur PIC
Fréquencemètre à microcontrôleur PIC – Description
Fréquencemètre à microcontrôleur PIC – Structure du programme
Fréquencemètre à microcontrôleur PIC – Mesure
Fréquencemètre à microcontrôleur PIC – Commande de l’afficheur LCD
Fréquencemètre à microcontrôleur PIC – Réalisation