En aquest exemple farem servir els polsadors per anar movent un cursor (groc) per la matriu de LED i encendre de color blau els punts seleccionats. D'aquesta manera, aconseguirem fer un dibuix. Les funcions assignades a cada polsador són les següents:
| Polsador | Funció |
| 0 | Lliure |
| 1 | Desplaçament horitzontal |
| 2 | Desplaçament vertical |
| 3 | Encendre o apagar LED |
| 4 | Lliure |
| 5 | Esborrar dibuix |
Encara que en aquest programa gastem poca memòria de dades (30 bytes) hem optat per guardar el vector figura, que és el que conté els punts del dibuix, al banc 1 de la memòria; així al banc 0 hi ha més espai disponible per si fem servir aquest programa com a base per a futurs projectes. Amb una idea semblant, hem implementat la consulta del polsador 4, encara que en aquest programa no té cap funció.
Fixem-nos que tots els accessos al vector que guarda el dibuix es fan emprant adreçament indirecte. Atès que l'adreçament indirecte treballa amb adreces de vuit bits, es pot accedir directament a les dades del banc 1 sense necessitat de canviar de banc.
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
Port EQU 0x20 ; Bits a enviar al port B Sortida EQU 0x21 ; Valors a enviar al MAX7221 (6 bytes, 48 bits) Compta EQU 0x27 ; Variable per comptar els bits a Envia_max Compt EQU 0x28 ; Variable per comptar els bytes Comp EQU 0x29 ; Variable per comptar els bits Filera EQU 0x2A ; Variable per comptar fileres Actiu EQU 0x2B ; Variable que diu quin color està actiu ; Actiu = 0 Apagat ; Actiu = 1 Vermell ; Actiu = 2 Verd ; Actiu = 3 Blau Polsador EQU 0x2C ; Variable que conté un bit per a cada polsador per saber si està premut x EQU 0x2D ; Coordenada X del cursor (0 a 7) ; X = 0 és la columna de la dreta y EQU 0x2E ; Coordenada Y del cursor (0 a 7) caux EQU 0x2F ; Comptador auxiliar mirar EQU 0x30 ; Espera que es deixi anar el polsador mascara EQU 0x31 ; Màscara per a les operacions amb bits Retard1 EQU 0x32 ; Variables per als cicles de retard Retard2 EQU 0x33 ; Zona de memòria de dades que no depèn del banc triat W_Copia EQU 0x70 ; Guardarà el contingut de W durant la interrupció ST_Copia EQU 0x71 ; Guardarà STATUS durant la interrupció ; Zona de memòria de dades del banc 1 figura EQU 0xA0 ; Aquí guardarem el dibuix (8 bytes, 8 fileres)
PSECT code, class=CODE, delta=2, abs main: ; Adreça 0 h goto Inici ; Saltem al lloc on hi ha el programa principal nop ; Zona de memòria de programa que no utilitzem nop nop
Interrup: ; Adreça 4 h
movwf W_Copia ; Copiem l'acumulador a W_Copia
swapf STATUS,w ; Copiem STATUS a l'acumulador permutant els nibbles
clrf STATUS ; Posa a 0 i així segur que el banc és el 0
movwf ST_Copia ; Guarda STATUS permutat a ST_Copia
btfss T0IF ; Mira si Timer0 ha arribat a zero
; Si hi ha arribat, no fa la instrucció següent
goto FiInt ; Si la interrupció no és del Timer0 no fem res
Timer0: ; Programa corresponent a Timer0
bcf T0IF ; Si ha arribat, desactivem el bit
movlw 100 ; Nova preselecció
movwf TMR0 ; Ho posem a TMR0
; Anem a gestionar el canvi de color
movlw 00000011B ; Descarta els bits que no serveixen
andwf Actiu,f
btfsc ZERO
goto NoZero ; Si Actiu val 0 no ho canvia
decf Actiu,f ; Passem a activar un altre color
btfss ZERO ; Si s'activa Z és que hem arribat a zero
goto NoZero ; Si és zero, tornem a 3
movlw 3
movwf Actiu
NoZero: ; Gestiona l'activació de tres MAX7221
; Segons Actiu, activa un color o un altre
movlw 00000011B ; Descarta els bits que no serveixen
andwf Actiu,f
btfsc ZERO ; Salta si el resultat no és zero
goto Apagat ; Si està apagat ho desactiva tot
movlw 1
xorwf Actiu,w
btfsc ZERO
goto Vermell ; Si val 1, activem el vermell
movlw 2
xorwf Actiu,w
btfsc ZERO
goto Verd ; Si val 2, activem el verd
; Si no és cap d'ells, activem el blau
movlw 0x01 ; Activat
movwf Sortida+4 ; Blau
movlw 0x00 ; Desactivat
movwf Sortida ; Vermell
movwf Sortida+2 ; Verd
movlw 1
goto Activa
Vermell:
movlw 0x01 ; Activat
movwf Sortida ; Vermell
movlw 0x00 ; Desactivat
movwf Sortida+2 ; Verd
movwf Sortida+4 ; Blau
nop ; Temps a afegir
nop
nop
nop
goto Activa
Verd:
movlw 0x01 ; Activat
movwf Sortida+2 ; Verd
movlw 0x00 ; Desactivat
movwf Sortida ; Vermell
movwf Sortida+4 ; Blau
goto Activa
Apagat:
movlw 0x00 ; Desactivat
movwf Sortida ; Vermell
movwf Sortida+2 ; Verd
movwf Sortida+4 ; Blau
Activa:
movlw 0x0C ; Shutdown mode
movwf Sortida+1 ; Ho prepara per enviar-ho
movwf Sortida+3 ; Ho prepara per enviar-ho
movwf Sortida+5 ; Ho prepara per enviar-ho
call Envia_max ; Ho envia als MAX7221
FiInt:
swapf ST_Copia,w ; Copia permutant ST_Copia a l'acumulador
movwf STATUS ; I ho passa a STATUS recuperant el valor d'abans
; de la interrupció
swapf W_Copia,f ; Permuta els bits de W_Copia
swapf W_Copia,w ; Torna a permutar els bits de W_Copia
; i els guarda a l'acumulador sense variar STATUS
retfie ; Torna al programa principal, on s'havia quedat
Inici:
bsf RP0 ; Tria el banc 1
movlw 10000101B ; Configuració de Timer0
; Com a temporitzador basat en rellotge
; 101 - Factor d'escala de 64
; I resistències de pull-up desactivades (valor per defecte)
movwf OPTION_REG ; Ho guarda al registre de configuració del Timer0
movlw 0xFF ; Posa l'acumulador a FFh (tot uns)
movwf TRISA ; Posa tots els bits del port A com a entrada
clrf TRISB ; Posa tots els bits del port B com a sortida
clrf TRISC ; Posa tots els bits del port C com a sortida
movlw 00010000B
movwf ADCON1 ; Posa el conversor a 1/8 de la freqüència
bcf RP0
bsf RP1 ; Tria el banc 2
movlw 00000101B
movwf ANSEL ; Configura AN0 i AN2 com entrada analògica
bcf RP0
bcf RP1 ; Tria el banc 0
clrf PORTC
clrf Port ; Posa a zero tots els bits de la variable Port
movf Port,w
movwf PORTB ; I ho envia al port B
movlw 00001001B
movwf ADCON0 ; Activa el conversor A/D connectat a AN2
; amb el resultat justificat per l'esquerra
call Ini3max ; Inicialitza la matriu
; Configura Timer 0 i activa la matriu i les interrupcions
; Una interrupció cada, aproximadament, 10 ms
movlw 1
movwf Actiu ; Posa en marxa el vermell
movlw 100 ; Presselecció de 100, que són 156 iteracions
movwf TMR0 ; Ho posa com a preselecció del temporitzador
movlw 10100000B ; Activem GIE i T0IE
movwf INTCON ; Activa les interrupcions globals i la de Timer0
call Apaga ; Apaga els LED
clrf x ; Posa x a zero
clrf y ; Posa y a zero
movlw 1
movwf mirar ; Posa mirar a 1
call PosaZero ; Posa a zero els bytes del vector figura
Bucle:
; Mirem els polsadors
; Un cop s'ha fet l'acció del polsador, no es tornarà a fer fins
; que es detecti que s'han deixat anar
call Llegir ; Llegeix els polsadors
movf mirar,f ; S'han de mirar els polsadors?
btfsc ZERO ; Si és zero no s'han de mirar
goto NoMirar ; Anem a veure si ja s'ha deixat anar
movf Polsador,w
xorlw 00000001B ; Mirem si s'ha premut el polsador 1
btfss ZERO ; Si és l'1, salta
goto NoEsPol1 ; No és l'1
; S'ha premut el polsador 1
incf x,f ; Incrementem x del cursor
movlw 00000111B ; Valor 7
andwf x,f ; Limitem x entre 0 i 7
goto Zmirar ; Ja estem del polsador 1
NoEsPol1:
movf Polsador,w
xorlw 00000010B ; Mirem si s'ha premut el polsador 2
btfss ZERO ; Si és el 2, salta
goto NoEsPol2 ; No és el 2
; S'ha premut el polsador 2
incf y,f ; Incrementem y del cursor
movlw 00000111B ; Valor 7
andwf y,f ; Limitem x entre 0 i 7
goto Zmirar ; Ja estem del polsador 2
NoEsPol2:
movf Polsador,w
xorlw 00000100B ; Mirem si s'ha premut el polsador 3
btfss ZERO ; Si és el 3, salta
goto NoEsPol3 ; No és el 3
; S'ha premut el polsador 3
movlw 00000001B ; Posem un 1 a la columna 0
movwf mascara ; Ho guardem com a màscara
movf x,w ; Agafem la x del cursor
btfsc ZERO ; Mirem si és zero
goto xZero ; Si és zero no cal fer res
movwf Comp ; Hem de rodar els bits x posicions
rodaX:
bcf CARRY ; Volem entrar zeros
rlf mascara,f ; Rodem a l'esquerra i entrem el zero
decfsz Comp,f ; Decrementa Comp
goto rodaX ; Si Comp no és zero, repeteix el bucle
xZero: ; Ja tenim l'1 posat a la columna
movlw figura ; Agafem l'adreça de la primera posició del vector
movwf FSR ; La posem com a punter d'adreçament indirecte
movf y,w ; Agafem la y del cursor
addwf FSR,f ; Ho afegim al punter
movf mascara,w ; Agafa la màscara
xorwf INDF,f ; L'aplica a la filera corresponent
goto Zmirar ; Ja estem del polsador 3
NoEsPol3:
movf Polsador,w
xorlw 00001000B ; Mirem si s'ha premut el polsador 4
btfss ZERO ; Si és el 4, salta
goto NoEsPol4 ; No és el 4
; S'ha premut el polsador 4
; El polsador 4 no fa res
goto Zmirar ; Ja estem del polsador 4
NoEsPol4:
movf Polsador,w
xorlw 00010000B ; Mirem si s'ha premut el polsador 5
btfss ZERO ; Si és el 5, salta
goto NoEsPol5 ; No és el 5
; S'ha premut el polsador 5
call PosaZero ; Posa a zero els bytes del vector figura
Zmirar: ; Ja estem del polsador 5
clrf mirar ; Posa mirar a zero fins que es deixi el polsador
NoEsPol5:
goto Matriu ; Envia la figura actual a la matriu
NoMirar:
movf Polsador,w ; Agafem la lectura dels polsadors
btfss ZERO ; Mira si és zero
goto Matriu ; Si no és zero cal seguir esperant
movlw 1 ; Si és zero, s'ha deixat el polsador
movwf mirar ; Posa mirar a 1
Matriu: ; Anem a mostrar la figura actual a la matriu de LED
clrf caux ; Primer enviem la filera 0
movlw 8 ; Número de bytes que cal enviar
movwf Compt ; Variable per comptar els bytes
movlw figura ; Agafem l'adreça de la primera posició del vector
movwf FSR ; La posem com a punter d'adreçament indirecte
BucleMatriu:
clrf Sortida ; Vermell, en principi, a zero
clrf Sortida+2 ; Verd, en principi, a zero
movf INDF,w ; Agafa la filera actual
movwf Sortida+4 ; La posa en el blau
; Anem a veure si estem a la filera del cursor
movf caux,w ; Mirem la filera que estem enviant
xorwf y,w ; I comparem amb la del cursor
btfss ZERO ; Si és zero, són iguals
goto noCur ; No és la filera del cursor
movlw 00000001B ; Posem un 1 a la columna 0
movwf mascara ; Ho guardem com a màscara
movf x,w ; Agafem la x del cursor
btfsc ZERO ; Mirem si és zero
goto xnul ; Si és zero no cal fer res
movwf Comp ; Hem de rodar els bits x posicions
giraX:
bcf CARRY ; Volem entrar zeros
rlf mascara,f ; Rodem a l'esquerra i entrem el zero
decfsz Comp,f ; Decrementa Comp
goto giraX ; Si Comp no és zero, repeteix el bucle
xnul: ; Ja tenim l'1 posat a la columna
movf mascara,w ; Agafem la màscara que hem preparat (set 0 i un 1)
iorwf Sortida,f ; L'apliquem al vermell
iorwf Sortida+2,f ; i al verd, per fer el cursor groc
comf mascara,w ; Agafem l'invers de la màscara (set 1 i un 0)
andwf Sortida+4,f ; L'apliquem al blau per apagar el LED
; Fi del tractament del cursor
noCur:
; A la matriu s'hi envien valors entre 1 i 8 (no de 0 a 7)
incf caux,w ; Incrementa l'índex i el guarda a w
movwf Sortida+1 ; El posa per indicar la filera que escrivim
movwf Sortida+3 ; El posa per indicar la filera que escrivim
movwf Sortida+5 ; El posa per indicar la filera que escrivim
call Envia3max ; Ho envia al MAX7221
incf FSR,f ; Incrementa el punter
incf caux,f ; Incrementa l'índex
decfsz Compt,f ; Decrementa Compt
goto BucleMatriu ; Si Compt no és zero, repeteix el bucle
movlw 1 ; Retard de 0,771 ms
call Retms
goto Bucle ; Torna a repetir
;
; Posa a zero els bytes del vector figura
;
PosaZero:
movlw 8 ; Número de bytes que cal posar a zero
movwf Compt ; Variable per comptar els bytes
movlw figura ; Agafem l'adreça de la primera posició del vector
movwf FSR ; La posem com a punter d'adreçament indirecte
BucleZero:
clrf INDF ; Posa a zero la posició actual
incf FSR,f ; Incrementa el punter
decfsz Compt,f ; Decrementa Compt
goto BucleZero ; Si Compt no és zero, repeteix el bucle
return
;
; Funció que llegeix els polsadors
;
Llegir:
clrf Polsador ; Si aquest valor no es canvia és que no hi ha cap polsador premut
nop ; espera un microsegon
nop ; espera un microsegon
nop ; espera un microsegon
nop ; espera un microsegon
nop ; espera un microsegon, en total 5
bsf GO_DONE ; Inicia la conversió
btfsc GO_DONE ; Quan el bit sigui 0 la conversió haurà acabat
goto $-1 ; repetim la línia fins que deixi de ser 0
; Comparació P1
movlw 220 ; Límit superior de P1
subwf ADRESH,w ; W = ADRESH - W
btfsc CARRY ; C = 1 si ADRESH >= W
goto NoEsP1 ; ADRESH >= W
movlw 200 ; Límit inferior de P1
subwf ADRESH,w ; W = ADRESH - W
btfss CARRY ; C = 1 si ADRESH >= W
goto NoEsP1 ; ADRESH < W
movlw 00000001B ; Polsador P1
movwf Polsador ; Ho copia a Polsador
goto NoEsP5
NoEsP1: ; Comparació P2
movlw 194 ; Límit superior de P2
subwf ADRESH,w ; W = ADRESH - W
btfsc CARRY ; C = 1 si ADRESH >= W
goto NoEsP2 ; ADRESH >= W
movlw 174 ; Límit inferior de P2
subwf ADRESH,w ; W = ADRESH - W
btfss CARRY ; C = 1 si ADRESH >= W
goto NoEsP2 ; ADRESH < W
movlw 00000010B ; Polsador P2
movwf Polsador ; Ho copia a Polsador
goto NoEsP5
NoEsP2: ; Comparació P3
movlw 163 ; Límit superior de P3
subwf ADRESH,w ; W = ADRESH - W
btfsc CARRY ; C = 1 si ADRESH >= W
goto NoEsP3 ; ADRESH >= W
movlw 143 ; Límit inferior de P3
subwf ADRESH,w ; W = ADRESH - W
btfss CARRY ; C = 1 si ADRESH >= W
goto NoEsP3 ; ADRESH < W
movlw 00000100B ; Polsador P3
movwf Polsador ; Ho copia a Polsador
goto NoEsP5
NoEsP3: ; Comparació P4
movlw 90 ; Límit superior de P4
subwf ADRESH,w ; W = ADRESH - W
btfsc CARRY ; C = 1 si ADRESH >= W
goto NoEsP4 ; ADRESH >= W
movlw 70 ; Límit inferior de P4
subwf ADRESH,w ; W = ADRESH - W
btfss CARRY ; C = 1 si ADRESH >= W
goto NoEsP4 ; ADRESH < W
movlw 00001000B ; Polsador P4
movwf Polsador ; Ho copia a Polsador
goto NoEsP5
NoEsP4: ; Comparació P5
movlw 55 ; Límit superior de P5
subwf ADRESH,w ; W = ADRESH - W
btfsc CARRY ; C = 1 si ADRESH >= W
goto NoEsP5 ; ADRESH >= W
movlw 35 ; Límit inferior de P5
subwf ADRESH,w ; W = ADRESH - W
btfss CARRY ; C = 1 si ADRESH >= W
goto NoEsP5 ; ADRESH < W
movlw 00010000B ; Polsador P5
movwf Polsador ; Ho copia a Polsador
NoEsP5:
return
;
; Apaga tots els LED
;
Apaga:
movlw 8 ; Hem d'apagar vuit fileres
movwf Filera ; Ho guarda al comptador
Repetir:
movf Filera,w ; Filera actual
movwf Sortida+1 ; Ho prepara per enviar-ho
movwf Sortida+3 ; Ho prepara per enviar-ho
movwf Sortida+5 ; Ho prepara per enviar-ho
movlw 00000000B ; Apagat
movwf Sortida ; Ho prepara per enviar-ho
movwf Sortida+2 ; Ho prepara per enviar-ho
movwf Sortida+4 ; Ho prepara per enviar-ho
call Envia3max ; Ho envia al MAX7221
decfsz Filera,f ; Passem a una altra filera
goto Repetir
return
;
; Inicialització de tres MAX7221
;
Ini3max:
movlw 0x0C ; Shutdown mode
movwf Sortida+1 ; Ho prepara per enviar-ho
movwf Sortida+3 ; Ho prepara per enviar-ho
movwf Sortida+5 ; Ho prepara per enviar-ho
movlw 0x00 ; Desactivat
movwf Sortida ; Ho prepara per enviar-ho
movwf Sortida+2 ; Ho prepara per enviar-ho
movwf Sortida+4 ; Ho prepara per enviar-ho
call Envia_max ; Ho envia al MAX7221
movlw 0x09 ; Decode mode
movwf Sortida+1 ; Ho prepara per enviar-ho
movwf Sortida+3 ; Ho prepara per enviar-ho
movwf Sortida+5 ; Ho prepara per enviar-ho
movlw 0x00 ; No decode
movwf Sortida ; Ho prepara per enviar-ho
movwf Sortida+2 ; Ho prepara per enviar-ho
movwf Sortida+4 ; Ho prepara per enviar-ho
call Envia_max ; Ho envia al MAX7221
movlw 0x0B ; Scan limit
movwf Sortida+1 ; Ho prepara per enviar-ho
movwf Sortida+3 ; Ho prepara per enviar-ho
movwf Sortida+5 ; Ho prepara per enviar-ho
movlw 0x07 ; Vuit fileres
movwf Sortida ; Ho prepara per enviar-ho
movwf Sortida+2 ; Ho prepara per enviar-ho
movwf Sortida+4 ; Ho prepara per enviar-ho
call Envia_max ; Ho envia al MAX7221
return
;
; Envia dades (48 bits) a tres MAX7221
; desactivant les interrupcions
;
Envia3max:
bcf T0IE ; Desactiva les interrupcions momentàniament
call Envia_max
bsf T0IE ; Reactiva les interrupcions a l'acabar
return
;
; Envia dades (48 bits) a tres MAX7221
;
; Els bits estan a les variables:
; Sortida Valor vermells
; Sortida+1 Adreça vermells
; Sortida+2 Valor verds
; Sortida+3 Adreça verds
; Sortida+4 Valor blaus
; Sortida+5 Adreça blaus
; Al final de la funció, el valor de Sortida queda corromput
; Si es vol conservar, cal copiar-lo a una altra variable
;
; Aquesta funció dura, aproximadament, 1 ms
Envia_max:
bcf Port,5 ; S'assegura que Clock està desactivat
bcf Port,6 ; S'assegura que Latch està desactivat
movf Port,w ; Agafa el valor de Port
movwf PORTB ; I el posa al port B
movlw 48 ; Número de bits a enviar
movwf Compta ; Variable per comptar els bits
Bucle3max:
bcf Port,4 ; Desactiva Data. Si toca activar-ho, ja ho farem
rlf Sortida,f ; Fa sortir el bit de més a l'esquerra cap a C
rlf Sortida+1,f ; i roda els altres a l'esquerra
rlf Sortida+2,f
rlf Sortida+3,f
rlf Sortida+4,f
rlf Sortida+5,f
btfsc CARRY ; Mira si el bit de l'esquerra era un 1
bsf Port,4 ; Si era 1, activa Data
movf Port,w ; Agafa el valor de Port. El valor que ha canviat és Data
movwf PORTB ; I el posa al port B
bsf Port,5 ; Activa Clock, forçant a llegir el bit
movf Port,w ; Agafa el valor de Port. El valor que ha canviat és Clock
movwf PORTB ; I el posa al port B
bcf Port,5 ; Desactiva Clock
movf Port,w ; Agafa el valor de Port. El valor que ha canviat és Clock
movwf PORTB ; I el posa al port B
decfsz Compta,f ; Decrementa Compta
goto Bucle3max ; Si Compta no és zero, repeteix el bucle
bsf Port,6 ; Torna a activar Latch
; Els valors es copiaran a la sortida del registre
movf Port,w ; Agafa el valor de Port. El valor que ha canviat és Latch
movwf PORTB ; I el posa al port B
return
;
; Funció de retard de 0,771 W ms
;
Retms:
movwf Retard2
Buclems:
decfsz Retard1,f
goto Buclems
decfsz Retard2,f
goto Buclems
return
END main
La següent versió del programa és molt similar però mostra el cursor intermitent. Per fer-ho, decrementa un comptador a cada cicle i quan s'assoleix el nombre de cicles canvia la variable que controla si el cursor està encès o apagat.
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 #define cic_int 35 ; Nombre de cicles per a la intermitència
Port EQU 0x20 ; Bits a enviar al port B Sortida EQU 0x21 ; Valors a enviar al MAX7221 (6 bytes, 48 bits) Compta EQU 0x27 ; Variable per comptar els bits a Envia_max Compt EQU 0x28 ; Variable per comptar els bytes Comp EQU 0x29 ; Variable per comptar els bits Filera EQU 0x2A ; Variable per comptar fileres Actiu EQU 0x2B ; Variable que diu quin color està actiu ; Actiu = 0 Apagat ; Actiu = 1 Vermell ; Actiu = 2 Verd ; Actiu = 3 Blau Polsador EQU 0x2C ; Variable que conté un bit per a cada polsador per saber si està premut x EQU 0x2D ; Coordenada X del cursor (0 a 7) ; X = 0 és la columna de la dreta y EQU 0x2E ; Coordenada Y del cursor (0 a 7) caux EQU 0x2F ; Comptador auxiliar mirar EQU 0x30 ; Espera que es deixi anar el polsador mascara EQU 0x31 ; Màscara per a les operacions amb bits compt_int EQU 0x32 ; Comptador de cicles per a la intermitència cur_on EQU 0x33 ; Controla l'estat del cursor Retard1 EQU 0x34 ; Variables per als cicles de retard Retard2 EQU 0x35 ; Zona de memòria de dades que no depèn del banc triat W_Copia EQU 0x70 ; Guardarà el contingut de W durant la interrupció ST_Copia EQU 0x71 ; Guardarà STATUS durant la interrupció ; Zona de memòria de dades del banc 1 figura EQU 0xA0 ; Aquí guardarem el dibuix (8 bytes, 8 fileres)
PSECT code, class=CODE, delta=2, abs main: ; Adreça 0 h goto Inici ; Saltem al lloc on hi ha el programa principal nop ; Zona de memòria de programa que no utilitzem nop nop
Interrup: ; Adreça 4 h
movwf W_Copia ; Copiem l'acumulador a W_Copia
swapf STATUS,w ; Copiem STATUS a l'acumulador permutant els nibbles
clrf STATUS ; Posa a 0 i així segur que el banc és el 0
movwf ST_Copia ; Guarda STATUS permutat a ST_Copia
btfss T0IF ; Mira si Timer0 ha arribat a zero
; Si hi ha arribat, no fa la instrucció següent
goto FiInt ; Si la interrupció no és del Timer0 no fem res
Timer0: ; Programa corresponent a Timer0
bcf T0IF ; Si ha arribat, desactivem el bit
movlw 100 ; Nova preselecció
movwf TMR0 ; Ho posem a TMR0
; Anem a gestionar el canvi de color
movlw 00000011B ; Descarta els bits que no serveixen
andwf Actiu,f
btfsc ZERO
goto NoZero ; Si Actiu val 0 no ho canvia
decf Actiu,f ; Passem a activar un altre color
btfss ZERO ; Si s'activa Z és que hem arribat a zero
goto NoZero ; Si és zero, tornem a 3
movlw 3
movwf Actiu
NoZero: ; Gestiona l'activació de tres MAX7221
; Segons Actiu, activa un color o un altre
movlw 00000011B ; Descarta els bits que no serveixen
andwf Actiu,f
btfsc ZERO ; Salta si el resultat no és zero
goto Apagat ; Si està apagat ho desactiva tot
movlw 1
xorwf Actiu,w
btfsc ZERO
goto Vermell ; Si val 1, activem el vermell
movlw 2
xorwf Actiu,w
btfsc ZERO
goto Verd ; Si val 2, activem el verd
; Si no és cap d'ells, activem el blau
movlw 0x01 ; Activat
movwf Sortida+4 ; Blau
movlw 0x00 ; Desactivat
movwf Sortida ; Vermell
movwf Sortida+2 ; Verd
movlw 1
goto Activa
Vermell:
movlw 0x01 ; Activat
movwf Sortida ; Vermell
movlw 0x00 ; Desactivat
movwf Sortida+2 ; Verd
movwf Sortida+4 ; Blau
nop ; Temps a afegir
nop
nop
nop
goto Activa
Verd:
movlw 0x01 ; Activat
movwf Sortida+2 ; Verd
movlw 0x00 ; Desactivat
movwf Sortida ; Vermell
movwf Sortida+4 ; Blau
goto Activa
Apagat:
movlw 0x00 ; Desactivat
movwf Sortida ; Vermell
movwf Sortida+2 ; Verd
movwf Sortida+4 ; Blau
Activa:
movlw 0x0C ; Shutdown mode
movwf Sortida+1 ; Ho prepara per enviar-ho
movwf Sortida+3 ; Ho prepara per enviar-ho
movwf Sortida+5 ; Ho prepara per enviar-ho
call Envia_max ; Ho envia als MAX7221
FiInt:
swapf ST_Copia,w ; Copia permutant ST_Copia a l'acumulador
movwf STATUS ; I ho passa a STATUS recuperant el valor d'abans
; de la interrupció
swapf W_Copia,f ; Permuta els bits de W_Copia
swapf W_Copia,w ; Torna a permutar els bits de W_Copia
; i els guarda a l'acumulador sense variar STATUS
retfie ; Torna al programa principal, on s'havia quedat
Inici:
bsf RP0 ; Tria el banc 1
movlw 10000101B ; Configuració de Timer0
; Com a temporitzador basat en rellotge
; 101 - Factor d'escala de 64
; I resistències de pull-up desactivades (valor per defecte)
movwf OPTION_REG ; Ho guarda al registre de configuració del Timer0
movlw 0xFF ; Posa l'acumulador a FFh (tot uns)
movwf TRISA ; Posa tots els bits del port A com a entrada
clrf TRISB ; Posa tots els bits del port B com a sortida
clrf TRISC ; Posa tots els bits del port C com a sortida
movlw 00010000B
movwf ADCON1 ; Posa el conversor a 1/8 de la freqüència
bcf RP0
bsf RP1 ; Tria el banc 2
movlw 00000101B
movwf ANSEL ; Configura AN0 i AN2 com entrada analògica
bcf RP0
bcf RP1 ; Tria el banc 0
clrf PORTC
clrf Port ; Posa a zero tots els bits de la variable Port
movf Port,w
movwf PORTB ; I ho envia al port B
movlw 00001001B
movwf ADCON0 ; Activa el conversor A/D connectat a AN2
; amb el resultat justificat per l'esquerra
call Ini3max ; Inicialitza la matriu
; Configura Timer 0 i activa la matriu i les interrupcions
; Una interrupció cada, aproximadament, 10 ms
movlw 1
movwf Actiu ; Posa en marxa el vermell
movlw 100 ; Presselecció de 100, que són 156 iteracions
movwf TMR0 ; Ho posa com a preselecció del temporitzador
movlw 10100000B ; Activem GIE i T0IE
movwf INTCON ; Activa les interrupcions globals i la de Timer0
call Apaga ; Apaga els LED
clrf x ; Posa x a zero
clrf y ; Posa y a zero
movlw 1
movwf mirar ; Posa mirar a 1
movwf cur_on ; Posa cur_on a 1
movlw cic_int ; Nombre de cicles per a la intermitència
movwf compt_int
call PosaZero ; Posa a zero els bytes del vector figura
Bucle:
; Mirem els polsadors
; Un cop s'ha fet l'acció del polsador, no es tornarà a fer fins
; que es detecti que s'han deixat anar
call Llegir ; Llegeix els polsadors
movf mirar,f ; S'han de mirar els polsadors?
btfsc ZERO ; Si és zero no s'han de mirar
goto NoMirar ; Anem a veure si ja s'ha deixat anar
movf Polsador,w
xorlw 00000001B ; Mirem si s'ha premut el polsador 1
btfss ZERO ; Si és l'1, salta
goto NoEsPol1 ; No és l'1
; S'ha premut el polsador 1
incf x,f ; Incrementem x del cursor
movlw 00000111B ; Valor 7
andwf x,f ; Limitem x entre 0 i 7
goto Zmirar ; Ja estem del polsador 1
NoEsPol1:
movf Polsador,w
xorlw 00000010B ; Mirem si s'ha premut el polsador 2
btfss ZERO ; Si és el 2, salta
goto NoEsPol2 ; No és el 2
; S'ha premut el polsador 2
incf y,f ; Incrementem y del cursor
movlw 00000111B ; Valor 7
andwf y,f ; Limitem x entre 0 i 7
goto Zmirar ; Ja estem del polsador 2
NoEsPol2:
movf Polsador,w
xorlw 00000100B ; Mirem si s'ha premut el polsador 3
btfss ZERO ; Si és el 3, salta
goto NoEsPol3 ; No és el 3
; S'ha premut el polsador 3
movlw 00000001B ; Posem un 1 a la columna 0
movwf mascara ; Ho guardem com a màscara
movf x,w ; Agafem la x del cursor
btfsc ZERO ; Mirem si és zero
goto xZero ; Si és zero no cal fer res
movwf Comp ; Hem de rodar els bits x posicions
rodaX:
bcf CARRY ; Volem entrar zeros
rlf mascara,f ; Rodem a l'esquerra i entrem el zero
decfsz Comp,f ; Decrementa Comp
goto rodaX ; Si Comp no és zero, repeteix el bucle
xZero: ; Ja tenim l'1 posat a la columna
movlw figura ; Agafem l'adreça de la primera posició del vector
movwf FSR ; La posem com a punter d'adreçament indirecte
movf y,w ; Agafem la y del cursor
addwf FSR,f ; Ho afegim al punter
movf mascara,w ; Agafa la màscara
xorwf INDF,f ; L'aplica a la filera corresponent
goto Zmirar ; Ja estem del polsador 3
NoEsPol3:
movf Polsador,w
xorlw 00001000B ; Mirem si s'ha premut el polsador 4
btfss ZERO ; Si és el 4, salta
goto NoEsPol4 ; No és el 4
; S'ha premut el polsador 4
; El polsador 4 no fa res
goto Zmirar ; Ja estem del polsador 4
NoEsPol4:
movf Polsador,w
xorlw 00010000B ; Mirem si s'ha premut el polsador 5
btfss ZERO ; Si és el 5, salta
goto NoEsPol5 ; No és el 5
; S'ha premut el polsador 5
call PosaZero ; Posa a zero els bytes del vector figura
Zmirar: ; Ja estem del polsador 5
clrf mirar ; Posa mirar a zero fins que es deixi el polsador
NoEsPol5:
goto Matriu ; Envia la figura actual a la matriu
NoMirar:
movf Polsador,w ; Agafem la lectura dels polsadors
btfss ZERO ; Mira si és zero
goto Matriu ; Si no és zero cal seguir esperant
movlw 1 ; Si és zero, s'ha deixat el polsador
movwf mirar ; Posa mirar a 1
Matriu: ; Anem a mostrar la figura actual a la matriu de LED
clrf caux ; Primer enviem la filera 0
movlw 8 ; Número de bytes que cal enviar
movwf Compt ; Variable per comptar els bytes
movlw figura ; Agafem l'adreça de la primera posició del vector
movwf FSR ; La posem com a punter d'adreçament indirecte
BucleMatriu:
clrf Sortida ; Vermell, en principi, a zero
clrf Sortida+2 ; Verd, en principi, a zero
movf INDF,w ; Agafa la filera actual
movwf Sortida+4 ; La posa en el blau
; Mirem si s'ha de mostrar el cursor
movf cur_on,w ; Mirem el valor de cur_on
btfsc ZERO ; Si no és zero, mostrem el cursor
goto noCur ; Si és zero no hem de mostrar el cursor
; Anem a veure si estem a la filera del cursor
movf caux,w ; Mirem la filera que estem enviant
xorwf y,w ; I comparem amb la del cursor
btfss ZERO ; Si és zero, són iguals
goto noCur ; No és la filera del cursor
movlw 00000001B ; Posem un 1 a la columna 0
movwf mascara ; Ho guardem com a màscara
movf x,w ; Agafem la x del cursor
btfsc ZERO ; Mirem si és zero
goto xnul ; Si és zero no cal fer res
movwf Comp ; Hem de rodar els bits x posicions
giraX:
bcf CARRY ; Volem entrar zeros
rlf mascara,f ; Rodem a l'esquerra i entrem el zero
decfsz Comp,f ; Decrementa Comp
goto giraX ; Si Comp no és zero, repeteix el bucle
xnul: ; Ja tenim l'1 posat a la columna
movf mascara,w ; Agafem la màscara que hem preparat (set 0 i un 1)
iorwf Sortida,f ; L'apliquem al vermell
iorwf Sortida+2,f ; i al verd, per fer el cursor groc
comf mascara,w ; Agafem l'invers de la màscara (set 1 i un 0)
andwf Sortida+4,f ; L'apliquem al blau per apagar el LED
; Fi del tractament del cursor
noCur:
; A la matriu s'hi envien valors entre 1 i 8 (no de 0 a 7)
incf caux,w ; Incrementa l'índex i el guarda a w
movwf Sortida+1 ; El posa per indicar la filera que escrivim
movwf Sortida+3 ; El posa per indicar la filera que escrivim
movwf Sortida+5 ; El posa per indicar la filera que escrivim
call Envia3max ; Ho envia al MAX7221
incf FSR,f ; Incrementa el punter
incf caux,f ; Incrementa l'índex
decfsz Compt,f ; Decrementa Compt
goto BucleMatriu ; Si Compt no és zero, repeteix el bucle
movlw 1 ; Retard de 0,771 ms
call Retms
decfsz compt_int,f ; Decrementa el comptador per a la intermitència
goto Bucle ; Si no és zero, torna a l'inici del bucle
movlw cic_int ; Nombre de cicles per a la intermitència
movwf compt_int
incf cur_on,f ; Incrementa cur_on
movlw 00000001B ; Valor 1
andwf cur_on,f ; Limitem cur_on entre 0 i 1
goto Bucle ; Torna a repetir
;
; Posa a zero els bytes del vector figura
;
PosaZero:
movlw 8 ; Número de bytes que cal posar a zero
movwf Compt ; Variable per comptar els bytes
movlw figura ; Agafem l'adreça de la primera posició del vector
movwf FSR ; La posem com a punter d'adreçament indirecte
BucleZero:
clrf INDF ; Posa a zero la posició actual
incf FSR,f ; Incrementa el punter
decfsz Compt,f ; Decrementa Compt
goto BucleZero ; Si Compt no és zero, repeteix el bucle
return
;
; Funció que llegeix els polsadors
;
Llegir:
clrf Polsador ; Si aquest valor no es canvia és que no hi ha cap polsador premut
nop ; espera un microsegon
nop ; espera un microsegon
nop ; espera un microsegon
nop ; espera un microsegon
nop ; espera un microsegon, en total 5
bsf GO_DONE ; Inicia la conversió
btfsc GO_DONE ; Quan el bit sigui 0 la conversió haurà acabat
goto $-1 ; repetim la línia fins que deixi de ser 0
; Comparació P1
movlw 220 ; Límit superior de P1
subwf ADRESH,w ; W = ADRESH - W
btfsc CARRY ; C = 1 si ADRESH >= W
goto NoEsP1 ; ADRESH >= W
movlw 200 ; Límit inferior de P1
subwf ADRESH,w ; W = ADRESH - W
btfss CARRY ; C = 1 si ADRESH >= W
goto NoEsP1 ; ADRESH < W
movlw 00000001B ; Polsador P1
movwf Polsador ; Ho copia a Polsador
goto NoEsP5
NoEsP1: ; Comparació P2
movlw 194 ; Límit superior de P2
subwf ADRESH,w ; W = ADRESH - W
btfsc CARRY ; C = 1 si ADRESH >= W
goto NoEsP2 ; ADRESH >= W
movlw 174 ; Límit inferior de P2
subwf ADRESH,w ; W = ADRESH - W
btfss CARRY ; C = 1 si ADRESH >= W
goto NoEsP2 ; ADRESH < W
movlw 00000010B ; Polsador P2
movwf Polsador ; Ho copia a Polsador
goto NoEsP5
NoEsP2: ; Comparació P3
movlw 163 ; Límit superior de P3
subwf ADRESH,w ; W = ADRESH - W
btfsc CARRY ; C = 1 si ADRESH >= W
goto NoEsP3 ; ADRESH >= W
movlw 143 ; Límit inferior de P3
subwf ADRESH,w ; W = ADRESH - W
btfss CARRY ; C = 1 si ADRESH >= W
goto NoEsP3 ; ADRESH < W
movlw 00000100B ; Polsador P3
movwf Polsador ; Ho copia a Polsador
goto NoEsP5
NoEsP3: ; Comparació P4
movlw 90 ; Límit superior de P4
subwf ADRESH,w ; W = ADRESH - W
btfsc CARRY ; C = 1 si ADRESH >= W
goto NoEsP4 ; ADRESH >= W
movlw 70 ; Límit inferior de P4
subwf ADRESH,w ; W = ADRESH - W
btfss CARRY ; C = 1 si ADRESH >= W
goto NoEsP4 ; ADRESH < W
movlw 00001000B ; Polsador P4
movwf Polsador ; Ho copia a Polsador
goto NoEsP5
NoEsP4: ; Comparació P5
movlw 55 ; Límit superior de P5
subwf ADRESH,w ; W = ADRESH - W
btfsc CARRY ; C = 1 si ADRESH >= W
goto NoEsP5 ; ADRESH >= W
movlw 35 ; Límit inferior de P5
subwf ADRESH,w ; W = ADRESH - W
btfss CARRY ; C = 1 si ADRESH >= W
goto NoEsP5 ; ADRESH < W
movlw 00010000B ; Polsador P5
movwf Polsador ; Ho copia a Polsador
NoEsP5:
return
;
; Apaga tots els LED
;
Apaga:
movlw 8 ; Hem d'apagar vuit fileres
movwf Filera ; Ho guarda al comptador
Repetir:
movf Filera,w ; Filera actual
movwf Sortida+1 ; Ho prepara per enviar-ho
movwf Sortida+3 ; Ho prepara per enviar-ho
movwf Sortida+5 ; Ho prepara per enviar-ho
movlw 00000000B ; Apagat
movwf Sortida ; Ho prepara per enviar-ho
movwf Sortida+2 ; Ho prepara per enviar-ho
movwf Sortida+4 ; Ho prepara per enviar-ho
call Envia3max ; Ho envia al MAX7221
decfsz Filera,f ; Passem a una altra filera
goto Repetir
return
;
; Inicialització de tres MAX7221
;
Ini3max:
movlw 0x0C ; Shutdown mode
movwf Sortida+1 ; Ho prepara per enviar-ho
movwf Sortida+3 ; Ho prepara per enviar-ho
movwf Sortida+5 ; Ho prepara per enviar-ho
movlw 0x00 ; Desactivat
movwf Sortida ; Ho prepara per enviar-ho
movwf Sortida+2 ; Ho prepara per enviar-ho
movwf Sortida+4 ; Ho prepara per enviar-ho
call Envia_max ; Ho envia al MAX7221
movlw 0x09 ; Decode mode
movwf Sortida+1 ; Ho prepara per enviar-ho
movwf Sortida+3 ; Ho prepara per enviar-ho
movwf Sortida+5 ; Ho prepara per enviar-ho
movlw 0x00 ; No decode
movwf Sortida ; Ho prepara per enviar-ho
movwf Sortida+2 ; Ho prepara per enviar-ho
movwf Sortida+4 ; Ho prepara per enviar-ho
call Envia_max ; Ho envia al MAX7221
movlw 0x0B ; Scan limit
movwf Sortida+1 ; Ho prepara per enviar-ho
movwf Sortida+3 ; Ho prepara per enviar-ho
movwf Sortida+5 ; Ho prepara per enviar-ho
movlw 0x07 ; Vuit fileres
movwf Sortida ; Ho prepara per enviar-ho
movwf Sortida+2 ; Ho prepara per enviar-ho
movwf Sortida+4 ; Ho prepara per enviar-ho
call Envia_max ; Ho envia al MAX7221
return
;
; Envia dades (48 bits) a tres MAX7221
; desactivant les interrupcions
;
Envia3max:
bcf T0IE ; Desactiva les interrupcions momentàniament
call Envia_max
bsf T0IE ; Reactiva les interrupcions a l'acabar
return
;
; Envia dades (48 bits) a tres MAX7221
;
; Els bits estan a les variables:
; Sortida Valor vermells
; Sortida+1 Adreça vermells
; Sortida+2 Valor verds
; Sortida+3 Adreça verds
; Sortida+4 Valor blaus
; Sortida+5 Adreça blaus
; Al final de la funció, el valor de Sortida queda corromput
; Si es vol conservar, cal copiar-lo a una altra variable
;
; Aquesta funció dura, aproximadament, 1 ms
Envia_max:
bcf Port,5 ; S'assegura que Clock està desactivat
bcf Port,6 ; S'assegura que Latch està desactivat
movf Port,w ; Agafa el valor de Port
movwf PORTB ; I el posa al port B
movlw 48 ; Número de bits a enviar
movwf Compta ; Variable per comptar els bits
Bucle3max:
bcf Port,4 ; Desactiva Data. Si toca activar-ho, ja ho farem
rlf Sortida,f ; Fa sortir el bit de més a l'esquerra cap a C
rlf Sortida+1,f ; i roda els altres a l'esquerra
rlf Sortida+2,f
rlf Sortida+3,f
rlf Sortida+4,f
rlf Sortida+5,f
btfsc CARRY ; Mira si el bit de l'esquerra era un 1
bsf Port,4 ; Si era 1, activa Data
movf Port,w ; Agafa el valor de Port. El valor que ha canviat és Data
movwf PORTB ; I el posa al port B
bsf Port,5 ; Activa Clock, forçant a llegir el bit
movf Port,w ; Agafa el valor de Port. El valor que ha canviat és Clock
movwf PORTB ; I el posa al port B
bcf Port,5 ; Desactiva Clock
movf Port,w ; Agafa el valor de Port. El valor que ha canviat és Clock
movwf PORTB ; I el posa al port B
decfsz Compta,f ; Decrementa Compta
goto Bucle3max ; Si Compta no és zero, repeteix el bucle
bsf Port,6 ; Torna a activar Latch
; Els valors es copiaran a la sortida del registre
movf Port,w ; Agafa el valor de Port. El valor que ha canviat és Latch
movwf PORTB ; I el posa al port B
return
;
; Funció de retard de 0,771 W ms
;
Retms:
movwf Retard2
Buclems:
decfsz Retard1,f
goto Buclems
decfsz Retard2,f
goto Buclems
return
END main

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