Programació en mpasm del PIC 16F690

Referència Trucs Perifèrics   Recursos CITCEA
Tutorial Exemples Projectes   Inici

Exemple DM - Dibuixem sobre la matriu de LED (un sol color)

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.

#include <p16F690.inc>
	__config (_INTRC_OSC_NOCLKOUT&_WDT_OFF&_PWRTE_OFF&_MCLRE_OFF&_CP_OFF&_BOR_OFF&_IESO_OFF&_FCMEN_OFF)
	cblock 0x20
Port			; Bits a enviar al port B
Sortida:6		; Valors a enviar al MAX7221 (48 bits)
Compta			; Variable per comptar els bits a Envia_max
Compt			; Variable per comptar els bytes
Comp			; Variable per comptar els bits
Filera			; Variable per comptar fileres
Actiu			; Variable que diu quin color està actiu
			; Actiu = 0		Apagat
			; Actiu = 1		Vermell
			; Actiu = 2		Verd
			; Actiu = 3		Blau
Polsador		; Variable que conté un bit per a cada polsador per saber si està premut	
x			; Coordenada X del cursor (0 a 7)
			; X = 0 és la columna de la dreta
y			; Coordenada Y del cursor (0 a 7)
caux			; Comptador auxiliar
mirar			; Espera que es deixi anar el polsador
mascara			; Màscara per a les operacions amb bits
Retard1			; Variables per als cicles de retard
Retard2
	endc
	cblock 0x70	; Zona de memòria de dades que no depèn del banc triat
W_Copia			; Guardarà el contingut de W durant la interrupció
ST_Copia		; Guardarà STATUS durant la interrupció 
	endc
	cblock 0xA0	; Zona de memòria de dades del banc 1
figura:8		; Aquí guardarem el dibuix (8 fileres)
	endc
	org 0
	goto	Inici		; Saltem al lloc on hi ha el programa principal
	nop			; Zona de memòria de programa que no utilitzem
	nop
	nop
Interrup
	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	INTCON,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	INTCON,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	b'00000011'	; Descarta els bits que no serveixen
	andwf	Actiu,f
	btfsc	STATUS,Z
	goto	NoZero		; Si Actiu val 0 no ho canvia
	decf	Actiu,f		; Passem a activar un altre color
	btfss	STATUS,Z	; 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	b'00000011'	; Descarta els bits que no serveixen
	andwf	Actiu,f
	btfsc	STATUS,Z	; Salta si el resultat no és zero
	goto	Apagat		; Si està apagat ho desactiva tot
	movlw	.1
	xorwf	Actiu,w
	btfsc	STATUS,Z
	goto	Vermell		; Si val 1, activem el vermell
	movlw	.2
	xorwf	Actiu,w
	btfsc	STATUS,Z
	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	STATUS,RP0	; Tria el banc 1
	movlw	b'10000101'	; 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	b'00010000'
	movwf	ADCON1		; Posa el conversor a 1/8 de la freqüència
	bcf	STATUS,RP0
	bsf	STATUS,RP1	; Tria el banc 2
	movlw	b'00000101'
	movwf	ANSEL		; Configura AN0 i AN2 com entrada analògica
	bcf	STATUS,RP0
	bcf	STATUS,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	b'00001001'
	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	b'10100000'	; 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	STATUS,Z	; Si és zero no s'han de mirar
	goto	NoMirar		; Anem a veure si ja s'ha deixat anar
	movf	Polsador,w
	xorlw	b'00000001'	; Mirem si s'ha premut el polsador 1
	btfss	STATUS,Z	; Si és l'1, salta
	goto	NoPol1		; No és l'1
				; S'ha premut el polsador 1
	incf	x,f		; Incrementem x del cursor
	movlw	b'00000111'	; Valor 7
	andwf	x,f		; Limitem x entre 0 i 7
	goto	Zmirar		; Ja estem del polsador 1
NoPol1
	movf	Polsador,w
	xorlw	b'00000010'	; Mirem si s'ha premut el polsador 2
	btfss	STATUS,Z	; Si és el 2, salta
	goto	NoPol2		; No és el 2
				; S'ha premut el polsador 2
	incf	y,f		; Incrementem y del cursor
	movlw	b'00000111'	; Valor 7
	andwf	y,f		; Limitem x entre 0 i 7
	goto	Zmirar		; Ja estem del polsador 2
NoPol2
	movf	Polsador,w
	xorlw	b'00000100'	; Mirem si s'ha premut el polsador 3
	btfss	STATUS,Z	; Si és el 3, salta
	goto	NoPol3		; No és el 3
				; S'ha premut el polsador 3
	movlw	b'00000001'	; Posem un 1 a la columna 0
	movwf	mascara		; Ho guardem com a màscara
	movf	x,w		; Agafem la x del cursor
	btfsc	STATUS,Z	; Mirem si és zero
	goto	xZero		; Si és zero no cal fer res
	movwf	Comp		; Hem de rodar els bits x posicions
