Programació en C del PIC 16F690

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

Exemple MS - Text en moviment a la matriu de LED

En aquest exemple farem aparèixer un conjunt de caràcters que es desplacen d'esquerra a dreta de la matriu. En aquest cas concret són les xifres del 0 al 4, però podria ser qualsevol caràcter. Les xifres s'han posat desordenades (0, 2, 1 i 3) per indicar que es poden posar en qualsevol ordre; també es podien repetir. Cal que cada caràcter estigui definit; per fer-ho senzill i compacte guardem les definicions dels caràcters a la memòria de programa, com en un dels programes de l'exemple ML. Cada caràcter s'ha creat amb una matriu de 7 ⨯ 5 punts però el definim amb vuit fileres perquè així és més fàcil multiplicar per vuit, que és el que necessitem per trobar el caràcter que ens cal a cada moment.

El programa treballa amb dos caràcters a la vegada, un que es mostra a la part esquerra de la matriu i un altre que es mostra a la part dreta. A mesura que es va desplaçant, es mostren menys píxels del caràcter de l'esquerra i més del de la dreta. Hem optat per iniciar i acabar la seqüència amb la matriu apagada, per això s'ha definit un bucle amb una posició més. A cada iteració del bucle s'agafa un caràcter per al costat esquerra de la matriu (buit en la primera iteració) i un per al costat dret (buit en la darrera iteració).

Per definir els caràcters ens hem basat en la definició que hi ha a la pàgina 17 del full de característiques de la pantalla sèrie i ho hem fet emprant aquest full de càlcul, que ja ens genera la línia completa per posar al programa.

També hem implementat la possibilitat de triar el color. La funció EnviaMat mira el paràmetre Color i, segons el seu valor, fa sortir els caràcters en el color triat. El bucle del programa reprodueix el text amb cada un dels set colors possibles i després torna a començar, però es podria triar un sol color. Els valors que corresponen a cada color són els de la taula següent:

Valor de Color Color que li correspon
Decimal Binari
7 111 Blanc
6 110 Groc
5 101 Magenta
4 100 Vermell
3 011 Cian
2 010 Verd
1 001 Blau
0 000 Apagat

Podem observar que cada un dels tres bits menys significatius correspon a un dels tres colors primaris (vermell, verd i blau), i això fa molt més fàcil comprovar quins dels colors s'han d'activar.

#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 testbit(var, bit) ((var) & (1 <<(bit)))
#define inici 0xF00				// Adreça on es guarden els dibuixos
#define numcar 4				// Nombre de caràcters a enviar
#define blanc 99				// Valor que representa un blanc
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ó
unsigned short adressa;				// Variable de 16 bits per a l'adreça
unsigned char text[numcar] = {0, 2, 1, 3};	// Caràcters que volem mostrar
unsigned char color;				// Color dels caràcters
char Actiu; 					// Variable que diu quin color està actiu
						// Actiu = 0		Apagat
						// Actiu = 1		Vermell
						// Actiu = 2		Verd
						// Actiu = 3		Blau
const unsigned char zero[8] __at(inici) = {0b00011100, 0b00100010, 0b00100110, 0b00101010,
	0b00110010, 0b00100010, 0b00011100, 0b00000000};
const unsigned char u[8] __at(inici+8) = {0b00001000, 0b00011000, 0b00001000, 0b00001000,
	0b00001000, 0b00001000, 0b00011100, 0b00000000}; 
const unsigned char dos[8] __at(inici+16) = {0b00011100, 0b00100010, 0b00000010, 0b00000100,
	0b00001000, 0b00010000, 0b00111110, 0b00000000};
const unsigned char tres[8] __at(inici+24) = {0b00111110, 0b00000100, 0b00001000, 0b00000100,
	0b00000010, 0b00100010, 0b00011100, 0b00000000}; 
						// Definició de les funcions que farem servir 
