En aquest cas també convertirem el valor d'un comptador a codi Gray (com a l'exemple AI) però ho farem d'una manera diferent. La nostra funció de conversió a codi Gray tindrà 16 diferents adreces de retorn del tipus retlw (retorn amb un valor a W) i anirem a la instrucció que correspon al valor actual a base de modificar el comptador de programa.
El programa següent és una versió simplificada en la que ja sabem que no cal tocar PCH:
PROCESSOR 16F690 #include <xc.inc> config FOSC = INTRCIO, WDTE = OFF, PWRTE = OFF, MCLRE = OFF, CP = OFF config CPD = OFF, BOREN = OFF, IESO = OFF, FCMEN = OFF
Polsador EQU 0x20 ; Una variable amb l'estat del polsador (1 = premut) Previ EQU 0x21 ; I una amb l'estat previ del polsador Visualit EQU 0x22 ; Una variable on guardem el que mostraran els LED Compta EQU 0x23 ; Una variable per comptar iteracions Retard1 EQU 0x24 ; Variable per al bucle de retard temp EQU 0x25 ; Variable temporal
PSECT code, class=CODE, delta=2, abs
main:
bsf RP0 ; Tria el banc 1
movlw 0xFF ; Posa l'acumulador a FFh (tot uns)
movwf TRISA ; Posa tots els bits del port A com a entrada
clrf TRISC ; Posa tots els bits del port C com a sortida
bcf RP0
movlw 5 ; Retard d'1 s
call Rets ; Retard per evitar problemes amb el polsador
clrf Compta ; Posa el comptador d'iteracions a valor zero
clrf Visualit ; Posa el comptador dels LED a valor zero
clrf Previ ; L'estat previ del polsador és no premut
clrf PORTC ; Comencem amb els LED apagats
Bucle:
movlw 00000001B
movwf Polsador ; Activem polsador abans de comprovar
btfsc PORTA,3 ; Mira si està desactivada l'entrada A3
; Si desactivat (premut), no fa la instrucció següent
clrf Polsador ; Si no està premut, desactiva polsador
movf Previ,w ; Copia Previ a l'acumulador
xorwf Polsador,w ; Compara Previ amb Polsador, si són iguals s'activa Z
btfsc ZERO ; Si són iguals va a Final
goto Esborra
incf Compta,f ; Si són iguals, incrementa el valor de Compta
movf Compta,w ; Copia Compta a l'acumulador
xorlw 4 ; Comprova si val 4, si ho val s'activa Z
btfss ZERO ; Si val 4 no fa la instrucció següent
goto Final ; Si no era 4 va a Final
movf Polsador,w ; Copia Polsador a W, si val 0 s'activa Z
btfsc ZERO ; Si Polsador valia 1 (Z=0) no fa la instrucció següent
goto Invert ; Si no està premut, ja estem
incf Visualit,f ; Si ho està, incrementa el valor de Visualit
btfsc Visualit,4 ; Mira si hem arribat a 16
clrf Visualit ; Si hem arribat a 16, torna a posar el comptador a zero
movf Visualit,w ; El valor actual el guardem a W
call Conversio ; funció de conversió a codi Gray
movwf PORTC ; Posa el valor de W als LED
Invert:
movf Previ,w ; Copia Previ a l'acumulador
xorlw 00000001B ; Inverteix el valor
movwf Previ ; I ho guarda a Previ
Esborra:
clrf Compta ; Posa el comptador d'iteracions a valor zero
Final: ; Funció de retard 1 ms
nop
decfsz Retard1,f
goto Final
goto Bucle ; Repetim-ho...
;
; Funció de retard de 0,2 W s
;
Rets:
movwf Retard1+2
Bucles:
decfsz Retard1,f
goto Bucles
decfsz Retard1+1,f
goto Bucles
decfsz Retard1+2,f
goto Bucles
return
;
; funció de conversió a codi Gray
;
Conversio:
andlw 0x0F ; Preventivament, posa a zero els quatre bits superiors
movwf temp ; Ho guardem a la variable temporal per tenir lliure l'acumulador
; Aquest és el número que buscarem a la taula
movlw Taula ; Carrega l'adreça de la taula
addwf temp,w ; Hi afegeix el número que busquem (entre 0 i 15)
; i ho guarda a l'acumulador
movwf PCL ; Modifica el valor de PCL
Taula:
retlw 00000000B ; Si el punter és zero retornem amb el codi Gray de 0 a l'acumulador
retlw 00000001B ; Torna amb 1
retlw 00000011B ; Torna amb 2
retlw 00000010B ; Torna amb 3
retlw 00000110B ; Torna amb 4
retlw 00000111B ; Torna amb 5
retlw 00000101B ; Torna amb 6
retlw 00000100B ; Torna amb 7
retlw 00001100B ; Torna amb 8
retlw 00001101B ; Torna amb 9
retlw 00001111B ; Torna amb 10
retlw 00001110B ; Torna amb 11
retlw 00001010B ; Torna amb 12
retlw 00001011B ; Torna amb 13
retlw 00001001B ; Torna amb 14
retlw 00001000B ; Torna amb 15
END main
La directiva IRP ens permet entrar les dades de manera compacta. Si, per exemple, escrivim aquest tros de programa:
Taula: IRP number, 00001111B, 0xFA, "P", 15 retlw number ENDM
obtindrem a la memòria de programa les instruccions retlw corresponents a cada un dels valors incloent-hi una línia per a cada lletra del text que està entre cometes:
Taula: retlw 0xF ; Equival a 00001111B retlw 0xFA ; 0xFA retlw 0x50 ; Equival a 'P' retlw 0xF ; Equival a 15
La següent versió del programa fa el mateix que el primer que hem vist però emprant la directiva IRP.
PROCESSOR 16F690 #include <xc.inc> config FOSC = INTRCIO, WDTE = OFF, PWRTE = OFF, MCLRE = OFF, CP = OFF config CPD = OFF, BOREN = OFF, IESO = OFF, FCMEN = OFF
Polsador EQU 0x20 ; Una variable amb l'estat del polsador (1 = premut) Previ EQU 0x21 ; I una amb l'estat previ del polsador Visualit EQU 0x22 ; Una variable on guardem el que mostraran els LED Compta EQU 0x23 ; Una variable per comptar iteracions Retard1 EQU 0x24 ; Variable per al bucle de retard temp EQU 0x25 ; Variable temporal
PSECT code, class=CODE, delta=2, abs
main:
bsf RP0 ; Tria el banc 1
movlw 0xFF ; Posa l'acumulador a FFh (tot uns)
movwf TRISA ; Posa tots els bits del port A com a entrada
clrf TRISC ; Posa tots els bits del port C com a sortida
bcf RP0
movlw 5 ; Retard d'1 s
call Rets ; Retard per evitar problemes amb el polsador
clrf Compta ; Posa el comptador d'iteracions a valor zero
clrf Visualit ; Posa el comptador dels LED a valor zero
clrf Previ ; L'estat previ del polsador és no premut
clrf PORTC ; Comencem amb els LED apagats
Bucle:
movlw 00000001B
movwf Polsador ; Activem polsador abans de comprovar
btfsc PORTA,3 ; Mira si està desactivada l'entrada A3
; Si desactivat (premut), no fa la instrucció següent
clrf Polsador ; Si no està premut, desactiva polsador
movf Previ,w ; Copia Previ a l'acumulador
xorwf Polsador,w ; Compara Previ amb Polsador, si són iguals s'activa Z
btfsc ZERO ; Si són iguals va a Final
goto Esborra
incf Compta,f ; Si són iguals, incrementa el valor de Compta
movf Compta,w ; Copia Compta a l'acumulador
xorlw 4 ; Comprova si val 4, si ho val s'activa Z
btfss ZERO ; Si val 4 no fa la instrucció següent
goto Final ; Si no era 4 va a Final
movf Polsador,w ; Copia Polsador a W, si val 0 s'activa Z
btfsc ZERO ; Si Polsador valia 1 (Z=0) no fa la instrucció següent
goto Invert ; Si no està premut, ja estem
incf Visualit,f ; Si ho està, incrementa el valor de Visualit
btfsc Visualit,4 ; Mira si hem arribat a 16
clrf Visualit ; Si hem arribat a 16, torna a posar el comptador a zero
movf Visualit,w ; El valor actual el guardem a W
call Conversio ; funció de conversió a codi Gray
movwf PORTC ; Posa el valor de W als LED
Invert:
movf Previ,w ; Copia Previ a l'acumulador
xorlw 00000001B ; Inverteix el valor
movwf Previ ; I ho guarda a Previ
Esborra:
clrf Compta ; Posa el comptador d'iteracions a valor zero
Final: ; Funció de retard 1 ms
nop
decfsz Retard1,f
goto Final
goto Bucle ; Repetim-ho...
;
; Funció de retard de 0,2 W s
;
Rets:
movwf Retard1+2
Bucles:
decfsz Retard1,f
goto Bucles
decfsz Retard1+1,f
goto Bucles
decfsz Retard1+2,f
goto Bucles
return
;
; funció de conversió a codi Gray
;
Conversio:
andlw 0x0F ; Preventivament, posa a zero els quatre bits superiors
movwf temp ; Ho guardem a la variable temporal per tenir lliure l'acumulador
; Aquest és el número que buscarem a la taula
movlw Taula ; Carrega l'adreça de la taula
addwf temp,w ; Hi afegeix el número que busquem (entre 0 i 15)
; i ho guarda a l'acumulador
movwf PCL ; Modifica el valor de PCL
Taula:
IRP valors, 00000000B, 00000001B, 00000011B, 00000010B, 00000110B, 00000111B, 00000101B, 00000100B
retlw valors
ENDM
IRP valors, 00001100B, 00001101B, 00001111B, 00001110B, 00001010B, 00001011B, 00001001B, 00001000B
retlw valors
ENDM
END main
A continuació tenim una nova versió en la que la funció està posada de tal manera que una part de la taula està a PCH 00h i una altra a 01h; així ens veiem obligats a controlar PCH:
PROCESSOR 16F690 #include <xc.inc> config FOSC = INTRCIO, WDTE = OFF, PWRTE = OFF, MCLRE = OFF, CP = OFF config CPD = OFF, BOREN = OFF, IESO = OFF, FCMEN = OFF
Polsador EQU 0x20 ; Una variable amb l'estat del polsador (1 = premut) Previ EQU 0x21 ; I una amb l'estat previ del polsador Visualit EQU 0x22 ; Una variable on guardem el que mostraran els LED Compta EQU 0x23 ; Una variable per comptar iteracions Retard1 EQU 0x24 ; Variable per als bucles de retard (3 bytes) temp EQU 0x27 ; Variable temporal
PSECT code, class=CODE, delta=2, abs
main:
bsf RP0 ; Tria el banc 1
movlw 0xFF ; Posa l'acumulador a FFh (tot uns)
movwf TRISA ; Posa tots els bits del port A com a entrada
clrf TRISC ; Posa tots els bits del port C com a sortida
bcf RP0
movlw 5 ; Retard d'1 s
call Rets ; Retard per evitar problemes amb el polsador
clrf Compta ; Posa el comptador d'iteracions a valor zero
clrf Visualit ; Posa el comptador dels LED a valor zero
clrf Previ ; L'estat previ del polsador és no premut
clrf PORTC ; Comencem amb els LED apagats
Bucle:
movlw 00000001B
movwf Polsador ; Activem polsador abans de comprovar
btfsc PORTA,3 ; Mira si està desactivada l'entrada A3
; Si desactivat (premut), no fa la instrucció següent
clrf Polsador ; Si no està premut, desactiva polsador
movf Previ,w ; Copia Previ a l'acumulador
xorwf Polsador,w ; Compara Previ amb Polsador, si són iguals s'activa Z
btfsc ZERO ; Si són iguals va a Final
goto Esborra
incf Compta,f ; Si són iguals, incrementa el valor de Compta
movf Compta,w ; Copia Compta a l'acumulador
xorlw 4 ; Comprova si val 4, si ho val s'activa Z
btfss ZERO ; Si val 4 no fa la instrucció següent
goto Final ; Si no era 4 va a Final
movf Polsador,w ; Copia Polsador a W, si val 0 s'activa Z
btfsc ZERO ; Si Polsador valia 1 (Z=0) no fa la instrucció següent
goto Invert ; Si no està premut, ja estem
incf Visualit,f ; Si ho està, incrementa el valor de Visualit
btfsc Visualit,4 ; Mira si hem arribat a 16
clrf Visualit ; Si hem arribat a 16, torna a posar el comptador a zero
movf Visualit,w ; El valor actual el guardem a W
call Conversio ; funció de conversió a codi Gray
movwf PORTC ; Posa el valor de W als LED
Invert:
movf Previ,w ; Copia Previ a l'acumulador
xorlw 00000001B ; Inverteix el valor
movwf Previ ; I ho guarda a Previ
Esborra:
clrf Compta ; Posa el comptador d'iteracions a valor zero
Final: ; Funció de retard 1 ms
nop
decfsz Retard1,f
goto Final
goto Bucle ; Repetim-ho...
;
; Funció de retard de 0,2 W s
;
Rets:
movwf Retard1+2
Bucles:
decfsz Retard1,f
goto Bucles
decfsz Retard1+1,f
goto Bucles
decfsz Retard1+2,f
goto Bucles
return
;
; funció de conversió a codi Gray
;
ORG 0xf0 ; Adreça triada perquè segur canviï PCH
Conversio:
andlw 0x0F ; Preventivament, posa a zero els quatre bits superiors
movwf temp ; Ho guardem a la variable temporal per tenir lliure l'acumulador
; Aquest és el número que buscarem a la taula
movlw high Taula ; Carrega la part alta de l'adreça de la taula
movwf PCLATH ; Ho posa a la part alta de PC
movlw low Taula ; Carrega la part baixa de l'adreça de la taula
addwf temp,w ; Hi afegeix el número que busquem (entre 0 i 15)
; i ho guarda a l'acumulador
btfsc CARRY ; S'ha activat C?
incf PCLATH,f ; Si s'ha activat, incrementem PCLATH
movwf PCL ; Modifica el valor de PCL (i, per tant, també el de PCH)
Taula:
retlw 00000000B ; Si el punter és zero retornem amb el codi Gray de 0 a l'acumulador
retlw 00000001B ; Torna amb 1
retlw 00000011B ; Torna amb 2
retlw 00000010B ; Torna amb 3
retlw 00000110B ; Torna amb 4
retlw 00000111B ; Torna amb 5
retlw 00000101B ; Torna amb 6
retlw 00000100B ; Torna amb 7
retlw 00001100B ; Torna amb 8
retlw 00001101B ; Torna amb 9
retlw 00001111B ; Torna amb 10
retlw 00001110B ; Torna amb 11
retlw 00001010B ; Torna amb 12
retlw 00001011B ; Torna amb 13
retlw 00001001B ; Torna amb 14
retlw 00001000B ; Torna amb 15
END main

Aquesta obra d'Oriol Boix està llicenciada sota una llicència no importada Reconeixement-NoComercial-SenseObraDerivada 3.0.