rodaX
	bcf	STATUS,C	; 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
NoPol3
	movf	Polsador,w
	xorlw	b'00001000'	; Mirem si s'ha premut el polsador 4
	btfss	STATUS,Z	; Si és el 4, salta
	goto	NoPol4		; No és el 4
				; S'ha premut el polsador 4
				; El polsador 4 no fa res
	goto	Zmirar		; Ja estem del polsador 4
NoPol4
	movf	Polsador,w
	xorlw	b'00010000'	; Mirem si s'ha premut el polsador 5
	btfss	STATUS,Z	; Si és el 5, salta
	goto	NoPol5		; 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
NoPol5
	goto	Matriu		; Envia la figura actual a la matriu
NoMirar
	movf	Polsador,w	; Agafem la lectura dels polsadors
	btfss	STATUS,Z	; 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	STATUS,Z	; Si és zero, són iguals
	goto	noCur		; No és la filera del cursor
	movlw	b'00000001'	; Posem un 1 a la columna 0
	movwf	mascara		; Ho guardem com a màscara
	movf	x,w		; Agafem la x del cursor
	btfsc	STATUS,Z	; Mirem si és zero
	goto	xnul		; Si és zero no cal fer res
	movwf	Comp		; Hem de rodar els bits x posicions
giraX
	bcf	STATUS,C	; 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	ADCON0,GO	; Inicia la conversió
	btfsc	ADCON0,GO	; 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	STATUS,C	; C = 1 si ADRESH >= W
	goto	NoP1		; ADRESH >= W
	movlw	.200		; Límit inferior de P1
	subwf	ADRESH,w	; W = ADRESH - W
	btfss	STATUS,C	; C = 1 si ADRESH >= W
	goto	NoP1		; ADRESH < W
	movlw	b'00000001'	; Polsador P1
	movwf	Polsador	; Ho copia a Polsador
	goto	NoP5
NoP1				; Comparació P2
	movlw	.194		; Límit superior de P2
	subwf	ADRESH,w	; W = ADRESH - W
	btfsc	STATUS,C	; C = 1 si ADRESH >= W
	goto	NoP2		; ADRESH >= W
	movlw	.174		; Límit inferior de P2
	subwf	ADRESH,w	; W = ADRESH - W
	btfss	STATUS,C	; C = 1 si ADRESH >= W
	goto	NoP2		; ADRESH < W
	movlw	b'00000010'	; Polsador P2
	movwf	Polsador	; Ho copia a Polsador
	goto	NoP5
NoP2				; Comparació P3
	movlw	.163		; Límit superior de P3
	subwf	ADRESH,w	; W = ADRESH - W
	btfsc	STATUS,C	; C = 1 si ADRESH >= W
	goto	NoP3		; ADRESH >= W
	movlw	.143		; Límit inferior de P3
	subwf	ADRESH,w	; W = ADRESH - W
	btfss	STATUS,C	; C = 1 si ADRESH >= W
	goto	NoP3		; ADRESH < W
	movlw	b'00000100'	; Polsador P3
	movwf	Polsador	; Ho copia a Polsador
	goto	NoP5
NoP3				; Comparació P4
	movlw	.90		; Límit superior de P4
	subwf	ADRESH,w	; W = ADRESH - W
	btfsc	STATUS,C	; C = 1 si ADRESH >= W
	goto	NoP4		; ADRESH >= W
	movlw	.70		; Límit inferior de P4
	subwf	ADRESH,w	; W = ADRESH - W
	btfss	STATUS,C	; C = 1 si ADRESH >= W
	goto	NoP4		; ADRESH < W
	movlw	b'00001000'	; Polsador P4
	movwf	Polsador	; Ho copia a Polsador
	goto	NoP5
NoP4				; Comparació P5
	movlw	.55		; Límit superior de P5
	subwf	ADRESH,w	; W = ADRESH - W
	btfsc	STATUS,C	; C = 1 si ADRESH >= W
	goto	NoP5		; ADRESH >= W
	movlw	.35		; Límit inferior de P5
	subwf	ADRESH,w	; W = ADRESH - W
	btfss	STATUS,C	; C = 1 si ADRESH >= W
	goto	NoP5		; ADRESH < W
	movlw	b'00010000'	; Polsador P5
	movwf	Polsador	; Ho copia a Polsador
NoP5
	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	b'00000000'	; 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	INTCON,T0IE	; Desactiva les interrupcions momentàniament
	call	Envia_max
	bsf	INTCON,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	STATUS,C	; 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

La següent versió del programa és molt similar però mostra el cursor intermitent. Per fer-ho, decrementa el 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.

