Es tracta d'una variant del conegut joc Pong, adaptada a les característiques de la matriu de LED. En aquest cas les pales es mouen horitzontalment i, per tant, es juga com si el Pong hagués estat girat 90°.
El programa és el 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 #include <stdlib.h> // Carrega el fitxer on hi ha la funcis rand() #define _XTAL_FREQ 4000000 // La freq|hncia del rellotge is 4 MHz
char Port; // Gestis del port a la funcis Envia_max
char Compta; // Comptador de bits a la funcis Envia_max
char Sortida[6]; // Valors a enviar al MAX7221 (48 bits)
char Sorti[6]; // Valors a enviar al MAX7221 des de la interrupcis
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]; // Aqum guardarem el dibuix (8 fileres)
char x = 3; // Coordenada X del cursor (0 a 7)
// X = 0 is la columna de la dreta
char mascara = 0b11000000;
char mascara2 = 0b11000000;
char y = 0; // Coordenada Y del cursor (0 a 7)
char mirar = 1; // Espera que es deixi anar el polsador
char actualitza = 0;
char x2=3;
char y2=7;
char FilaBola = 3; // Fila de la bola
char d= 1;// Direccion de la bola, entre 0 y 2 | 0 Izq - 1 Recto - 2 Dch
char Bola= 0b00010000;
char Sentido = 0; // Sentido de la Bola, Sentido=0 Para Abajo | Sentido=1 Para Arriba
char ApagaBola = 0;
char Centro = 0;
char Gol1 = 0;
char Gol2 = 0;
char empieza = 0;
// Definicis 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); // Funcis de lectura dels polsadors
void EnviaL(char Caracter); // Envia un car`cter
void Esborra(void); // Esborra la pantalla i posa el cursor a l'inici
void Cursor(char Filera, char Columna); // Posiciona el cursor
// (filera 1 a 2 i columna 1 a 32, segons pantalla)
char obtenerDireccionAleatoria();
char Wins(char jug);
void main (void) {
OPTION_REG = 0b10000101; // Configuracis de Timer0
// Com a temporitzador basat en rellotge
// 101 - Factor d'escala de 64
// I resisthncies de pull-up desactivades (valor per defecte)
TRISC = 0; // Tot el port C is de sortida
TRISB = 0; // Tot el port B is de sortida
TRISA = 0xFF; // Tot el port A is d'entrada
ANSEL = 0b00000101; // Configura AN0 i AN2 com entrada analrgica
ANSELH = 0; // Desactiva les altres entrades analrgiques
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|hncia
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; // Presseleccis de 100, que ssn 156 iteracions
// Correspon a una interrupcis cada 7,5 ms
INTCON = 0b10100000; // Activem GIE i T0IE
Apaga(); // Apaga tots els LED
__delay_ms(2000); // Esperem que arrenqui la pantalla
TXSTAbits.BRGH = 1; // Configuracis de velocitat
BAUDCTLbits.BRG16 = 0; // Par`metre de velocitat de 8 bits
SPBRG = 25; // Velocitat de 9600 baud
TXSTAbits.SYNC = 0; // Comunicacis asmncrona
TXSTAbits.TX9 = 0; // Comunicacis de 8 bits
RCSTAbits.SPEN = 1; // Activa comunicacis shrie
TXSTAbits.TXEN = 1; // Activa comunicacis
Esborra(); // Esborra la pantalla i posa el cursor a l'inici
EnviaL('J'); // Lletra
EnviaL('1'); // Lletra
EnviaL(':'); // Lletra
EnviaL('0'); // Lletra
Cursor(2, 1); // Posicis
EnviaL('J'); // Lletra
EnviaL('2'); // Lletra
EnviaL(':'); // Lletra
EnviaL('0'); // Lletra
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'accis del polsador, no es tornar` a fer fins
// que es detecti que s'han deixat anar
if (actualitza > 6){
if (Centro==1){
__delay_ms(1000);
FilaBola=4;
Bola= 0b0001000;
d=obtenerDireccionAleatoria();
Sentido=!Sentido;
Centro=0;
}
if (Centro==2){
__delay_ms(1000);
FilaBola=3;
Bola= 0b0001000;
d=obtenerDireccionAleatoria();
Sentido=!Sentido;
Centro=0;
}
if (empieza == 1){
if (Sentido == 0){ // Si estem a la filera del cursor
if (FilaBola < 7){
char Comprobacio;
//IZQ
if(d==0){
if(FilaBola == 6){
Comprobacio = (Bola << 1) & mascara2; //DETECTA PALA
if(Comprobacio != 0){
Sentido = 1;
d = obtenerDireccionAleatoria(); // Generar direccion aleatoria
ApagaBola = 1;
Bola <<= 1;
FilaBola++ ;
} else{
//GOL1
Gol1 += 1;
Bola <<= 1;
FilaBola++;
Centro=1;
Cursor(1, 4);
EnviaL(Gol1+'0');
empieza = 0;
}
} else{
if ((Bola & 0x80) == 0) { // Mantener dentro de limites de bits
ApagaBola = 0;
Bola <<= 1;
FilaBola++ ;
} else {
d = 2; // Cambiar direccion si llega al l?mite
}
}
} else{
//CENTRO
if(d==1){
if(FilaBola == 6){
Comprobacio = Bola & mascara2; //DETECTA PALA
if(Comprobacio != 0){
Sentido = 1;
d = obtenerDireccionAleatoria(); // Direccion aleatoria
ApagaBola = 1;
} else{
//GOL1
Gol1 += 1;
FilaBola++;
Centro=1;
Cursor(1, 4);
EnviaL(Gol1+'0');
empieza = 0;
}
} else{
ApagaBola = 0;
FilaBola++ ;
}
} else{
//DCH
if(d==2){
if(FilaBola == 6){
Comprobacio = (Bola >> 1) & mascara2; //DETECTA PALA
if (Bola == 0b00000001){
Comprobacio = (Bola << 1) & mascara2;
}
if(Comprobacio != 0){
Sentido = 1;
d = obtenerDireccionAleatoria();
ApagaBola = 1;
Bola >>= 1;
FilaBola++ ;
} else{
//GOL1
Gol1 += 1;
Bola >>= 1;
FilaBola++;
Centro=1;
Cursor(1, 4);
EnviaL(Gol1+'0');
empieza = 0;
}
} else{
if ((Bola & 0x01) == 0) { // Mantener dentro de limites de bits
ApagaBola = 0;
Bola >>= 1;
FilaBola++ ;
} else {
d = 0; // Cambiar direccion si llega al l?mite
}
}
}
}
}
}
} else{
if (Sentido == 1){ // Si estem a la filera del cursor
if (FilaBola > 0){
char Comprobacio2;
if(d==0){
if(FilaBola == 1){
Comprobacio2 = (Bola << 1) & mascara; //DETECTA PALA
if(Comprobacio2 != 0){
Sentido = 0;
d = obtenerDireccionAleatoria();
ApagaBola = 1;
Bola <<= 1;
FilaBola-- ;
} else{
//GOL2
Bola <<= 1;
FilaBola--;
Gol2 += 1;
Centro=2;
Cursor(2, 4);
EnviaL(Gol2+'0');
empieza = 0;
}
} else{
if ((Bola & 0x80) == 0) { // Mantener dentro de limites de bits
ApagaBola = 0;
Bola <<= 1;
FilaBola-- ;
} else {
d = 2; // Cambiar direccion si llega al limite
}
}
} else{
if(d==1){
if(FilaBola == 1){
Comprobacio2 = Bola & mascara; //DETECTA PALA
if(Comprobacio2 != 0){
Sentido = 0;
d = obtenerDireccionAleatoria();
ApagaBola = 1;
} else{
//GOL2
FilaBola--;
Gol2 += 1;
Centro=2;
Cursor(2, 4);
EnviaL(Gol2+'0');
empieza = 0;
}
}
if (FilaBola>1){
ApagaBola = 0;
FilaBola-- ;
}
} else{
if(d==2){
if(FilaBola == 1){
Comprobacio2 = (Bola >> 1) & mascara; //DETECTA PALA
if (Bola == 0b00000001){
Comprobacio2 = (Bola << 1) & mascara;
}
if(Comprobacio2 != 0){
Sentido = 0;
d = obtenerDireccionAleatoria();
ApagaBola = 1;
Bola >>= 1;
FilaBola-- ;
} else{
//GOL2
Bola >>= 1;
FilaBola--;
Gol2 += 1;
Centro=2;
Cursor(2, 4);
EnviaL(Gol2+'0');
empieza = 0;
}
} else{
if ((Bola & 0x01) == 0) { // Mantener dentro de limites de bits
ApagaBola = 0;
Bola >>= 1;
FilaBola-- ;
} else {
d = 0; // Cambiar direcci?n si llega al limite
}
}
}
}
}
}
}
}
}
// Verificacion final de limites
if (Bola > 0x80){
Bola = 0x80;
} else{
if (Bola < 0x01){
Bola = 0x01;
}
}
// Verificacion de limites de FilaBola (por si algun cambio la desborda)
if (FilaBola < 0){
FilaBola = 0;
} else{
if (FilaBola > 7){
FilaBola = 7;
}
}
actualitza = 0;
}
Polsad = Polsador(); // Llegim els polsadors
if (mirar == 1){
if (Polsad == 1) {
if (x>0 & x<=6) {
// Si s'ha premut el polsador 1
x = (x - 1); // Incrementa x perr la manti entre 0 i 7
mirar = 0;
}
}
if (Polsad == 2) {
if (x>=0 & x<6) {
// Si s'ha premut el polsador 1
x = (x + 1); // Incrementa x perr la manti entre 0 i 7
mirar = 0;
}
}
if (Polsad == 3) { // Si s'ha premut el polsador 3
// Invertim el LED corresponent
empieza = 1;
mirar = 0;
}
if (Polsad == 4) { // Si s'ha premut el polsador 4
if (x2>0 & x2<=6) {
// Si s'ha premut el polsador 1
x2 = (x2 - 1); // Incrementa x perr la manti entre 0 i 7
mirar = 0; // No fem res
}
}
if (Polsad == 5) { // Si s'ha premut el polsador 5
if (x2>=0 & x2<6) {
// Si s'ha premut el polsador 1
x2 = (x2 + 1); // Incrementa x perr la manti entre 0 i 7
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++){
FilaBola = FilaBola%8;
Sortida[0] = 0; // Vermells
Sortida[2] = 0; // Verds
Sortida[4] = 0; // Blaus
// El cursor es mostra groc, independentment del punt
if (y == k){ // Si estem a la filera del cursor
mascara = (0b11000000 >> x);
Sortida[0] = Sortida[0] | mascara; // Encin vermell
Sortida[2] = 0; // Encin verd
Sortida[4] = Sortida[4] | mascara; // Apaga blau
}
if (y2 == k){ // Si estem a la filera del cursor
mascara2 = (0b11000000 >> x2);
Sortida[0] = 0; // Encin vermell
Sortida[2] = Sortida[2] | mascara2; // Encin verd
Sortida[4] = Sortida[4] | mascara2; // Apaga blau
}
if (FilaBola == k){ // Si estem a la filera de la bola
if(ApagaBola == 0){
Sortida[0] = Sortida[0] | Bola; // Encin vermell
Sortida[2] = Sortida[2] | Bola; // Encin verd
Sortida[4] = 0; // Apaga blau
}
}
Sortida[1] = k+1; // Filera
Sortida[3] = k+1;
Sortida[5] = k+1;
Envia3max(Sortida); // Ho envia al MAX7221
__delay_ms(1);
}
if (Gol1 == 5) {
Wins(1);
Gol1 = 0;
Gol2 = 0;
}
if (Gol2 == 5) {
Wins(2);
Gol1 = 0;
Gol2 = 0;
}
actualitza++;
}
}
void __interrupt() temporit(void){
// void interrupt temporit(void) { // Lmnia alternativa
if (INTCONbits.T0IF) { // Comprovem que hi ha interrupcis per Timer 0
TMR0 = 100; // Preseleccis de Timer0
INTCONbits.T0IF = 0; // Desactiva el bit que indica interrupcis 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 is vermell
Sorti[0] = 0x01; // Vermell activat
}
if (Actiu == 2) { // Si is verd
Sorti[2] = 0x01; // Verd activat
}
if (Actiu == 3) { // Si is 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
}
}
char obtenerDireccionAleatoria() {
int direccion;
do {
direccion = rand() % 4; // Genera un nzmero entre 0 y 3
} while (direccion == 3); // Repite hasta obtener 0, 1, o 2
return direccion;
}
char Wins(char jug) {
if (jug == 1) {
Esborra();
Cursor(1,1);
EnviaL('J');
EnviaL('1');
EnviaL(' ');
EnviaL('W');
EnviaL('i');
EnviaL('n');
EnviaL('s');
}
if (jug == 2) {
Esborra();
Cursor(2,1);
EnviaL('J');
EnviaL('2');
EnviaL(' ');
EnviaL('W');
EnviaL('i');
EnviaL('n');
EnviaL('s');
}
__delay_ms(5000);
Esborra();
EnviaL('J'); // Lletra
EnviaL('1'); // Lletra
EnviaL(':'); // Lletra
EnviaL('0'); // Lletra
Cursor(2, 1); // Posicis
EnviaL('J'); // Lletra
EnviaL('2'); // Lletra
EnviaL(':'); // Lletra
EnviaL('0'); // Lletra
}
void EnviaL(char Caracter) {
INTCONbits.GIE = 0; // Desactiva les interrupcions moment`niament
RCSTAbits.SPEN = 1; // Activa comunicacis shrie
TXSTAbits.TXEN = 1; // Activa comunicacis
TXREG = Caracter; // Agafa el car`cter i l'envia
__delay_ms(1); // Donem temps
while (PIR1bits.TXIF == 0) // Esperem que s'acabi d'enviar
; // No fem res
RCSTAbits.SPEN = 0; // Desactiva comunicacis shrie
TXSTAbits.TXEN = 0; // Desactiva comunicacis
INTCONbits.GIE = 1; // Activa les interrupcions
}
void Esborra(void) {
EnviaL(254); // Car`cter de control
EnviaL(1); // Esborra la pantalla i posa el cursor a l'inici
}
void Cursor(char Filera, char Columna) {
char Posicio = 0; // Variable per a calcular la posicis
if (Filera == 2) {
Posicio = 64; // La primera columna de la segona fila is 64;
}
if (Columna > 0 && Columna < 33) { // Comprovem que sigui un valor raonable
Posicio = Posicio + Columna; // Sumem les adreces
Posicio = Posicio - 1; // Restem 1 perquh numera des de 0
}
Posicio = Posicio + 128; // Posa el bit de posicionat a 1
EnviaL(254); // Control de la posicis del cursor
EnviaL(Posicio); // Canvia el cursor de lloc
}
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 mis a l'esquerra
// Temp nomis 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] = 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 forga 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("movwf PORTB"); // I el posa al port B
asm("banksel _Compta");
asm("movlw 48"); // Nzmero 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 mis 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 is Data
asm("movwf PORTB"); // I el posa al port B
asm("bsf (_Port&7fh),5"); // Activa Clock, forgant a llegir el bit
asm("movf (_Port&7fh),w"); // Agafa el valor de Port. El valor que ha canviat is Clock
asm("movwf PORTB"); // I el posa al port B
asm("bcf (_Port&7fh),5"); // Desactiva Clock
asm("movf (_Port&7fh),w"); // Agafa el valor de Port. El valor que ha canviat is Clock
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 is zero, repeteix el bucle
asm("banksel (_Port&7fh)");
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 is Latch
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;
}

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