unsigned char llegir_MemProg(unsigned short adre);
						// Llegeix el contingut de la memòria de programa
						// a la posició indicada per l'adreça
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
void EnviaMat(unsigned char color);	// Envia un text
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
	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
	while (1){
		for(char j = 7; j > 0; j--){	// 7 colors
			EnviaMat(j);
			__delay_ms(80);		// Retard
		}
	}
}
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 EnviaMat(unsigned char color){
	unsigned char caracE, caracD, Esquerra, Dreta, linia;
	// Hem d'enviar tots els caràcters i un blanc a cada costat
	// Per això el bucle és de numcar+1 repeticions
	// la posició numcar (4, inexistent) representa l'espai en blanc
	// Posicions gràfiques (i): 0, 1, 2, 3, 4, 5
	// Punters:                 4, 0, 1, 2, 3, 4
	for (unsigned char i = 0; i < numcar+1; i++){
		if(i == 0){
			caracE = blanc;
		} else {
			caracE = text[i-1];
		}
		if(i == numcar){
			caracD = blanc;
		} else {
			caracD = text[i];
		}
		// Per a cada parella de caràcters cal enviar vuit cops, un per desplaçament
		for (unsigned char j = 0; j < 8; j++){
			// Per a cada posició del desplaçament cal enviar les vuit línies
			for (unsigned char k = 0; k < 8; k++){
				if(caracE == blanc){
					Esquerra = 0;	// Si és un espai en blanc
				} else {
					adressa = inici + 8 * caracE + k;
					Esquerra = llegir_MemProg(adressa);
				}
				if(caracD == blanc){
					Dreta = 0;	// Si és un espai en blanc
				} else {
					adressa = inici + 8 * caracD + k;
					Dreta = llegir_MemProg(adressa);
				}
				if(j == 0){		// Si no hi ha desplaçament
					linia = Esquerra;
				} else {
					linia = (unsigned char) ((Esquerra << j) | (Dreta >> (8-j)));
				}
				Sortida[1] = k+1;	// Filera
				Sortida[3] = k+1;
				Sortida[5] = k+1;
				if(testbit(color, 2)){	// Vermells
					Sortida[0] = linia;
				} else {
					Sortida[0] = 0;
				}
				if(testbit(color, 1)){	// Verds
					Sortida[2] = linia;
				} else {
					Sortida[2] = 0;
				}
				if(testbit(color, 0)){	// Blaus
					Sortida[4] = linia;
				} else {
					Sortida[4] = 0;
				}
				Envia3max(Sortida);	// Ho envia al MAX7221
				__delay_ms(1);
			}
			__delay_ms(80);		// Retard
		}
	}
}
unsigned char llegir_MemProg(unsigned short adre) {
						// Llegeix el contingut de la memòria de programa
						// a la posició indicada per l'adreça
	EEADRH = adre/256;			// Part més significativa de l'adreça que volem llegir
	EEADR = (char) (adre%256);			// Part menys significativa de l'adreça que volem llegir
	EECON1bits.EEPGD = 1;			// Seleccionem memòria de programa i no EEPROM
	EECON1bits.RD = 1;			// Activa la lectura
	_delay(5);				// Donem temps a fer la lectura
	return EEDAT;				// Llegeix i retorna el resultat
}
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
	}
}

Pot succeir que desitgem que en una mateixa seqüència hi hagi caràcters de dos o més colors. El següent programa permet indicar un color per a cada caràcter, fent servir una segona llista per indicar-lo. Per provar-ho, hem posat una llista de set caràcters i mostrem cada un amb un color diferent, entre els set possibles.

#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 testbit(var, bit) ((var) & (1 <<(bit)))
#define inici 0xF00				// Adreça on es guarden els dibuixos
#define numcar 7				// Nombre de caràcters a enviar
#define blanc 99				// Valor que representa un blanc
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ó
unsigned short adressa;				// Variable de 16 bits per a l'adreça
unsigned char text[numcar] = {0, 2, 1, 3, 1, 2, 0};	// Caràcters que volem mostrar
unsigned char colors[numcar] = {4, 2, 1, 6, 5, 3, 7};	// Colors dels caràcters
						// vermell, verd, blau, groc, magenta, cian, blanc
char Actiu; 					// Variable que diu quin color està actiu
						// Actiu = 0		Apagat
						// Actiu = 1		Vermell
						// Actiu = 2		Verd
						// Actiu = 3		Blau
const unsigned char zero[8] __at(inici) = {0b00011100, 0b00100010, 0b00100110, 0b00101010,
	0b00110010, 0b00100010, 0b00011100, 0b00000000};