#include <p16F690.inc>
	__config (_INTRC_OSC_NOCLKOUT&_WDT_OFF&_PWRTE_OFF&_MCLRE_OFF&_CP_OFF&_BOR_OFF&_IESO_OFF&_FCMEN_OFF)
#define cic_int  .35	; Nombre de cicles per a la intermitència
	cblock 0x20
Port			; Bits a enviar al port B
Sortida:6		; Valors a enviar al MAX7221 (48 bits)
Compta			; Variable per comptar els bits a Envia_max
Compt			; Variable per comptar els bytes
Comp			; Variable per comptar els bits
Filera			; Variable per comptar fileres
Actiu			; Variable que diu quin color està actiu
			; Actiu = 0		Apagat
			; Actiu = 1		Vermell
			; Actiu = 2		Verd
			; Actiu = 3		Blau
Polsador		; Variable que conté un bit per a cada polsador per saber si està premut	
x			; Coordenada X del cursor (0 a 7)
			; X = 0 és la columna de la dreta
y			; Coordenada Y del cursor (0 a 7)
caux			; Comptador auxiliar
mirar			; Espera que es deixi anar el polsador
mascara			; Màscara per a les operacions amb bits
compt_int		; Comptador de cicles per a la intermitència
cur_on			; Controla l'estat del cursor
Retard1			; Variables per als cicles de retard
Retard2
	endc
	cblock 0x70	; Zona de memòria de dades que no depèn del banc triat
W_Copia			; Guardarà el contingut de W durant la interrupció
ST_Copia		; Guardarà STATUS durant la interrupció 
	endc
	cblock 0xA0	; Zona de memòria de dades del banc 1
figura:8		; Aquí guardarem el dibuix (8 fileres)
	endc
	org 0
	goto	Inici		; Saltem al lloc on hi ha el programa principal
	nop			; Zona de memòria de programa que no utilitzem
	nop
	nop
Interrup
	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	INTCON,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	INTCON,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	b'00000011'	; Descarta els bits que no serveixen
	andwf	Actiu,f
	btfsc	STATUS,Z
	goto	NoZero		; Si Actiu val 0 no ho canvia
	decf	Actiu,f		; Passem a activar un altre color
	btfss	STATUS,Z	; 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	b'00000011'	; Descarta els bits que no serveixen
	andwf	Actiu,f
	btfsc	STATUS,Z	; Salta si el resultat no és zero
	goto	Apagat		; Si està apagat ho desactiva tot
	movlw	.1
	xorwf	Actiu,w
	btfsc	STATUS,Z
	goto	Vermell		; Si val 1, activem el vermell
	movlw	.2
	xorwf	Actiu,w
	btfsc	STATUS,Z
	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	STATUS,RP0	; Tria el banc 1
	movlw	b'10000101'	; 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	b'00010000'
	movwf	ADCON1		; Posa el conversor a 1/8 de la freqüència
	bcf	STATUS,RP0
	bsf	STATUS,RP1	; Tria el banc 2
	movlw	b'00000101'
	movwf	ANSEL		; Configura AN0 i AN2 com entrada analògica
	bcf	STATUS,RP0
	bcf	STATUS,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	b'00001001'
	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	b'10100000'	; 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	STATUS,Z	; Si és zero no s'han de mirar
	goto	NoMirar		; Anem a veure si ja s'ha deixat anar
	movf	Polsador,w
	xorlw	b'00000001'	; Mirem si s'ha premut el polsador 1
	btfss	STATUS,Z	; Si és l'1, salta
	goto	NoPol1		; No és l'1
				; S'ha premut el polsador 1
	incf	x,f		; Incrementem x del cursor
	movlw	b'00000111'	; Valor 7
	andwf	x,f		; Limitem x entre 0 i 7
	goto	Zmirar		; Ja estem del polsador 1
NoPol1
	movf	Polsador,w
	xorlw	b'00000010'	; Mirem si s'ha premut el polsador 2
	btfss	STATUS,Z	; Si és el 2, salta
	goto	NoPol2		; No és el 2
				; S'ha premut el polsador 2
	incf	y,f		; Incrementem y del cursor
	movlw	b'00000111'	; Valor 7
	andwf	y,f		; Limitem x entre 0 i 7
	goto	Zmirar		; Ja estem del polsador 2
NoPol2
	movf	Polsador,w
	xorlw	b'00000100'	; Mirem si s'ha premut el polsador 3
	btfss	STATUS,Z	; Si és el 3, salta
	goto	NoPol3		; No és el 3
				; S'ha premut el polsador 3
	movlw	b'00000001'	; Posem un 1 a la columna 0
	movwf	mascara		; Ho guardem com a màscara
	movf	x,w		; Agafem la x del cursor
	btfsc	STATUS,Z	; Mirem si és zero
	goto	xZero		; Si és zero no cal fer res
	movwf	Comp		; Hem de rodar els bits x posicions
