Programació en C 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

#pragma config FOSC = INTRCIO, WDTE = OFF, PWRTE = OFF, MCLRE = OFF, CP = OFF
#pragma config CPD = OFF, BOREN = OFF, IESO = OFF, FCMEN = OFF
#include <xc.h>					// Carrega el fitxer de funcions necessari per al compilador XC8
#define _XTAL_FREQ  4000000			// La freqüència del rellotge és 4 MHz
char Port;					// Gestió del port a la funció Envia_max
char Compta;					// Comptador de bits a la funció Envia_max
char Sortida[6];				// Valors a enviar al MAX7221 (48 bits)
char Sorti[6];					// Valors a enviar al MAX7221 des de la interrupció
char Actiu; 					// Variable que diu quin color està actiu
						// Actiu = 0		Apagat
						// Actiu = 1		Vermell
						// Actiu = 2		Verd
						// Actiu = 3		Blau
char Polsad;					// Polsador que s'ha premut
char figura[8];					// Aquí guardarem el dibuix (8 fileres)
char x = 0;					// Coordenada X del cursor (0 a 7)
						// X = 0 és la columna de la dreta
char y = 0;					// Coordenada Y del cursor (0 a 7)
char mirar = 1;					// Espera que es deixi anar el polsador
						// Definició de les funcions que farem servir 
void Envia3max(char Valor[]);			// Envia un joc de valors als tres MAX7221
						// desactivant interrupcions
