En l'exemple següent mostrarem un parell de dibuixos a la matriu de LED. El programa és llarg però senzill. En la part d'inicialització configura el microcontrolador. En el bucle simplement va alternant els dos patrons de les figures següents deixant un temps entre canvi i canvi per tal que els patrons es puguin veure suficientment bé.

#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
// 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
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) {
// Matriu 1
Sortida[1] = 0x01; // Filera 1
Sortida[3] = 0x01;
Sortida[5] = 0x01;
Sortida[0] = 0b00111100; // Vermells
Sortida[2] = 0b00000000; // Verds
Sortida[4] = 0b00000000; // Blaus
Envia3max(Sortida); // Ho envia al MAX7221
Sortida[1] = 0x02; // Filera 2
Sortida[3] = 0x02;
Sortida[5] = 0x02;
Sortida[0] = 0b01111110; // Vermells
Sortida[2] = 0b00000000; // Verds
Sortida[4] = 0b00000000; // Blaus
Envia3max(Sortida); // Ho envia al MAX7221
Sortida[1] = 0x03; // Filera 3
Sortida[3] = 0x03;
Sortida[5] = 0x03;
Sortida[0] = 0b11111111; // Vermells
Sortida[2] = 0b00000000; // Verds
Sortida[4] = 0b00000000; // Blaus
Envia3max(Sortida); // Ho envia al MAX7221
Sortida[1] = 0x04; // Filera 4
Sortida[3] = 0x04;
Sortida[5] = 0x04;
Sortida[0] = 0b11111111; // Vermells
Sortida[2] = 0b01111110; // Verds
Sortida[4] = 0b01111110; // Blaus
Envia3max(Sortida); // Ho envia al MAX7221
Sortida[1] = 0x05; // Filera 5
Sortida[3] = 0x05;
Sortida[5] = 0x05;
Sortida[0] = 0b11111111; // Vermells
Sortida[2] = 0b01111110; // Verds
Sortida[4] = 0b01111110; // Blaus
Envia3max(Sortida); // Ho envia al MAX7221
Sortida[1] = 0x06; // Filera 6
Sortida[3] = 0x06;
Sortida[5] = 0x06;
Sortida[0] = 0b11111111; // Vermells
Sortida[2] = 0b00000000; // Verds
Sortida[4] = 0b00000000; // Blaus
Envia3max(Sortida); // Ho envia al MAX7221
Sortida[1] = 0x07; // Filera 7
Sortida[3] = 0x07;
Sortida[5] = 0x07;
Sortida[0] = 0b01111110; // Vermells
Sortida[2] = 0b00000000; // Verds
Sortida[4] = 0b00000000; // Blaus
Envia3max(Sortida); // Ho envia al MAX7221
Sortida[1] = 0x08; // Filera 8
Sortida[3] = 0x08;
Sortida[5] = 0x08;
Sortida[0] = 0b00111100; // Vermells
Sortida[2] = 0b00000000; // Verds
Sortida[4] = 0b00000000; // Blaus
Envia3max(Sortida); // Ho envia al MAX7221
// Fi de la matriu 1
__delay_ms(1400); // Retard d'1,4 s teòrics
// Correspon a uns 2,8 s
// Matriu 2
Sortida[1] = 0x01; // Filera 1
Sortida[3] = 0x01;
Sortida[5] = 0x01;
Sortida[0] = 0b00000000; // Vermells
Sortida[2] = 0b00011000; // Verds
Sortida[4] = 0b00000000; // Blaus
Envia3max(Sortida); // Ho envia al MAX7221
Sortida[1] = 0x02; // Filera 2
Sortida[3] = 0x02;
Sortida[5] = 0x02;
Sortida[0] = 0b00000000; // Vermells
Sortida[2] = 0b00111100; // Verds
Sortida[4] = 0b00000000; // Blaus
Envia3max(Sortida); // Ho envia al MAX7221
Sortida[1] = 0x03; // Filera 3
Sortida[3] = 0x03;
Sortida[5] = 0x03;
Sortida[0] = 0b00000000; // Vermells
Sortida[2] = 0b01111110; // Verds
Sortida[4] = 0b00000000; // Blaus
Envia3max(Sortida); // Ho envia al MAX7221
Sortida[1] = 0x04; // Filera 4
Sortida[3] = 0x04;
Sortida[5] = 0x04;
Sortida[0] = 0b00000000; // Vermells
Sortida[2] = 0b11111111; // Verds
Sortida[4] = 0b00000000; // Blaus
Envia3max(Sortida); // Ho envia al MAX7221
Sortida[1] = 0x05; // Filera 5
Sortida[3] = 0x05;
Sortida[5] = 0x05;
Sortida[0] = 0b00000000; // Vermells
Sortida[2] = 0b00011000; // Verds
Sortida[4] = 0b00000000; // Blaus
Envia3max(Sortida); // Ho envia al MAX7221
Sortida[1] = 0x06; // Filera 6
Sortida[3] = 0x06;
Sortida[5] = 0x06;
Sortida[0] = 0b00000000; // Vermells
Sortida[2] = 0b00011000; // Verds
Sortida[4] = 0b00000000; // Blaus
Envia3max(Sortida); // Ho envia al MAX7221
Sortida[1] = 0x07; // Filera 7
Sortida[3] = 0x07;
Sortida[5] = 0x07;
Sortida[0] = 0b00000000; // Vermells
Sortida[2] = 0b00011000; // Verds
Sortida[4] = 0b00000000; // Blaus
Envia3max(Sortida); // Ho envia al MAX7221
Sortida[1] = 0x08; // Filera 8
Sortida[3] = 0x08;
Sortida[5] = 0x08;
Sortida[0] = 0b00000000; // Vermells
Sortida[2] = 0b00011000; // Verds
Sortida[4] = 0b00000000; // Blaus
Envia3max(Sortida); // Ho envia al MAX7221
// Fi de la matriu 2
__delay_ms(1400); // Retard d'1,4 s teòrics
// Correspon a uns 2,8 s
}
}
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
}
}
El següent programa fa exactament el mateix però guardant els dibuixos en tres vectors, un per a cada color.
#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 verms1[8] = {0b00111100, 0b01111110, 0b11111111, 0b11111111,
0b11111111, 0b11111111, 0b01111110, 0b00111100};
char verds1[8] = {0b00000000, 0b00000000, 0b00000000, 0b01111110,
0b01111110, 0b00000000, 0b00000000, 0b00000000};
char blaus1[8] = {0b00000000, 0b00000000, 0b00000000, 0b01111110,
0b01111110, 0b00000000, 0b00000000, 0b00000000};
char verms2[8] = {0b00000000, 0b00000000, 0b00000000, 0b00000000,
0b00000000, 0b00000000, 0b00000000, 0b00000000};
char verds2[8] = {0b00011000, 0b00111100, 0b01111110, 0b11111111,
0b00011000, 0b00011000, 0b00011000, 0b00011000};
char blaus2[8] = {0b00000000, 0b00000000, 0b00000000, 0b00000000,
0b00000000, 0b00000000, 0b00000000, 0b00000000};
// 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
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) {
// Matriu 1
for (unsigned char k = 0; k < 8; k++){
Sortida[1] = k+1; // Filera
Sortida[3] = k+1;
Sortida[5] = k+1;
Sortida[0] = verms1[k]; // Vermells
Sortida[2] = verds1[k]; // Verds
Sortida[4] = blaus1[k]; // Blaus
Envia3max(Sortida); // Ho envia al MAX7221
__delay_ms(1);
}
__delay_ms(1400); // Retard d'1,4 s teòrics
// Correspon a uns 2,8 s
// Matriu 2
for (unsigned char k = 0; k < 8; k++){
Sortida[1] = k+1; // Filera
Sortida[3] = k+1;
Sortida[5] = k+1;
Sortida[0] = verms2[k]; // Vermells
Sortida[2] = verds2[k]; // Verds
Sortida[4] = blaus2[k]; // Blaus
Envia3max(Sortida); // Ho envia al MAX7221
__delay_ms(1);
}
__delay_ms(1400); // Retard d'1,4 s teòrics
// Correspon a uns 2,8 s
}
}
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
}
}
El següent programa fa exactament el mateix però guardant cada dibuix en una matriu.
#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 fig1[3][8] = { {0b00111100, 0b01111110, 0b11111111, 0b11111111,
0b11111111, 0b11111111, 0b01111110, 0b00111100},
{0b00000000, 0b00000000, 0b00000000, 0b01111110,
0b01111110, 0b00000000, 0b00000000, 0b00000000},
{0b00000000, 0b00000000, 0b00000000, 0b01111110,
0b01111110, 0b00000000, 0b00000000, 0b00000000} };
char fig2[3][8] = { {0b00000000, 0b00000000, 0b00000000, 0b00000000,
0b00000000, 0b00000000, 0b00000000, 0b00000000},
{0b00011000, 0b00111100, 0b01111110, 0b11111111,
0b00011000, 0b00011000, 0b00011000, 0b00011000},
{0b00000000, 0b00000000, 0b00000000, 0b00000000,
0b00000000, 0b00000000, 0b00000000, 0b00000000} };
// 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
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) {
// Matriu 1
for (unsigned char k = 0; k < 8; k++){
Sortida[1] = k+1; // Filera
Sortida[3] = k+1;
Sortida[5] = k+1;
Sortida[0] = fig1[0][k]; // Vermells
Sortida[2] = fig1[1][k]; // Verds
Sortida[4] = fig1[2][k]; // Blaus
Envia3max(Sortida); // Ho envia al MAX7221
__delay_ms(1);
}
__delay_ms(1400); // Retard d'1,4 s teòrics
// Correspon a uns 2,8 s
// Matriu 2
for (unsigned char k = 0; k < 8; k++){
Sortida[1] = k+1; // Filera
Sortida[3] = k+1;
Sortida[5] = k+1;
Sortida[0] = fig2[0][k]; // Vermells
Sortida[2] = fig2[1][k]; // Verds
Sortida[4] = fig2[2][k]; // Blaus
Envia3max(Sortida); // Ho envia al MAX7221
__delay_ms(1);
}
__delay_ms(1400); // Retard d'1,4 s teòrics
// Correspon a uns 2,8 s
}
}
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
}
}
També és possible guardar els tres vectors, atès que són constants, a la memòria de programa. Per fer-ho fàcil, hem indicat amb una instrucció define la posició de l'inici del primer vector i situem els altres cinc a continuació (atès que els vectors són de vuit components, sumem 8 a la posició de l'anterior. A l'hora de llegir les dades també partim de la posició d'inici i li anem sumant 8 cada cop que volem saltar al vector següent.
#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 inici 0xF00 // Adreça on es guarden els dibuixos
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
char Actiu; // Variable que diu quin color està actiu
// Actiu = 0 Apagat
// Actiu = 1 Vermell
// Actiu = 2 Verd
// Actiu = 3 Blau
const unsigned char verms1[8] __at(inici) = {0b00111100, 0b01111110, 0b11111111, 0b11111111,
0b11111111, 0b11111111, 0b01111110, 0b00111100};
const unsigned char verds1[8] __at(inici+8) = {0b00000000, 0b00000000, 0b00000000, 0b01111110,
0b01111110, 0b00000000, 0b00000000, 0b00000000};
const unsigned char blaus1[8] __at(inici+16) = {0b00000000, 0b00000000, 0b00000000, 0b01111110,
0b01111110, 0b00000000, 0b00000000, 0b00000000};
const unsigned char verms2[8] __at(inici+24) = {0b00000000, 0b00000000, 0b00000000, 0b00000000,
0b00000000, 0b00000000, 0b00000000, 0b00000000};
const unsigned char verds2[8] __at(inici+32) = {0b00011000, 0b00111100, 0b01111110, 0b11111111,
0b00011000, 0b00011000, 0b00011000, 0b00011000};
const unsigned char blaus2[8] __at(inici+40) = {0b00000000, 0b00000000, 0b00000000, 0b00000000,
0b00000000, 0b00000000, 0b00000000, 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 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) {
// Matriu 1
for (unsigned char k = 0; k < 8; k++){
Sortida[1] = k+1; // Filera
Sortida[3] = k+1;
Sortida[5] = k+1;
adressa = inici + k; // Vermells
Sortida[0] = llegir_MemProg(adressa);
adressa += 8; // Verds
Sortida[2] = llegir_MemProg(adressa);
adressa += 8; // Blaus
Sortida[4] = llegir_MemProg(adressa);
Envia3max(Sortida); // Ho envia al MAX7221
__delay_ms(1);
}
__delay_ms(1400); // Retard d'1,4 s teòrics
// Correspon a uns 2,8 s
// Matriu 2
for (unsigned char k = 0; k < 8; k++){
Sortida[1] = k+1; // Filera
Sortida[3] = k+1;
Sortida[5] = k+1;
adressa = inici + 24 + k; // Vermells
Sortida[0] = llegir_MemProg(adressa);
adressa += 8; // Verds
Sortida[2] = llegir_MemProg(adressa);
adressa += 8; // Blaus
Sortida[4] = llegir_MemProg(adressa);
Envia3max(Sortida); // Ho envia al MAX7221
__delay_ms(1);
}
__delay_ms(1400); // Retard d'1,4 s teòrics
// Correspon a uns 2,8 s
}
}
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
}
}
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
}
}
Com ja s'ha comentat, podem implementar la funció Envia3max en assemblador. El programa que guarda les imatges en matrius, per exemple, 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
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 fig1[3][8] = { {0b00111100, 0b01111110, 0b11111111, 0b11111111,
0b11111111, 0b11111111, 0b01111110, 0b00111100},
{0b00000000, 0b00000000, 0b00000000, 0b01111110,
0b01111110, 0b00000000, 0b00000000, 0b00000000},
{0b00000000, 0b00000000, 0b00000000, 0b01111110,
0b01111110, 0b00000000, 0b00000000, 0b00000000} };
char fig2[3][8] = { {0b00000000, 0b00000000, 0b00000000, 0b00000000,
0b00000000, 0b00000000, 0b00000000, 0b00000000},
{0b00011000, 0b00111100, 0b01111110, 0b11111111,
0b00011000, 0b00011000, 0b00011000, 0b00011000},
{0b00000000, 0b00000000, 0b00000000, 0b00000000,
0b00000000, 0b00000000, 0b00000000, 0b00000000} };
// 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
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) {
// Matriu 1
for (unsigned char k = 0; k < 8; k++){
Sortida[1] = k+1; // Filera
Sortida[3] = k+1;
Sortida[5] = k+1;
Sortida[0] = fig1[0][k]; // Vermells
Sortida[2] = fig1[1][k]; // Verds
Sortida[4] = fig1[2][k]; // Blaus
Envia3max(); // Ho envia al MAX7221
__delay_ms(1);
}
__delay_ms(1400); // Retard d'1,4 s teòrics
// Correspon a uns 2,8 s
// Matriu 2
for (unsigned char k = 0; k < 8; k++){
Sortida[1] = k+1; // Filera
Sortida[3] = k+1;
Sortida[5] = k+1;
Sortida[0] = fig2[0][k]; // Vermells
Sortida[2] = fig2[1][k]; // Verds
Sortida[4] = fig2[2][k]; // Blaus
Envia3max(); // Ho envia al MAX7221
__delay_ms(1);
}
__delay_ms(1400); // Retard d'1,4 s teòrics
// Correspon a uns 2,8 s
}
}
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
}
}

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