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