void Envia_max(void);				// Envia un joc de valors als tres MAX7221
void Ini3max(void);				// Inicialitza els tres MAX7221
void Apaga(void);				// Apaga tots els LED
char Polsador(void);				// Funció de lectura dels polsadors
void main (void) {
	OPTION_REG = 0b10000101;       		// 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)
	TRISC = 0;				// Tot el port C és de sortida
	TRISB = 0;				// Tot el port B és de sortida
	TRISA = 0xFF;				// Tot el port A és d'entrada
	ANSEL = 0b00000101;			// Configura AN0 i AN2 com entrada analògica
	ANSELH = 0;				// Desactiva les altres entrades analògiques
	PORTC = 0;				// Inicialitza a 0 el port C
	PORTB = 0;				// Inicialitza a 0 el port B
	ADCON1 = 0b00010000;			// Posa el conversor a 1/8 de la freqüència
	ADCON0 = 0b00001001;			// Activa el conversor A/D connectat a AN2
						// amb el resultat justificat per l'esquerra
	Ini3max();				// Inicialitza els tres MAX7221
	Actiu = 1;				// Activa el color vermell
	TMR0 = 100;				// Presselecció de 100, que són 156 iteracions
						// Correspon a una interrupció cada 7,5 ms
	INTCON = 0b10100000;			// Activem GIE i T0IE
	Apaga();				// Apaga tots els LED
	for (signed char k = 0; k < 8; k++){
		figura[k] = 0;			// Comencem amb tots els LED apagats
	}
	while (1) {
		// 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
		Polsad = Polsador();		// Llegim els polsadors
		if (mirar == 1){
			if (Polsad == 1) {	// Si s'ha premut el polsador 1
				x = (x + 1) % 8;	// Incrementa x però la manté entre 0 i 7
				mirar = 0;
			}
			if (Polsad == 2) {	// Si s'ha premut el polsador 2
				y = (y + 1) % 8;	// Incrementa y però la manté entre 0 i 7
				mirar = 0;
			}
			if (Polsad == 3) {	// Si s'ha premut el polsador 3
						// Invertim el LED corresponent
				figura[y] = (char) (figura[y] ^ (1 << x));
				mirar = 0;
			}
			if (Polsad == 4) {	// Si s'ha premut el polsador 4
						// No fem res
				mirar = 0;
			}
			if (Polsad == 5) {	// Si s'ha premut el polsador 5
				for (signed char k = 0; k < 8; k++){
					figura[k] = 0;		// Esborrem la figura
				}
				mirar = 0;
			}
		} else {
			if (Polsad == 0) {	// Si no s'ha premut cap polsador (o dos a la vegada)
				mirar = 1;
			}
		}
		// Anem a mostrar la figura actual a la matriu de LED
		for (unsigned char k = 0; k < 8; k++){
			char mascara;
			Sortida[0] = 0;	// Vermells
			Sortida[2] = 0;	// Verds
			Sortida[4] = figura[k];	// Blaus
			// El cursor es mostra groc, independentment del punt
			if (y == k){		// Si estem a la filera del cursor
				mascara = (char) (1 << x);
				Sortida[0] = Sortida[0] | mascara;		// Encén vermell
				Sortida[2] = Sortida[2] | mascara;		// Encén verd
				Sortida[4] = Sortida[4] & ~mascara;		// Apaga blau
			}
			Sortida[1] = k+1;	// Filera
			Sortida[3] = k+1;
			Sortida[5] = k+1;
			Envia3max(Sortida);	// Ho envia al MAX7221
			__delay_ms(1);
		}
	}
}
void __interrupt() temporit(void){
	if (INTCONbits.T0IF) {			// Comprovem que hi ha interrupció per Timer 0
		TMR0 = 100;			// Preselecció de Timer0
		INTCONbits.T0IF = 0;		// Desactiva el bit que indica interrupció pel Timer0
		if (Actiu != 0) {		// Si la matriu no està apagada
			Actiu--;		// Passem a activar un altre color
			if (Actiu == 0) {	// Si hem arribat a zero
				Actiu = 3;	// Torna a posar el 3
			}
		}
						// D'entrada els desactivem els tres
		Sorti[0] = 0x00;		// Vermell
		Sorti[2] = 0x00;		// Verd
		Sorti[4] = 0x00;		// Blau
		if (Actiu == 1) {		// Si és vermell
			Sorti[0] = 0x01;	// Vermell activat
		}
		if (Actiu == 2) {		// Si és verd
			Sorti[2] = 0x01;	// Verd activat
		}
		if (Actiu == 3) {		// Si és blau
			Sorti[4] = 0x01;	// Blau activat
		}
		Sorti[1] = 0x0C;		// Shutdown mode
		Sorti[3] = 0x0C;		// Shutdown mode
		Sorti[5] = 0x0C;		// Shutdown mode
		Envia_max();		// Ho envia al MAX7221
	}
}
void Envia3max(char Valor[]) {			// Envia un joc de valors als tres MAX7221
	INTCONbits.T0IE = 0;			// Desactiva les interrupcions momentàniament
	char Port = 0;				// Variable on guardem l'estat del port B
	char Temp;				// Variable temporal
	for (signed char j = 5; j >= 0; j--){		// Hem d'enviar 6 bytes
		for (signed char k = 1; k < 9; k++){			// De 8 bits
			Temp = Valor[j] & 0b10000000;		// Agafa el bit de més a l'esquerra
								// Temp només podrà valer 0 o 128
			if (Temp == 0) {			// Si val 0
				Port = Port & 0b11101111;	// Desactiva Data (bit 4)
			} else {				// Si val 128
				Port = Port | 0b00010000;	// Activa Data (bit 4)
			}
			Valor[j] = (char) (Valor[j] << 1);	// Rodem els bits per situar el següent
			PORTB = Port;				// Ho posa al port B
			Port = Port | 0b00100000;		// Activa Clock (bit 5) i força lectura
			PORTB = Port;				// Ho posa al port B
			Port = Port & 0b11011111;		// Desactiva Clock (bit 5)
			PORTB = Port;				// Ho posa al port B
		}
	}
	Port = Port | 0b01000000;		// Activa Latch (bit 6) per copiar a les sortides
	PORTB = Port;				// Ho posa al port B
	INTCONbits.T0IE = 1;			// Reactiva les interrupcions a l'acabar
}
void Envia_max(void) {				// Envia un joc de valors als tres MAX7221
	asm("banksel _Port");
	asm("bcf (_Port&7fh),5");		// S'assegura que Clock està desactivat
	asm("bcf (_Port&7fh),6");		// S'assegura que Latch està desactivat
	asm("movf (_Port&7fh),w");		// Agafa el valor de Port
	asm("banksel PORTB");
	asm("movwf PORTB");			// I el posa al port B
	asm("banksel _Compta");
	asm("movlw 48");			// Número de bits a enviar
	asm("movwf (_Compta&7fh)");		// Variable per comptar els bits
	asm("Bucle:");
	asm("banksel _Port");
	asm("bcf (_Port&7fh),4");		// Desactiva Data. Si toca activar-ho, ja ho farem
	asm("banksel _Sorti");
	asm("rlf (_Sorti&7fh),f");		// Fa sortir el bit de més a l'esquerra cap a C
	asm("rlf ((_Sorti+1)&7fh),f");		// i roda els altres a l'esquerra
	asm("rlf ((_Sorti+2)&7fh),f");
	asm("rlf ((_Sorti+3)&7fh),f");
	asm("rlf ((_Sorti+4)&7fh),f");
	asm("rlf ((_Sorti+5)&7fh),f");
	asm("banksel _Port");
	asm("btfsc STATUS,0");			// Mira si el bit de l'esquerra era un 1
	asm("bsf (_Port&7fh),4");		// Si era 1, activa Data
	asm("movf (_Port&7fh),w");		// Agafa el valor de Port. El valor que ha canviat és Data
	asm("banksel PORTB");
	asm("movwf PORTB");			// I el posa al port B
	asm("banksel _Port");
	asm("bsf (_Port&7fh),5");		// Activa Clock, forçant a llegir el bit
	asm("movf (_Port&7fh),w");		// Agafa el valor de Port. El valor que ha canviat és Clock
	asm("banksel PORTB");
	asm("movwf PORTB");			// I el posa al port B
	asm("banksel _Port");
	asm("bcf (_Port&7fh),5");		// Desactiva Clock
	asm("movf (_Port&7fh),w");		// Agafa el valor de Port. El valor que ha canviat és Clock
	asm("banksel PORTB");
	asm("movwf PORTB");			// I el posa al port B
	asm("banksel _Compta");
	asm("decfsz (_Compta&7fh),f");		// Decrementa Compta
	asm("goto (Bucle&7ffh)");			// Si Compta no és zero, repeteix el bucle
	asm("banksel _Port");
	asm("bsf (_Port&7fh),6");		// Torna a activar Latch
						// Els valors es copiaran a la sortida del registre
	asm("movf (_Port&7fh),w");		// Agafa el valor de Port. El valor que ha canviat és Latch
	asm("banksel PORTB");
	asm("movwf PORTB");			// I el posa al port B
}
void Ini3max(void) {				// Inicialitza els tres MAX7221
	char Bytes[6];				// Els sis bytes que cal enviar
	Bytes[0] = 0x00;			// Desactivat
	Bytes[1] = 0x0C;			// Shutdown mode
	Bytes[2] = 0x00;
	Bytes[3] = 0x0C;
	Bytes[4] = 0x00;
	Bytes[5] = 0x0C;
	Envia3max(Bytes);			// Els envia
	Bytes[0] = 0x00;			// No decode
	Bytes[1] = 0x09;			// Decode mode
	Bytes[2] = 0x00;
	Bytes[3] = 0x09;
	Bytes[4] = 0x00;
	Bytes[5] = 0x09;
	Envia3max(Bytes);			// Els envia
	Bytes[0] = 0x07;			// Vuit fileres
	Bytes[1] = 0x0B;			// Scan limit
	Bytes[2] = 0x07;
	Bytes[3] = 0x0B;
	Bytes[4] = 0x07;
	Bytes[5] = 0x0B;
	Envia3max(Bytes);			// Els envia
}
void Apaga(void) {				// Apaga tots els LED
	char Bytes[6];				// Els sis bytes que cal enviar
	for (unsigned char j = 1; j <= 8; j++){		// Hem d'enviar 8 fileres
		Bytes[1] = j;			// Filera
		Bytes[3] = j;
		Bytes[5] = j;
		Bytes[0] = 0x00;		// Vermells
		Bytes[2] = 0x00;		// Verds
		Bytes[4] = 0x00;		// Blaus
		Envia3max(Bytes);		// Els envia
	}
}
char Polsador(void) {
	char Pols = 0;
	ADCON0bits.GO = 1;		// Posa en marxa el conversor
	while (ADCON0bits.GO == 1)	// Mentre no acabi
		;    			// ens esperem
	if (ADRESH < 220 && ADRESH > 200) {
		Pols = 1;		// Comprova polsador 1
	}
	if (ADRESH < 194 && ADRESH > 174) {
		Pols = 2;		// Comprova polsador 2
	}
	if (ADRESH < 163 && ADRESH > 143) {
		Pols = 3;		// Comprova polsador 3
	}
	if (ADRESH < 90 && ADRESH > 70) {
		Pols = 4;		// Comprova polsador 4
	}
	if (ADRESH < 55 && ADRESH > 35) {
		Pols = 5;		// Comprova polsador 5
	}
	return Pols;
}

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