const unsigned char u[8] __at(inici+8) = {0b00001000, 0b00011000, 0b00001000, 0b00001000,
	0b00001000, 0b00001000, 0b00011100, 0b00000000}; 
const unsigned char dos[8] __at(inici+16) = {0b00011100, 0b00100010, 0b00000010, 0b00000100,
	0b00001000, 0b00010000, 0b00111110, 0b00000000};
const unsigned char tres[8] __at(inici+24) = {0b00111110, 0b00000100, 0b00001000, 0b00000100,
	0b00000010, 0b00100010, 0b00011100, 0b00000000}; 
						// Definició de les funcions que farem servir 
unsigned char llegir_MemProg(unsigned short adre);
						// Llegeix el contingut de la memòria de programa
						// a la posició indicada per l'adreça
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
void EnviaMat(void);	// Envia un text
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
	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
	while (1){
		EnviaMat();
		__delay_ms(80);		// Retard
	}
}
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 EnviaMat(void){
	unsigned char caracE, caracD, colorE, colorD, Esquerra, Dreta, Erodat, Drodat, linia;
	// Hem d'enviar tots els caràcters i un blanc a cada costat
	// Per això el bucle és de numcar+1 repeticions
	// la posició blanc (inexistent) representa l'espai en blanc
	// Posicions gràfiques (i): 0, 1, 2, 3, 4, 5
	// Punters:                 4, 0, 1, 2, 3, 4
	for (unsigned char i = 0; i < numcar+1; i++){
		if(i == 0){
			caracE = blanc;
			colorE = 0;
		} else {
			caracE = text[i-1];
			colorE = colors[i-1];
		}
		if(i == numcar){
			caracD = blanc;
			colorD = 0;
		} else {
			caracD = text[i];
			colorD = colors[i];
		}
		// Per a cada parella de caràcters cal enviar vuit cops, un per desplaçament
		for (unsigned char j = 0; j < 8; j++){
			// Per a cada posició del desplaçament cal enviar les vuit línies
			for (unsigned char k = 0; k < 8; k++){
				if(caracE == blanc){
					Esquerra = 0;	// Si és un espai en blanc
				} else {
					adressa = inici + 8 * caracE + k;
					Esquerra = llegir_MemProg(adressa);
				}
				if(caracD == blanc){
					Dreta = 0;	// Si és un espai en blanc
				} else {
					adressa = inici + 8 * caracD + k;
					Dreta = llegir_MemProg(adressa);
				}
				if(j == 0){		// Si no hi ha desplaçament
					Erodat = Esquerra;
					Drodat = 0;
				} else {
					Erodat = (unsigned char) (Esquerra << j);
					Drodat = (unsigned char) (Dreta >> (8-j));
				}
				Sortida[1] = k+1;	// Filera
				Sortida[3] = k+1;
				Sortida[5] = k+1;
				if(testbit(colorE, 2)){	// Vermells
					linia = Erodat;
				} else {
					linia = 0;
				}
				if(testbit(colorD, 2)){	// Vermells
					linia = linia | Drodat;
				}
				Sortida[0] = linia;
				if(testbit(colorE, 1)){	// Verds
					linia = Erodat;
				} else {
					linia = 0;
				}
				if(testbit(colorD, 1)){	// Verds
					linia = linia | Drodat;
				}
				Sortida[2] = linia;
				if(testbit(colorE, 0)){	// Verds
					linia = Erodat;
				} else {
					linia = 0;
				}
				if(testbit(colorD, 0)){	// Blaus
					linia = linia | Drodat;
				}
				Sortida[4] = linia;
				Envia3max(Sortida);	// Ho envia al MAX7221
				__delay_ms(1);
			}
			__delay_ms(80);		// Retard
		}
	}
}
unsigned char llegir_MemProg(unsigned short adre) {
						// Llegeix el contingut de la memòria de programa
						// a la posició indicada per l'adreça
	EEADRH = adre/256;			// Part més significativa de l'adreça que volem llegir
	EEADR = (char) (adre%256);			// Part menys significativa de l'adreça que volem llegir
	EECON1bits.EEPGD = 1;			// Seleccionem memòria de programa i no EEPROM
	EECON1bits.RD = 1;			// Activa la lectura
	_delay(5);				// Donem temps a fer la lectura
	return EEDAT;				// Llegeix i retorna el resultat
}
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
	}
}

 

 

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