A l'iniciar el programa estan encesos els vuit LED de la filera inferior. Els tres de l'esquerra, en color blau, representen les columnes que no es faran servir i els cinc de la dreta, en vermell, representen les columnes que corresponen al joc. Tot seguit, s'encendrà un LED groc (que representa una nota musical) a la part superior, en una columna escollida aleatòriament i anirà baixant. Quan arribi a baix, l'usuari ha d'estar prement el polsador que correspon a la columna del LED groc.

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 "pic16f690.h" // Carrega el fitxer d'adreces i paràmetres del PIC 16F690 #include <xc.h> // Carrega el fitxer de funcions necessari per al compilador XC8 #include <stdlib.h> // rand // Feim servir la funció rand() #define _XTAL_FREQ 4000000 // La freqüència del rellotge és 4 MHz #define Polsa RA3 #define clrbit(var, bit) ((var) &= ~(1 << (bit))) #define flipbit(var, bit) ((var) ^= (1<<(bit)))
//VARIABLES
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
char Vides=0; // Nombre de vides, quan vides=0 el joc s'atura
char Polsad; // Polsador que s'ha premut (1-5, 0==(cap o 2 alhora))
short Delay=+250; // Ens ajuda a fer _delay() variable
char k=250;
char Cicles=0; // Compta cicles
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
char Punt; // Sistema de puntuació
char D; // Desenes
char U; // Unitats
char r1; // Unitats rècord
char r2; // Detecta l'existència d'un rècord anterior
char r3; // Detecta l'existència d'un rècord anterior
char r4; // Detecta l'existència d'un rècord anterior
char p1=0; // Unitats rècord variables
char Urec=0; // Unitats rècord
char Drec=0; // Desenes rècord
char control; // Variable de control de la funció TocaNota. Si és 0 nota, si és 1 silenci
int bucles; // Comptador d'iteracions de la nota
int silenci; // Durada del silenci
char port=0; // Variable auxiliar del port C
char Llengua=0; // Determina l'idioma a la pantalla LCD
char menu[14] = {'1','.','C','A',' ','2','.','E','S',' ','3','.','E','N'};
char menu2[4] = {'4','.','E','U'};
char menu3[4] = {'5','.','I','T'};
char cat1[10] = {'P','R','E','M','I',' ','B','T','N','0'};
char cat2[3] = {'P','E','R'};
char cat3[5] = {'J','U','G','A','R'};
char cas1[5] = {'P','U','L','S','E'};
char btn[4] = {'B','T','N','0'};
char cas2[4] = {'P','A','R','A'};
char eng1[5] = {'P','R','E','S','S'};
char eng2[2] = {'T','O'};
char eng3[4] = {'P','L','A','Y'};
char eus1[6] = {'S','A','K','A','T','U'};
char eus2[16] = {'E','R','R','E','P','R','O','D','U','Z','I','T','Z','E','K','O'};
char ita1[5] = {'P','R','E','M','I'};
char ita2[7] = {'G','I','O','C','A','R','E'};
//FUNCIONS void Envia3max(char Valor[]); // Envia un joc de valors als tres MAX7221 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. Definició de les funcions que farem servir 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 void TocaNota(char valPre, char valPos, char valPR2, int numbuc, int numsil); unsigned char llegir_EEPROM(unsigned char adre); // Llegeix el contingut de l'EEPROM a la posició indicada per l'adreça void escriu_EEPROM(unsigned char adre, unsigned char dada); // Escriu el valor donat a l'adreça EEPROM indicada char Polsador(void);
void main (void) {
OPTION_REG = 0b10000101; // Configuració de Timer0 cCom 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
PORTA = 1; // Inicialitza a 1 el port A
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 = 0b11100000; // Activem GIE i T0IE
Apaga(); // Apaga tots els LED
TXSTAbits.BRGH = 1; // Configuració de velocitat
BAUDCTLbits.BRG16 = 0; // Paràmetre de velocitat de 8 bits
SPBRG = 25; // Velocitat de 9600 baud
TXSTAbits.SYNC = 0; // Comunicació asíncrona
TXSTAbits.TX9 = 0; // Comunicació de 8 bits
Esborra();
while(1){
Polsad = Polsador(); // Llegim els polsadors
if (Polsa == 0){ // Iniciam una partida
Vides=4;
Punt=0;
Delay=250;
}
if (Vides == 0){ // Quan s'acaba una partida, 3 tons i cara trista a la matriu
PORTC = 0b00000000; // Quan Vides==0 apagam els LED
//MELODIA
TocaNota(0, 5, 253, 132, 100); // Valor que correspon aproximadament a mi3
TocaNota(0, 5, 213, 156, 100); // Valor que correspon aproximadament a sol3
TocaNota(0, 3, 239, 209, 100); // Valor que correspon aproximadament a do4
//CARA TRISTA
Sortida[1] = 0x01; // Filera 1
Sortida[0] = 0b11111111; // Vermells
Envia3max(Sortida); // Ho envia al MAX7221
Sortida[1] = 0x02; // Filera 2
Sortida[3] = 0x02;
Sortida[5] = 0x02;
Sortida[0] = 0b11111111; // Vermells
Sortida[2] = 0b01100110; // Verds
Sortida[4] = 0b01100110; // Blaus
Envia3max(Sortida); // Ho envia al MAX7221
Sortida[1] = 0x03; // Filera 3
Sortida[3] = 0x03;
Sortida[5] = 0x03;
Sortida[0] = 0b11111111; // Vermells
Sortida[2] = 0b01100110; // Verds
Sortida[4] = 0b01100110; // Blaus
Envia3max(Sortida); // Ho envia al MAX7221
Sortida[1] = 0x04; // Filera 4
Sortida[0] = 0b11111111; // Vermells
Envia3max(Sortida); // Ho envia al MAX7221
Sortida[1] = 0x05; // Filera 5
Sortida[0] = 0b11111111; // Vermells
Envia3max(Sortida); // Ho envia al MAX7221
Sortida[1] = 0x06; // Filera 6
Sortida[3] = 0x06;
Sortida[5] = 0x06;
Sortida[0] = 0b11111111; // Vermells
Sortida[2] = 0b00111100; // Verds
Sortida[4] = 0b00111100; // Blaus
Envia3max(Sortida); // Ho envia al MAX7221
Sortida[1] = 0x07; // Filera 7
Sortida[3] = 0x07;
Sortida[5] = 0x07;
Sortida[0] = 0b11111111; // Vermells
Sortida[2] = 0b01000010; // Verds
Sortida[4] = 0b01000010; // Blaus
Envia3max(Sortida); // Ho envia al MAX7221
Sortida[1] = 0x08; // Filera 8
Sortida[0] = 0b11111111; // Vermells
Envia3max(Sortida); // Ho envia al MAX7221
Esborra();
//PUNTUACIÓ RÈCORD
r1 = llegir_EEPROM(0); // Rècord
r2 = llegir_EEPROM(1); // Número de control: 8
r3 = llegir_EEPROM(2); // Número de control: 7
r4 = llegir_EEPROM(3); // Número de control: 3
if ((r2==8)&&(r3==7)&&(r4==3)){ // Número de control: 873. Si no hi és posam el rècord a 00
if (p1>r1){
escriu_EEPROM(0, p1); // Escriu rècord
}
}else{ // Número de control: 873. Si no hi és posam el rècord a 00
escriu_EEPROM(0, p1);
escriu_EEPROM(1, 8);
escriu_EEPROM(2, 7);
escriu_EEPROM(3, 3);
}
r1 = llegir_EEPROM(0); // Unitats rècord
p1 = r1;
//MISSATGE FI DE LA PARTIDA + PUNTUACIÓ OBTINGUDA
if(Llengua==2){ // Castellà
EnviaL(' ');
EnviaL('F');
EnviaL('I');
EnviaL('N');
EnviaL(' ');
EnviaL('D');
EnviaL('E');
EnviaL(' ');
EnviaL('P');
EnviaL('A');
EnviaL('R');
EnviaL('T');
EnviaL('I');
EnviaL('D');
EnviaL('A');
Cursor(2, 2); // Posició
EnviaL('P');
EnviaL('U');
EnviaL('N');
EnviaL('T');
EnviaL('U');
EnviaL('A');
EnviaL('C');
EnviaL('I');
EnviaL('O');
EnviaL('N');
EnviaL(' ');
EnviaL(' ');
EnviaL(D+'0'); // Desenes
EnviaL(U+'0'); // Unitats
}else if(Llengua==3){ // Anglès
Cursor(1, 4); // Posició
EnviaL('G');
EnviaL('A');
EnviaL('M');
EnviaL('E');
Cursor(1,10); // Posició
EnviaL('O');
EnviaL('V');
EnviaL('E');
EnviaL('R');
Cursor(2, 5); // Posició
EnviaL('S');
EnviaL('C');
EnviaL('O');
EnviaL('R');
EnviaL('E');
EnviaL(' ');
EnviaL(D+'0'); // Desenes
EnviaL(U+'0'); // Unitats
} else if(Llengua==4){ // Èuscar
Cursor(1, 2); // Posició
EnviaL('J');
EnviaL('O');
EnviaL('K');
EnviaL('O');
EnviaL('A');
Cursor(1,9); // Posició
EnviaL('A');
EnviaL('M');
EnviaL('A');
EnviaL('I');
EnviaL('E');
EnviaL('R');
EnviaL('A');
Cursor(2, 2); // Posició
EnviaL('P');
EnviaL('U');
EnviaL('N');
EnviaL('T');
EnviaL('U');
EnviaL('A');
EnviaL('Z');
EnviaL('I');
EnviaL('O');
EnviaL('A');
EnviaL(' ');
EnviaL(' ');
EnviaL(D+'0'); // Desenes
EnviaL(U+'0'); // Unitats
} else if(Llengua==5){ // Italià
Cursor(1, 3); // Posició
EnviaL('G');
EnviaL('I');
EnviaL('O');
EnviaL('C');
EnviaL('O');
Cursor(1,9); // Posició
EnviaL('F');
EnviaL('I');
EnviaL('N');
EnviaL('I');
EnviaL('T');
EnviaL('O');
Cursor(2, 5); // Posició
EnviaL('P');
EnviaL('U');
EnviaL('N');
EnviaL('T');
EnviaL('I');
EnviaL(' ');
EnviaL(D+'0'); // Desenes
EnviaL(U+'0'); // Unitats
}else{ // Si no es selecciona cap llengua, per defecte en català
EnviaL('F');
EnviaL('I');
EnviaL(' ');
EnviaL('D');
EnviaL('E');
EnviaL(' ');
EnviaL('L');
EnviaL('A');
EnviaL(' ');
EnviaL('P');
EnviaL('A');
EnviaL('R');
EnviaL('T');
EnviaL('I');
EnviaL('D');
EnviaL('A');
Cursor(2, 3); // Posició
EnviaL('P');
EnviaL('U');
EnviaL('N');
EnviaL('T');
EnviaL('U');
EnviaL('A');
EnviaL('C');
EnviaL('I');
EnviaL('O');
EnviaL(' ');
EnviaL(D+'0'); // Desenes
EnviaL(U+'0'); // Unitats
}
_delay(4000000);
while (Polsa!=0){
Apaga();
Esborra();
Polsad = Polsador(); // Llegim els polsadors
if (Polsad==1){ // Català
Llengua=1;
}
if (Polsad==2){ // Castellà
Llengua=2;
}
if (Polsad==3){ // Anglès
Llengua=3;
}
if (Polsad==4){ // Basc
Llengua=4;
}
if (Polsad==5){ // Italià
Llengua=5;
}
if(Llengua==0){ // Llengua==0 inicialment
Cursor(1,2); // Menú per a seleccionar llengüa. Segueix normativa ISO
for (signed char k = 0; k < 14; k++){
EnviaL(menu[k]);
}
Cursor(2,4);
for (signed char k = 0; k < 4; k++){
EnviaL(menu2[k]);
}
Cursor(2,10);
for (signed char k = 0; k < 4; k++){
EnviaL(menu3[k]);
}
}
if(Llengua==1){ // Català
Cursor(1, 4); // Posició
for (signed char k = 0; k < 10; k++){
EnviaL(cat1[k]);
}
Cursor(2, 4); // Posició
for (signed char k = 0; k < 3; k++){
EnviaL(cat2[k]);
}
Cursor(2, 9); // Posició
for (signed char k = 0; k < 5; k++){
EnviaL(cat3[k]);
}
}
if(Llengua==2){ //Castellà
Cursor(1,3); // Posició
for (signed char k = 0; k < 5; k++){
EnviaL(cas1[k]);
}
Cursor(1,11); // Posició
for (signed char k = 0; k < 4; k++){
EnviaL(btn[k]);
}
Cursor(2, 3); // Posició
for (signed char k = 0; k < 4; k++){
EnviaL(cas2[k]);
}
Cursor(2, 10); // Posició
for (signed char k = 0; k < 5; k++){
EnviaL(cat3[k]);
}
}
if(Llengua==3){ // Anglès
Cursor(1,4); // Posició
for (signed char k = 0; k < 5; k++){
EnviaL(eng1[k]);
}
Cursor(1,10); // Posició
for (signed char k = 0; k < 4; k++){
EnviaL(btn[k]);
}
Cursor(2, 5); // Posició
for (signed char k = 0; k < 2; k++){
EnviaL(eng2[k]);
}
Cursor(2, 9); // Posició
for (signed char k = 0; k < 4; k++){
EnviaL(eng3[k]);
}
}
if (Llengua==4){ // Basc
Cursor(1, 3); // Posició
for (signed char k = 0; k < 6; k++){
EnviaL(eus1[k]);
}
Cursor(1,11); // Posició
for (signed char k = 0; k < 4; k++){
EnviaL(btn[k]);
}
Cursor(2, 1); // Posició
for (signed char k = 0; k < 16; k++){
EnviaL(eus2[k]);
}
}
if (Llengua==5){ // Italià
Cursor(1,3); // Posició
for (signed char k = 0; k < 5; k++){
EnviaL(ita1[k]);
}
Cursor(1,11); // Posició
for (signed char k = 0; k < 4; k++){
EnviaL(btn[k]);
}
Cursor(2, 3); // Posició
for (signed char k = 0; k < 3; k++){
EnviaL(cat2[k]);
}
Cursor(2, 8); // Posició
for (signed char k = 0; k < 7; k++){
EnviaL(ita2[k]);
}
}
}
}
while (Vides > 0) { // Mentre tinguem vides el joc funcionarà
Esborra();
//REPRESENTACIÓ DE VIDES (LED)
if (Vides == 4){
PORTC = 0b00001111;
}
if (Vides == 3){
PORTC = 0b00001110;
}
if (Vides == 2){
PORTC = 0b00001100;
}
if (Vides == 1){
PORTC = 0b00001000;
}
//DIBUIX FILA y=7
Sortida[1] = 0x08; // Mantenim dibuixada la fila 0
Sortida[5] = 0x08;
Sortida[0] = 0b00011111; // Vermells
Sortida[4] = 0b11100000; // Blaus
Envia3max(Sortida); // Ho envia al MAX7221
//REPRESENTACIÓ DE PUNTS A LA PANTALLA LCD
U=Punt%10;
D=(Punt-U)/10;
Esborra(); // Esborra la pantalla i posa el cursor a l'inici
EnviaL(D+'0'); // Desenes
EnviaL(U+'0'); // Unitats
//PUNTUACIÓ RÈCORD
if (Punt>p1){
p1=Punt;
}
Urec=p1%10;
Drec=(p1-Urec)/10;
Cursor(2,1);
EnviaL('R');
EnviaL('E');
EnviaL('C');
EnviaL('O');
EnviaL('R');
EnviaL('D');
EnviaL(' ');
EnviaL(Drec+'0'); // Desenes rècord
EnviaL(Urec+'0'); // Unitats rècord
//MOVIMENT DE LA NOTA
y = (y + 1) % 8; // Incrementa y però la manté entre 0 i 7
Cicles=Cicles+1; // delay per als leds baixant la columna
if (Cicles==7){
Cicles=0;
Delay=Delay-5;
}
if (Delay>5){
k=Delay;
}
while(k>1){ // delay variable, va accelerant
_delay(500);
k=k-1;
}
if (y==0){ // Variable x random cada vegada que arribam a y=0
x=rand() & 0b111; // x random per la columna següent
while (x>=5) { // La x ha d'ésser <=5)
x=rand() & 0b111;
}
}
//FUNCIONAMENT DELS POLSADORS
Polsad = Polsador(); // Llegim els polsadors
if (y==7){ // Quan arribam a la darrera fila
if (x==0){ // Si som a la columna 7
if (Polsad==5){ // Si el polsador 5, corresponent a la columna 7 està activat
Punt=Punt+1; // Afegim 1 punt cada vegada que completa una columna
}else{ // Si el polsador no està activat
Vides=Vides-1; // Perdem una vida
TocaNota(0, 7, 239, 105, 20); // El brunzidor toca un do3
}
}
if (x==1){
if (Polsad==4){
Punt=Punt+1;
}else{
Vides=Vides-1;
TocaNota(0, 7, 239, 105, 20);
}
}
if (x==2){
if (Polsad==3){
Punt=Punt+1;
}else{
Vides=Vides-1;
TocaNota(0, 7, 239, 105, 20);
}
}
if (x==3){
if (Polsad==2){
Punt=Punt+1;
}else{
Vides=Vides-1;
TocaNota(0, 7, 239, 105, 20);
}
}
if (x==4){
if (Polsad==1){
Punt=Punt+1;
}else{
Vides=Vides-1;
TocaNota(0, 7, 239, 105, 20);
}
}
}
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 = (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 (PIR1bits.TMR2IF) { // Comprovem que hi ha interrupció per Timer2
PIR1bits.TMR2IF = 0; // Desactiva el bit que indica interrupció pel Timer2
if (control == 0){ // Si estem tocant una nota
flipbit(port, 5); // Inverteix la sortida del brunzidor
PORTC = port; // Ho copia al port C
}
bucles--; // Comptador per a la durada de la nota
if (bucles == 0){ // Si és zero, ja ha passat la durada de la nota
if ((control == 1) || (silenci == 0)){ // Si s'acaba el silenci
T2CONbits.TMR2ON = 0; // Desactiva el Timer2
PIE1bits.TMR2IE = 0; // Desactiva les interrupcions per Timer2
}
if (control == 0){ // Si estem tocant una nota
clrbit(port, 5); // A l'acabar, deixa la sortida desactivada
PORTC = port; // Ho copia al port C
if (silenci > 0){ // Si es preveu silenci
bucles = silenci; // Agafem la durada del silenci
control = 1; // Toca silenci
}
}
}
}
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] = 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("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("movwf PORTB"); // I el posa al port B
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("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 és Clock
asm("movwf PORTB"); // I el posa al port B
asm("banksel _Compta");
asm("decfsz (_Compta&7fh),f"); // Decrementa Compta
asm("goto Bucle"); // Si Compta no és 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 és 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;
}
void EnviaL(char Caracter) {
INTCONbits.GIE = 0; // Desactiva les interrupcions momentàniament
RCSTAbits.SPEN = 1; // Activa comunicació sèrie
TXSTAbits.TXEN = 1; // Activa comunicació
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 comunicació sèrie
TXSTAbits.TXEN = 0; // Desactiva comunicació
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 posició
if (Filera == 2) {
Posicio = 64; // La primera columna de la segona fila és 64;
}
if (Columna > 0 && Columna < 33) { // Comprovem que sigui un valor raonable
Posicio = Posicio + Columna; // Sumem les adreces
Posicio = Posicio - 1; // Restem 1 perquè numera des de 0
}
Posicio = Posicio + 128; // Posa el bit de posicionat a 1
EnviaL(254); // Control de la posició del cursor
EnviaL(Posicio); // Canvia el cursor de lloc
}
void TocaNota(char valPre, char valPos, char valPR2, int numbuc, int numsil) {
// Funció per tocar una nota
while(T2CONbits.TMR2ON) // Si està tocant una nota
; // Esperem que acabi
valPos &= 0b00001111; // Per precaució, posem a zero els bits no emprats
valPre &= 0b00000011; // Per precaució, posem a zero els bits no emprats
T2CON = ((valPos<<3) | valPre); // Ho posa a la configuració del temporitzador
PR2 = valPR2; // Preselecció del Timer2
bucles = numbuc; // Comptador d'iteracions
silenci = numsil; // Durada del silenci
control = 0; // Comencem tocant la nota
PIE1bits.TMR2IE = 1; // Activem les interrupcions per Timer2
T2CONbits.TMR2ON = 1; // Activem el Timer2
}
unsigned char llegir_EEPROM(unsigned char adre) { // Llegeix el contingut de l'EEPROM a la posició indicada per l'adreça
EECON1bits.EEPGD = 0; // Seleccionem EEPROM i no memòria de programa
EEADR = adre; // Adreça que volem llegir
EECON1bits.RD = 1; // Activa la lectura
return EEDATA; // Llegeix i retorna el resultat
}
void escriu_EEPROM(unsigned char adre, unsigned char dada) { // Escriu el valor donat a l'adreça EEPROM indicada
EECON1bits.EEPGD = 0; // Seleccionem EEPROM i no memòria de programa
EEDATA = dada; // Valor que volem escriure
EEADR = adre; // Adreça que volem escriure
EECON1bits.WREN = 1; // Habilita l'escriptura
INTCONbits.GIE = 0; // Desactiva interrupcions
EECON2 = 0x55; // Cal escriure uns valors predeterminats (55h i AAh)
EECON2 = 0xAA; // a EECON2 per activar el procés d'escriptura
EECON1bits.WR = 1; // Activa l'escriptura
while (EECON1bits.WR == 1) // Esperem a que l'escriptura acabi
;
EECON1bits.WREN = 0; // Deshabilitem l'escriptura
INTCONbits.GIE = 1; // Reactivem interrupcions
}

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