#pragma config FOSC = INTRCIO, WDTE = OFF, PWRTE = OFF, MCLRE = OFF, CP = OFF
#pragma config CPD = OFF, BOREN = OFF, IESO = OFF, FCMEN = OFF
#include <xc.h>					// Carrega el fitxer de funcions necessari per al compilador XC8
#define _XTAL_FREQ  4000000			// La freqüència del rellotge és 4 MHz
#define cic_int  5				// Nombre de cicles per a la intermitència
char Port;					// Gestió del port a la funció Envia_max
char Compta;					// Comptador de bits a la funció Envia_max
char Sortida[6];				// Valors a enviar al MAX7221 (48 bits)
char Sorti[6];					// Valors a enviar al MAX7221 des de la interrupció
char Actiu; 					// Variable que diu quin color està actiu
						// Actiu = 0		Apagat
						// Actiu = 1		Vermell
						// Actiu = 2		Verd
						// Actiu = 3		Blau
char Polsad;					// Polsador que s'ha premut
char figura[8];
char x = 0;					// Coordenada X del cursor (0 a 7)
						// X = 0 és la columna de la dreta
char y = 0;					// Coordenada Y del cursor (0 a 7)
char mirar = 1;					// Espera que es deixi anar el polsador
char compt_int = 0;				// Comptador de cicles per a la intermitència
char cur_on = 1;				// Controla l'estat del cursor
						// Definició de les funcions que farem servir 
void Envia3max(char Valor[]);			// Envia un joc de valors als tres MAX7221
						// desactivant interrupcions