rodaX
	bcf	STATUS,C	; 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
NoPol3
	movf	Polsador,w
	xorlw	b'00001000'	; Mirem si s'ha premut el polsador 4
	btfss	STATUS,Z	; Si és el 4, salta
	goto	NoPol4		; No és el 4
				; S'ha premut el polsador 4
				; El polsador 4 no fa res
	goto	Zmirar		; Ja estem del polsador 4
NoPol4
	movf	Polsador,w
	xorlw	b'00010000'	; Mirem si s'ha premut el polsador 5
	btfss	STATUS,Z	; Si és el 5, salta
	goto	NoPol5		; 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
NoPol5
	goto	Matriu		; Envia la figura actual a la matriu
NoMirar
	movf	Polsador,w	; Agafem la lectura dels polsadors
	btfss	STATUS,Z	; 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	STATUS,Z	; 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	STATUS,Z	; Si és zero, són iguals
	goto	noCur		; No és la filera del cursor
	movlw	b'00000001'	; Posem un 1 a la columna 0
	movwf	mascara		; Ho guardem com a màscara
	movf	x,w		; Agafem la x del cursor
	btfsc	STATUS,Z	; Mirem si és zero
	goto	xnul		; Si és zero no cal fer res
	movwf	Comp		; Hem de rodar els bits x posicions
giraX
	bcf	STATUS,C	; 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	b'00000001'	; 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	ADCON0,GO	; Inicia la conversió
	btfsc	ADCON0,GO	; 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	STATUS,C	; C = 1 si ADRESH >= W
	goto	NoP1		; ADRESH >= W
	movlw	.200		; Límit inferior de P1
	subwf	ADRESH,w	; W = ADRESH - W
	btfss	STATUS,C	; C = 1 si ADRESH >= W
	goto	NoP1		; ADRESH < W
	movlw	b'00000001'	; Polsador P1
	movwf	Polsador	; Ho copia a Polsador
	goto	NoP5
NoP1				; Comparació P2
	movlw	.194		; Límit superior de P2
	subwf	ADRESH,w	; W = ADRESH - W
	btfsc	STATUS,C	; C = 1 si ADRESH >= W
	goto	NoP2		; ADRESH >= W
	movlw	.174		; Límit inferior de P2
	subwf	ADRESH,w	; W = ADRESH - W
	btfss	STATUS,C	; C = 1 si ADRESH >= W
	goto	NoP2		; ADRESH < W
	movlw	b'00000010'	; Polsador P2
	movwf	Polsador	; Ho copia a Polsador
	goto	NoP5
NoP2				; Comparació P3
	movlw	.163		; Límit superior de P3
	subwf	ADRESH,w	; W = ADRESH - W
	btfsc	STATUS,C	; C = 1 si ADRESH >= W
	goto	NoP3		; ADRESH >= W
	movlw	.143		; Límit inferior de P3
	subwf	ADRESH,w	; W = ADRESH - W
	btfss	STATUS,C	; C = 1 si ADRESH >= W
	goto	NoP3		; ADRESH < W
	movlw	b'00000100'	; Polsador P3
	movwf	Polsador	; Ho copia a Polsador
	goto	NoP5
NoP3				; Comparació P4
	movlw	.90		; Límit superior de P4
	subwf	ADRESH,w	; W = ADRESH - W
	btfsc	STATUS,C	; C = 1 si ADRESH >= W
	goto	NoP4		; ADRESH >= W
	movlw	.70		; Límit inferior de P4
	subwf	ADRESH,w	; W = ADRESH - W
	btfss	STATUS,C	; C = 1 si ADRESH >= W
	goto	NoP4		; ADRESH < W
	movlw	b'00001000'	; Polsador P4
	movwf	Polsador	; Ho copia a Polsador
	goto	NoP5
NoP4				; Comparació P5
	movlw	.55		; Límit superior de P5
	subwf	ADRESH,w	; W = ADRESH - W
	btfsc	STATUS,C	; C = 1 si ADRESH >= W
	goto	NoP5		; ADRESH >= W
	movlw	.35		; Límit inferior de P5
	subwf	ADRESH,w	; W = ADRESH - W
	btfss	STATUS,C	; C = 1 si ADRESH >= W
	goto	NoP5		; ADRESH < W
	movlw	b'00010000'	; Polsador P5
	movwf	Polsador	; Ho copia a Polsador
NoP5
	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	b'00000000'	; 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	INTCON,T0IE	; Desactiva les interrupcions momentàniament
	call	Envia_max
	bsf	INTCON,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	STATUS,C	; 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

 

 

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