void Envia_max(void);				// Envia un joc de valors als tres MAX7221
void Ini3max(void);				// Inicialitza els tres MAX7221
void Apaga(void);				// Apaga tots els LED
char Polsador(void);				// Funció de lectura dels polsadors
void main (void) {
	OPTION_REG = 0b10000101;       		// 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)
	TRISC = 0;				// Tot el port C és de sortida
	TRISB = 0;				// Tot el port B és de sortida
	TRISA = 0xFF;				// Tot el port A és d'entrada
	ANSEL = 0b00000101;			// Configura AN0 i AN2 com entrada analògica
	ANSELH = 0;				// Desactiva les altres entrades analògiques
	PORTC = 0;				// Inicialitza a 0 el port C
	PORTB = 0;				// Inicialitza a 0 el port B
	ADCON1 = 0b00010000;			// Posa el conversor a 1/8 de la freqüència
	ADCON0 = 0b00001001;			// Activa el conversor A/D connectat a AN2
						// amb el resultat justificat per l'esquerra
	Ini3max();				// Inicialitza els tres MAX7221
	Actiu = 1;				// Activa el color vermell
	TMR0 = 100;				// Presselecció de 100, que són 156 iteracions
						// Correspon a una interrupció cada 7,5 ms
	INTCON = 0b10100000;			// Activem GIE i T0IE
	Apaga();				// Apaga tots els LED
	for (signed char k = 0; k < 8; k++){
		figura[k] = 0;			// Comencem amb tots els LED apagats
	}
	while (1) {
		// 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
		Polsad = Polsador();		// Llegim els polsadors
		if (mirar == 1){
			if (Polsad == 1) {	// Si s'ha premut el polsador 1
				x = (x + 1) % 8;	// Incrementa x però la manté entre 0 i 7
				mirar = 0;
			}
			if (Polsad == 2) {	// Si s'ha premut el polsador 2
				y = (y + 1) % 8;	// Incrementa y però la manté entre 0 i 7
				mirar = 0;
			}
			if (Polsad == 3) {	// Si s'ha premut el polsador 3
						// Invertim el LED corresponent
				figura[y] = (char) (figura[y] ^ (1 << x));
				mirar = 0;
			}
			if (Polsad == 4) {	// Si s'ha premut el polsador 4
						// No fem res
				mirar = 0;
			}
			if (Polsad == 5) {	// Si s'ha premut el polsador 5
				for (signed char k = 0; k < 8; k++){
					figura[k] = 0;		// Esborrem la figura
				}
				mirar = 0;
			}
		} else {
			if (Polsad == 0) {	// Si no s'ha premut cap polsador (o dos a la vegada)
				mirar = 1;
			}
		}
		// Anem a mostrar la figura actual a la matriu de LED
		for (signed char k = 0; k < 8; k++){
			Sortida[0] = 0;	// Vermells
			Sortida[2] = 0;	// Verds
			Sortida[4] = figura[k];	// Blaus
			// El cursor es mostra groc, independentment del punt
			if ((y == k) && (cur_on == 1)){		// Si estem a la filera del cursor
				Sortida[0] = (char) (Sortida[0] | (1 << x));		// Encén vermell
				Sortida[2] = (char) (Sortida[2] | (1 << x));		// Encén verd
				Sortida[4] = (char) (Sortida[4] & ~(1 << x));		// Apaga blau
			}
			Sortida[1] = (char) (k+1);	// Filera
			Sortida[3] = (char) (k+1);
			Sortida[5] = (char) (k+1);
			Envia3max(Sortida);	// Ho envia al MAX7221
			__delay_ms(1);
		}
		compt_int++;
		if (compt_int == cic_int){	// Si toca intermitència
			compt_int = 0;
			cur_on = (cur_on + 1) % 2;		// Canvia el cursor
		}
	}
}
void __interrupt() temporit(void){
	if (INTCONbits.T0IF) {			// Comprovem que hi ha interrupció per Timer 0
		TMR0 = 100;			// Preselecció de Timer0
		INTCONbits.T0IF = 0;		// Desactiva el bit que indica interrupció pel Timer0
		if (Actiu != 0) {		// Si la matriu no està apagada
			Actiu--;		// Passem a activar un altre color
			if (Actiu == 0) {	// Si hem arribat a zero
				Actiu = 3;	// Torna a posar el 3
			}
		}
						// D'entrada els desactivem els tres
		Sorti[0] = 0x00;		// Vermell
		Sorti[2] = 0x00;		// Verd
		Sorti[4] = 0x00;		// Blau
		if (Actiu == 1) {		// Si és vermell
			Sorti[0] = 0x01;	// Vermell activat
		}
		if (Actiu == 2) {		// Si és verd
			Sorti[2] = 0x01;	// Verd activat
		}
		if (Actiu == 3) {		// Si és blau
			Sorti[4] = 0x01;	// Blau activat
		}
		Sorti[1] = 0x0C;		// Shutdown mode
		Sorti[3] = 0x0C;		// Shutdown mode
		Sorti[5] = 0x0C;		// Shutdown mode
		Envia_max();		// Ho envia al MAX7221
	}
}
void Envia3max(char Valor[]) {			// Envia un joc de valors als tres MAX7221
	INTCONbits.T0IE = 0;			// Desactiva les interrupcions momentàniament
	char Port = 0;				// Variable on guardem l'estat del port B
	char Temp;				// Variable temporal
	for (signed char j = 5; j >= 0; j--){		// Hem d'enviar 6 bytes
		for (signed char k = 1; k < 9; k++){			// De 8 bits
			Temp = Valor[j] & 0b10000000;		// Agafa el bit de més a l'esquerra
								// Temp només podrà valer 0 o 128
			if (Temp == 0) {			// Si val 0
				Port = Port & 0b11101111;	// Desactiva Data (bit 4)
			} else {				// Si val 128
				Port = Port | 0b00010000;	// Activa Data (bit 4)
			}
			Valor[j] = (char) (Valor[j] << 1);	// Rodem els bits per situar el següent
			PORTB = Port;				// Ho posa al port B
			Port = Port | 0b00100000;		// Activa Clock (bit 5) i força lectura
			PORTB = Port;				// Ho posa al port B
			Port = Port & 0b11011111;		// Desactiva Clock (bit 5)
			PORTB = Port;				// Ho posa al port B
		}
	}
	Port = Port | 0b01000000;		// Activa Latch (bit 6) per copiar a les sortides
	PORTB = Port;				// Ho posa al port B
	INTCONbits.T0IE = 1;			// Reactiva les interrupcions a l'acabar
}
void Envia_max(void) {				// Envia un joc de valors als tres MAX7221
	asm("banksel _Port");
	asm("bcf (_Port&7fh),5");		// S'assegura que Clock està desactivat
	asm("bcf (_Port&7fh),6");		// S'assegura que Latch està desactivat
	asm("movf (_Port&7fh),w");		// Agafa el valor de Port
	asm("banksel PORTB");
	asm("movwf PORTB");			// I el posa al port B
	asm("banksel _Compta");
	asm("movlw 48");			// Número de bits a enviar
	asm("movwf (_Compta&7fh)");		// Variable per comptar els bits
	asm("Bucle:");
	asm("banksel _Port");
	asm("bcf (_Port&7fh),4");		// Desactiva Data. Si toca activar-ho, ja ho farem
	asm("banksel _Sorti");
	asm("rlf (_Sorti&7fh),f");		// Fa sortir el bit de més a l'esquerra cap a C
	asm("rlf ((_Sorti+1)&7fh),f");		// i roda els altres a l'esquerra
	asm("rlf ((_Sorti+2)&7fh),f");
	asm("rlf ((_Sorti+3)&7fh),f");
	asm("rlf ((_Sorti+4)&7fh),f");
	asm("rlf ((_Sorti+5)&7fh),f");
	asm("banksel _Port");
	asm("btfsc STATUS,0");			// Mira si el bit de l'esquerra era un 1
	asm("bsf (_Port&7fh),4");		// Si era 1, activa Data
	asm("movf (_Port&7fh),w");		// Agafa el valor de Port. El valor que ha canviat és Data
	asm("banksel PORTB");
	asm("movwf PORTB");			// I el posa al port B
	asm("banksel _Port");
	asm("bsf (_Port&7fh),5");		// Activa Clock, forçant a llegir el bit
	asm("movf (_Port&7fh),w");		// Agafa el valor de Port. El valor que ha canviat és Clock
	asm("banksel PORTB");
	asm("movwf PORTB");			// I el posa al port B
	asm("banksel _Port");
	asm("bcf (_Port&7fh),5");		// Desactiva Clock
	asm("movf (_Port&7fh),w");		// Agafa el valor de Port. El valor que ha canviat és Clock
	asm("banksel PORTB");
	asm("movwf PORTB");			// I el posa al port B
	asm("banksel _Compta");
	asm("decfsz (_Compta&7fh),f");		// Decrementa Compta
	asm("goto (Bucle&7ffh)");			// Si Compta no és zero, repeteix el bucle
	asm("banksel _Port");
	asm("bsf (_Port&7fh),6");		// Torna a activar Latch
						// Els valors es copiaran a la sortida del registre
	asm("movf (_Port&7fh),w");		// Agafa el valor de Port. El valor que ha canviat és Latch
	asm("banksel PORTB");
	asm("movwf PORTB");			// I el posa al port B
}
void Ini3max(void) {				// Inicialitza els tres MAX7221
	char Bytes[6];				// Els sis bytes que cal enviar
	Bytes[0] = 0x00;			// Desactivat
	Bytes[1] = 0x0C;			// Shutdown mode
	Bytes[2] = 0x00;
	Bytes[3] = 0x0C;
	Bytes[4] = 0x00;
	Bytes[5] = 0x0C;
	Envia3max(Bytes);			// Els envia
	Bytes[0] = 0x00;			// No decode
	Bytes[1] = 0x09;			// Decode mode
	Bytes[2] = 0x00;
	Bytes[3] = 0x09;
	Bytes[4] = 0x00;
	Bytes[5] = 0x09;
	Envia3max(Bytes);			// Els envia
	Bytes[0] = 0x07;			// Vuit fileres
	Bytes[1] = 0x0B;			// Scan limit
	Bytes[2] = 0x07;
	Bytes[3] = 0x0B;
	Bytes[4] = 0x07;
	Bytes[5] = 0x0B;
	Envia3max(Bytes);			// Els envia
}
void Apaga(void) {				// Apaga tots els LED
	char Bytes[6];				// Els sis bytes que cal enviar
	for (unsigned char j = 1; j <= 8; j++){		// Hem d'enviar 8 fileres
		Bytes[1] = j;			// Filera
		Bytes[3] = j;
		Bytes[5] = j;
		Bytes[0] = 0x00;		// Vermells
		Bytes[2] = 0x00;		// Verds
		Bytes[4] = 0x00;		// Blaus
		Envia3max(Bytes);		// Els envia
	}
}
char Polsador(void) {
	char Pols = 0;
	ADCON0bits.GO = 1;		// Posa en marxa el conversor
	while (ADCON0bits.GO == 1)	// Mentre no acabi
		;    			// ens esperem
	if (ADRESH < 220 && ADRESH > 200) {
		Pols = 1;		// Comprova polsador 1
	}
	if (ADRESH < 194 && ADRESH > 174) {
		Pols = 2;		// Comprova polsador 2
	}
	if (ADRESH < 163 && ADRESH > 143) {
		Pols = 3;		// Comprova polsador 3
	}
	if (ADRESH < 90 && ADRESH > 70) {
		Pols = 4;		// Comprova polsador 4
	}
	if (ADRESH < 55 && ADRESH > 35) {
		Pols = 5;		// Comprova polsador 5
	}
	return Pols;
}

Com ja s'ha comentat, podem implementar la funció Envia3max en assemblador. Aquest darrer programa quedaria així:

#pragma config FOSC = INTRCIO, WDTE = OFF, PWRTE = OFF, MCLRE = OFF, CP = OFF
#pragma config CPD = OFF, BOREN = OFF, IESO = OFF, FCMEN = OFF
#include <xc.h>					// Carrega el fitxer de funcions necessari per al compilador XC8
#define _XTAL_FREQ  4000000			// La freqüència del rellotge és 4 MHz
#define cic_int  5				// Nombre de cicles per a la intermitència
char Port;					// Gestió del port a la funció Envia_max
char Compta;					// Comptador de bits a la funció Envia_max
char Comptar;					// Comptador de bits a la funció Envia3max
char Sortida[6];				// Valors a enviar al MAX7221 (48 bits)
char Sorti[6];					// Valors a enviar al MAX7221 des de la interrupció
char Actiu; 					// Variable que diu quin color està actiu
						// Actiu = 0		Apagat
						// Actiu = 1		Vermell
						// Actiu = 2		Verd
						// Actiu = 3		Blau
char Polsad;					// Polsador que s'ha premut
char figura[8];
char x = 0;					// Coordenada X del cursor (0 a 7)
						// X = 0 és la columna de la dreta
char y = 0;					// Coordenada Y del cursor (0 a 7)
char mirar = 1;					// Espera que es deixi anar el polsador
char compt_int = 0;				// Comptador de cicles per a la intermitència
char cur_on = 1;				// Controla l'estat del cursor
						// Definició de les funcions que farem servir 
void Envia3max(void);			// Envia un joc de valors als tres MAX7221
						// desactivant interrupcions
void Envia_max(void);				// Envia un joc de valors als tres MAX7221
void Ini3max(void);				// Inicialitza els tres MAX7221
void Apaga(void);				// Apaga tots els LED
char Polsador(void);				// Funció de lectura dels polsadors
void main(void) {
	OPTION_REG = 0b10000101;       		// 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)
	TRISC = 0;				// Tot el port C és de sortida
	TRISB = 0;				// Tot el port B és de sortida
	TRISA = 0xFF;				// Tot el port A és d'entrada
	ANSEL = 0b00000101;			// Configura AN0 i AN2 com entrada analògica
	ANSELH = 0;				// Desactiva les altres entrades analògiques
	PORTC = 0;				// Inicialitza a 0 el port C
	PORTB = 0;				// Inicialitza a 0 el port B
	ADCON1 = 0b00010000;			// Posa el conversor a 1/8 de la freqüència
	ADCON0 = 0b00001001;			// Activa el conversor A/D connectat a AN2
						// amb el resultat justificat per l'esquerra
	Ini3max();				// Inicialitza els tres MAX7221
	Actiu = 1;				// Activa el color vermell
	TMR0 = 100;				// Presselecció de 100, que són 156 iteracions
						// Correspon a una interrupció cada 7,5 ms
	INTCON = 0b10100000;			// Activem GIE i T0IE
	Apaga();				// Apaga tots els LED
	for (signed char k = 0; k < 8; k++){
		figura[k] = 0;			// Comencem amb tots els LED apagats
	}
	while (1) {
		// 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
		Polsad = Polsador();		// Llegim els polsadors
		if (mirar == 1){
			if (Polsad == 1) {	// Si s'ha premut el polsador 1
				x = (x + 1) % 8;	// Incrementa x però la manté entre 0 i 7
				mirar = 0;
			}
			if (Polsad == 2) {	// Si s'ha premut el polsador 2
				y = (y + 1) % 8;	// Incrementa y però la manté entre 0 i 7
				mirar = 0;
			}
			if (Polsad == 3) {	// Si s'ha premut el polsador 3
						// Invertim el LED corresponent
				figura[y] = (char) (figura[y] ^ (1 << x));
				mirar = 0;
			}
			if (Polsad == 4) {	// Si s'ha premut el polsador 4
						// No fem res
				mirar = 0;
			}
			if (Polsad == 5) {	// Si s'ha premut el polsador 5
				for (signed char k = 0; k < 8; k++){
					figura[k] = 0;		// Esborrem la figura
				}
				mirar = 0;
			}
		} else {
			if (Polsad == 0) {	// Si no s'ha premut cap polsador (o dos a la vegada)
				mirar = 1;
			}
		}
		// Anem a mostrar la figura actual a la matriu de LED
		for (signed char k = 0; k < 8; k++){
			Sortida[0] = 0;	// Vermells
			Sortida[2] = 0;	// Verds
			Sortida[4] = figura[k];	// Blaus
			// El cursor es mostra groc, independentment del punt
			if ((y == k) && (cur_on == 1)){		// Si estem a la filera del cursor
				Sortida[0] = (char) (Sortida[0] | (1 << x));		// Encén vermell
				Sortida[2] = (char) (Sortida[2] | (1 << x));		// Encén verd
				Sortida[4] = (char) (Sortida[4] & ~(1 << x));		// Apaga blau
			}
			Sortida[1] = (char) (k+1);	// Filera
			Sortida[3] = (char) (k+1);
			Sortida[5] = (char) (k+1);
			Envia3max();	// Ho envia al MAX7221
			__delay_ms(1);
		}
		compt_int++;
		if (compt_int == cic_int){	// Si toca intermitència
			compt_int = 0;
			cur_on = (cur_on + 1) % 2;		// Canvia el cursor
		}
	}
}
void __interrupt() temporit(void){
	if (INTCONbits.T0IF) {			// Comprovem que hi ha interrupció per Timer 0
		TMR0 = 100;			// Preselecció de Timer0
		INTCONbits.T0IF = 0;		// Desactiva el bit que indica interrupció pel Timer0
		if (Actiu != 0) {		// Si la matriu no està apagada
			Actiu--;		// Passem a activar un altre color
			if (Actiu == 0) {	// Si hem arribat a zero
				Actiu = 3;	// Torna a posar el 3
			}
		}
						// D'entrada els desactivem els tres
		Sorti[0] = 0x00;		// Vermell
		Sorti[2] = 0x00;		// Verd
		Sorti[4] = 0x00;		// Blau
		if (Actiu == 1) {		// Si és vermell
			Sorti[0] = 0x01;	// Vermell activat
		}
		if (Actiu == 2) {		// Si és verd
			Sorti[2] = 0x01;	// Verd activat
		}
		if (Actiu == 3) {		// Si és blau
			Sorti[4] = 0x01;	// Blau activat
		}
		Sorti[1] = 0x0C;		// Shutdown mode
		Sorti[3] = 0x0C;		// Shutdown mode
		Sorti[5] = 0x0C;		// Shutdown mode
		Envia_max();		// Ho envia al MAX7221
	}
}
void Envia3max(void) {				// Envia un joc de valors als tres MAX7221
	asm("bcf INTCON,5");			// Desactiva les interrupcions momentàniament
	asm("banksel _Port");
	asm("bcf (_Port&7fh),5");		// S'assegura que Clock està desactivat
	asm("bcf (_Port&7fh),6");		// S'assegura que Latch està desactivat
	asm("movf (_Port&7fh),w");		// Agafa el valor de Port
	asm("banksel PORTB");
	asm("movwf PORTB");			// I el posa al port B
	asm("banksel _Comptar");
	asm("movlw 48");			// Número de bits a enviar
	asm("movwf (_Comptar&7fh)");		// Variable per comptar els bits
	asm("Bucles:");
	asm("banksel _Port");
	asm("bcf (_Port&7fh),4");		// Desactiva Data. Si toca activar-ho, ja ho farem
	asm("banksel _Sorti");
	asm("rlf (_Sortida&7fh),f");		// Fa sortir el bit de més a l'esquerra cap a C
	asm("rlf ((_Sortida+1)&7fh),f");	// i roda els altres a l'esquerra
	asm("rlf ((_Sortida+2)&7fh),f");
	asm("rlf ((_Sortida+3)&7fh),f");
	asm("rlf ((_Sortida+4)&7fh),f");
	asm("rlf ((_Sortida+5)&7fh),f");
	asm("banksel _Port");
	asm("btfsc STATUS,0");			// Mira si el bit de l'esquerra era un 1
	asm("bsf (_Port&7fh),4");		// Si era 1, activa Data
	asm("movf (_Port&7fh),w");		// Agafa el valor de Port. El valor que ha canviat és Data
	asm("banksel PORTB");
	asm("movwf PORTB");			// I el posa al port B
	asm("banksel _Port");
	asm("bsf (_Port&7fh),5");		// Activa Clock, forçant a llegir el bit
	asm("movf (_Port&7fh),w");		// Agafa el valor de Port. El valor que ha canviat és Clock
	asm("banksel PORTB");
	asm("movwf PORTB");			// I el posa al port B
	asm("banksel _Port");
	asm("bcf (_Port&7fh),5");		// Desactiva Clock
	asm("movf (_Port&7fh),w");		// Agafa el valor de Port. El valor que ha canviat és Clock
	asm("banksel PORTB");
	asm("movwf PORTB");			// I el posa al port B
	asm("banksel _Comptar");
	asm("decfsz (_Comptar&7fh),f");		// Decrementa Compta
	asm("goto (Bucles&7ffh)");		// Si Compta no és zero, repeteix el bucle
	asm("banksel _Port");
	asm("bsf (_Port&7fh),6");		// Torna a activar Latch
						// Els valors es copiaran a la sortida del registre
	asm("movf (_Port&7fh),w");		// Agafa el valor de Port. El valor que ha canviat és Latch
	asm("banksel PORTB");
	asm("movwf PORTB");			// I el posa al port B
	asm("bsf INTCON,5");			// Reactiva les interrupcions a l'acabar
}
void Envia_max(void) {				// Envia un joc de valors als tres MAX7221
	asm("banksel _Port");
	asm("bcf (_Port&7fh),5");		// S'assegura que Clock està desactivat
	asm("bcf (_Port&7fh),6");		// S'assegura que Latch està desactivat
	asm("movf (_Port&7fh),w");		// Agafa el valor de Port
	asm("banksel PORTB");
	asm("movwf PORTB");			// I el posa al port B
	asm("banksel _Compta");
	asm("movlw 48");			// Número de bits a enviar
	asm("movwf (_Compta&7fh)");		// Variable per comptar els bits
	asm("Bucle:");
	asm("banksel _Port");
	asm("bcf (_Port&7fh),4");		// Desactiva Data. Si toca activar-ho, ja ho farem
	asm("banksel _Sorti");
	asm("rlf (_Sorti&7fh),f");		// Fa sortir el bit de més a l'esquerra cap a C
	asm("rlf ((_Sorti+1)&7fh),f");		// i roda els altres a l'esquerra
	asm("rlf ((_Sorti+2)&7fh),f");
	asm("rlf ((_Sorti+3)&7fh),f");
	asm("rlf ((_Sorti+4)&7fh),f");
	asm("rlf ((_Sorti+5)&7fh),f");
	asm("banksel _Port");
	asm("btfsc STATUS,0");			// Mira si el bit de l'esquerra era un 1
	asm("bsf (_Port&7fh),4");		// Si era 1, activa Data
	asm("movf (_Port&7fh),w");		// Agafa el valor de Port. El valor que ha canviat és Data
	asm("banksel PORTB");
	asm("movwf PORTB");			// I el posa al port B
	asm("banksel _Port");
	asm("bsf (_Port&7fh),5");		// Activa Clock, forçant a llegir el bit
	asm("movf (_Port&7fh),w");		// Agafa el valor de Port. El valor que ha canviat és Clock
	asm("banksel PORTB");
	asm("movwf PORTB");			// I el posa al port B
	asm("banksel _Port");
	asm("bcf (_Port&7fh),5");		// Desactiva Clock
	asm("movf (_Port&7fh),w");		// Agafa el valor de Port. El valor que ha canviat és Clock
	asm("banksel PORTB");
	asm("movwf PORTB");			// I el posa al port B
	asm("banksel _Compta");
	asm("decfsz (_Compta&7fh),f");		// Decrementa Compta
	asm("goto (Bucle&7ffh)");			// Si Compta no és zero, repeteix el bucle
	asm("banksel _Port");
	asm("bsf (_Port&7fh),6");		// Torna a activar Latch
						// Els valors es copiaran a la sortida del registre
	asm("movf (_Port&7fh),w");		// Agafa el valor de Port. El valor que ha canviat és Latch
	asm("banksel PORTB");
	asm("movwf PORTB");			// I el posa al port B
}
void Ini3max(void) {				// Inicialitza els tres MAX7221
	Sortida[0] = 0x00;			// Desactivat
	Sortida[1] = 0x0C;			// Shutdown mode
	Sortida[2] = 0x00;
	Sortida[3] = 0x0C;
	Sortida[4] = 0x00;
	Sortida[5] = 0x0C;
	Envia3max();				// Els envia
	Sortida[0] = 0x00;			// No decode
	Sortida[1] = 0x09;			// Decode mode
	Sortida[2] = 0x00;
	Sortida[3] = 0x09;
	Sortida[4] = 0x00;
	Sortida[5] = 0x09;
	Envia3max();				// Els envia
	Sortida[0] = 0x07;			// Vuit fileres
	Sortida[1] = 0x0B;			// Scan limit
	Sortida[2] = 0x07;
	Sortida[3] = 0x0B;
	Sortida[4] = 0x07;
	Sortida[5] = 0x0B;
	Envia3max();				// Els envia
}
void Apaga(void) {				// Apaga tots els LED
	for (unsigned char j = 1; j <= 8; j++){		// Hem d'enviar 8 fileres
		Sortida[1] = j;			// Filera
		Sortida[3] = j;
		Sortida[5] = j;
		Sortida[0] = 0x00;		// Vermells
		Sortida[2] = 0x00;		// Verds
		Sortida[4] = 0x00;		// Blaus
		Envia3max();			// Els envia
	}
}
char Polsador(void) {
	char Pols = 0;
	ADCON0bits.GO = 1;		// Posa en marxa el conversor
	while (ADCON0bits.GO == 1)	// Mentre no acabi
		;    			// ens esperem
	if (ADRESH < 220 && ADRESH > 200) {
		Pols = 1;		// Comprova polsador 1
	}
	if (ADRESH < 194 && ADRESH > 174) {
		Pols = 2;		// Comprova polsador 2
	}
	if (ADRESH < 163 && ADRESH > 143) {
		Pols = 3;		// Comprova polsador 3
	}
	if (ADRESH < 90 && ADRESH > 70) {
		Pols = 4;		// Comprova polsador 4
	}
	if (ADRESH < 55 && ADRESH > 35) {
		Pols = 5;		// Comprova polsador 5
	}
	return Pols;
}

 

 

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