En aquest cas hi ha un jugador que intenta enfonsar els vaixells que ha situat la màquina. El programa situa quatre vaixells de manera aleatòria:
| Mida | Nombre de vaixells |
| 4 caselles | 1 |
| 3 caselles | 1 |
| 2 caselles | 1 |
| 4 caselles en forma l'ela | 1 |
Els colors dels LED de la matriu representen:
| Color | Significat |
| Apagat | Casella sobre la que no s'ha disparat |
| Blau | Aigua |
| Vermell | Tocat |
| Verd | Posició del cursor |
Els polsadors de la part inferior serveixen per moure el cursor i per disparar sobre la casella actual, segons el següent ordre:
| Polsador | Funció |
| 1 | Esquerra |
| 2 | Dreta |
| 3 | Amunt |
| 4 | Avall |
| 5 | Disparar |
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> #define _XTAL_FREQ 4000000 // La freqüència del rellotge és 4 MHz
char Port; // Gestió del port a la funció Envia_max
char Compta; // Comptador de bits a la funció Envia_max
char Sortida[6]; // Valors a enviar al MAX7221 (48 bits)
char Sorti[6]; // Valors a enviar al MAX7221 des de la interrupció
char Actiu; // Variable que diu quin color està actiu
// Actiu = 0 Apagat
// Actiu = 1 Vermell
// Actiu = 2 Verd
// Actiu = 3 Blau
char Polsad; // Polsador que s'ha premut
char figura[8]; // Aquí guardarem el dibuix (8 fileres) de les aigües
char vaixells[8]; // Aquí guardarem el dibuix (8 fileres) dels vaixells
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)
// Y = 0 és la fila de dalt
char mirar = 1; // Espera que es deixi anar el polsador
char conta_vaixells[4]={0,0,0,0}; // Nombre de tocs que ha rebut cada vaixell
char pok=0; // Diu quin vaixell s'ha tocat
char led_vaixells=0; // Diu els LED que s'han d'il·luminar
char led_matriu=1; // Marca la posició que s'ataca
int punts=0; // Comptador de la puntuació
signed char graella1[26]; // Guarda la posició X i Y del vaixell
signed char dx[4]= { 1, -1, 0, 0}; // Per escollir la direcció X del vaixell quan es crea
signed char dy[4]= { 0, 0, 1, -1}; // Per escollir la direcció Y del vaixell quan es crea
// Missatges de text que s'envien a la pantalla (es guarden a la memòria de dades)
const unsigned char Tocat[5] __at(0x260) = {84, 79, 67, 65, 84};
const unsigned char Enfonsat[8] __at(0x265) = {69, 78, 70, 79, 78, 83, 65, 84};
const signed char Benvingut[15] __at(0x273)={66, 69, 78, 86, 73, 78, 71, 85, 84, 80, 82, 69, 77, 32, 53};
const unsigned char Aigua[5] __at(0x288) = {65, 73, 71, 85, 65};
const signed char Victoria[11] __at(0x293) = {72, 65, 83, 32, 71, 85, 65, 78, 89, 65, 84};
const signed char Punts[7] __at(0x304) = {80, 85, 78, 84, 83, 58, 32};
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 char Polsador(void); // Funció de lectura dels polsadors char posok (char x, char y); // Diu si s'ha tocat vaixell i quin // Escriuen missatges per pantalla i que soni el brunzidor void aigua (void); void tocat (void); void enfonsat (void); void inici (void); void victoria(void); // Funcions auxiliars per obrir i tancar ports void obreportsbrun(void); void tancaportsbrun(void); void creavaixells(void); // Crea una distribució de vaixells aleatòria void polsador3(void); // Ataca la posició que vulguis void polsador3toc(char x); // Difèrencia entre victòria, enfonsat i tocat i encén els LED individuals 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 void score (void); // Ensenya la puntuació per pantalla unsigned char llegir_MemProg(unsigned short adre); // Llegeix de la memòria del programa void TocaNota(char ValPR2, char ValCCPR1L, char ValDC1B); // Fa sonar el brunzidor
void main (void) {
OPTION_REG = 0b10000101; // Configuració de Timer0
// Com a temporitzador basat en rellotge
// 101 - Factor d'escala de 64
// I resistències de pull-up desactivades (valor per defecte)
TRISC = 0; // Tot el port C és de sortida
TRISB = 0; // Tot el port B és de sortida
TRISA = 0xFF; // Tot el port A és d'entrada
ANSEL = 0b00000101; // Configura AN0 i AN2 com entrada analògica
ANSELH = 0; // Desactiva les altres entrades analògiques
PORTC = 0; // Inicialitza a 0 el port C
PORTB = 0; // Inicialitza a 0 el port B
ADCON1 = 0b00010000; // Posa el conversor a 1/8 de la freqüència
ADCON0 = 0b00001001; // Activa el conversor A/D connectat a AN2
// amb el resultat justificat per l'esquerra
Ini3max();
Actiu = 1; // Activa el color vermell
TMR0 = 150; // Presselecció de 150
INTCON = 0b10100000; // 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
RCSTAbits.SPEN = 1; // Activa comunicació sèrie
TXSTAbits.TXEN = 1; // Activa comunicació
for (char k = 0; k < 8; k++){
figura[k] = 0; // Comencem amb tots els LED apagats
vaixells[k]=0;
}
__delay_ms(1000);
inici();
while (Polsador()!=5){
; // Posa el joc en standby fins que s'apreta el botó d'engegat
}
srand(TMR0); // Defineix la llavor aleatòria en funció del temps que triga el usuari
creavaixells();
Esborra();
__delay_ms(300);
while (1){
// Mirem els polsadors
// Un cop s'ha fet l'acció del polsador, no es tornarà a fer fins que es detecti que s'han deixat anar
Polsad = Polsador();
if (mirar == 1){
if (Polsad == 1) { // Si s'ha premut el polsador 1 (es mou cap a la esquerra)
x = (x + 1) % 8; // Incrementa x però la manté entre 0 i 7
mirar = 0;
}
if (Polsad == 2) { // Si s'ha premut el polsador 2 (es mou cap a la dreta)
if (x!=0){
x = x - 1;
} else {
x=7;
}
mirar = 0;
}
if (Polsad == 3){ // Si s'ha premut el polsador 3 (es mou cap a dalt)
if (y!=0){
y = y - 1;
} else {
y=7;
}
mirar = 0;
}
if (Polsad == 4) { // Si s'ha premut el polsador 4 (es mou cap a la baix)
y = (y + 1) % 8; // Incrementa y però la manté entre 0 i 7
mirar = 0;
}
if (Polsad == 5) { // Si s'ha premut el polsador 5 (ataca))
// Invertim el LED corresponent (vermell= tocat, blau=aigua)
polsador3();
}
if (Polsad == 6) { // Si s'ha premut el polsador 0 (es reinicia)
for (char k = 0; k < 8; k++){
figura[k] = 0; // Esborrem la figura
vaixells[k]=0; // Comencem amb tots els LED apagats
}
PORTC=0;
// Reinicia totes les variables i crea una nova distribució de vaixells
led_vaixells=0;
for(char i = 0; i < 4; ++i){
conta_vaixells[i] = 0;
}
x=0;
y=0;
punts=0;
mirar = 0;
creavaixells();
}
} else {
if (Polsad == 0) { // Si no s'ha premut cap polsador (o dos a la vegada)
mirar = 1;
}
}
score();
// Anem a mostrar la figura actual a la matriu de LED
for (char k = 0; k < 8; k++){
char mascara;
Sortida[0] = vaixells[k]; // Vermells
Sortida[2] = 0; // Verds
Sortida[4] = figura[k]; // Blaus
// El cursor es mostra verd, independentment del punt
if (y == k){ // Si estem a la filera del cursor
mascara = (1 << x);
Sortida[0] = Sortida[0] & ~mascara; // apaga vermell
Sortida[2] = Sortida[2] | mascara; // encen verd
Sortida[4] = Sortida[4] & ~mascara; // apaga blau
}
Sortida[1] = k+1; // Filera
Sortida[3] = k+1;
Sortida[5] = k+1;
Envia3max(Sortida);
__delay_ms(1);
}
}
}
void __interrupt() temporit(void){
if (INTCONbits.T0IF){ // Comprovem que hi ha interrupció per Timer 0
TMR0 = 150;
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();
}
}
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
}
char posok (char x, char y){
// c1=vaixell L, c2=vaixell 2, c3=vaixell 3, c4=vaixell 4
for (char k = 0; k < 13; k++){
if (x==graella1[2*k] && y==graella1[2*k+1]){ //Retorna quin vaixell hem tocat
if (k<=3){
return 1;
}
if (k>= 4 && k <= 7){
return 4;
}
if (k>= 8 && k<=10){
return 3;
}
if (k>=11){
return 2;
}
}
}
return 0;
}
char posokay(signed char i,signed char j, char v){
if (i < 0 || i > 7 || j < 0 || j >7)
return 0; //Comprova que la casella esta dins la matriu
if (v != 0) {
for (char k = 0; k < 13; ++k) { //Comprova que no estigui tocant o en diagonal de cap vaixell ja col·locat
if ((graella1[2 * k] == i) && (graella1[2 * k + 1] == j))
return 0;
if ((graella1[2 * k] == i) && (graella1[2 * k + 1] == (j + 1)))
return 0;
if ((graella1[2 * k] == i) && (graella1[2 * k + 1] == (j - 1)))
return 0;
if ((graella1[2 * k] == (i + 1)) && (graella1[2 * k + 1] == j))
return 0;
if ((graella1[2 * k] == (i - 1)) && (graella1[2 * k + 1] == j))
return 0;
if ((graella1[2 * k] == (i - 1)) && (graella1[2 * k + 1] == (j - 1)))
return 0;
if ((graella1[2 * k] == (i - 1)) && (graella1[2 * k + 1] == (j + 1)))
return 0;
if ((graella1[2 * k] == (i + 1)) && (graella1[2 * k + 1] == (j - 1)))
return 0;
if ((graella1[2 * k] == (i + 1)) && (graella1[2 * k + 1] == (j + 1)))
return 0;
}
}
return 1;
}
void creavaixells(void){
signed char x1, y1, d; //Seran las variables que farem servir per col·locar els vaixells
char found = 0; //Variable que indicarà si es pot col·locar el vaixell
while (found == 0) { //Posem el vaixell en forma de ela
for(char i = 0; i < 26; ++i)
graella1[i] = -2;
x1 = rand() % 8;
y1 = rand() % 8;
d = rand() % 4;
while (posokay(x1, y1, 0) == 0 || posokay(x1 + dx[d], y1 + dy[d], 0) == 0) {
x1 = rand() % 8;
y1 = rand() % 8;
d = rand() % 4;
}
for(char i = 0; i < 2; ++i){
graella1[2*i] = x1 + i*dx[d];
graella1[1+2*i] = y1 + i*dy[d];
}
signed char xi = x1 + dx[d];
signed char yi = y1 + dy[d];
d = (d + 2) % 4;
if (posokay(xi + dx[d], yi + dy[d], 0) == 1 && posokay(xi + dx[d] * 2, yi + dy[d] * 2, 0)==1) {
found = 1;
for(char i = 0; i < 2; ++i){
graella1[4+2*i] = xi + (i+1)*dx[d];
graella1[5+2*i] = yi + (i+1)*dy[d];
}
}
}
// Posem el vaixell de quatre posicions
while (posokay(x1, y1, 1) == 0 || posokay(x1 + dx[d], y1 + dy[d], 1)== 0 || posokay(x1 + 2 * dx[d], y1 + 2 * dy[d], 1) == 0 || posokay(x1 + 3 * dx[d], y1 + 3 * dy[d], 1)==0) {
x1 = rand() % 8;
y1 = rand() % 8;
d = rand() % 4;
}
for(char i = 0; i <4; ++i){
graella1[8+2*i] = x1 + i*dx[d];
graella1[9+2*i] = y1 + i*dy[d];
}
// Posem el vaixell de tres posicions
while (posokay(x1, y1, 2) == 0 || posokay(x1 + dx[d], y1 + dy[d], 2) == 0 || posokay(x + 2 * dx[d], y + 2 * dy[d], 2) == 0) {
x1 = rand() % 8;
y1 = rand() % 8;
d = rand() % 4;
}
for(char i = 0; i <3; ++i){
graella1[16+2*i] = x1 + i*dx[d];
graella1[17+2*i] = y1 + i*dy[d];
}
//Posem el vaixell de dos posicions
while (posokay(x1, y1, 3) == 0 || posokay(x1 + dx[d], y1 + dy[d], 3) == 0) {
x1 = rand() % 8;
y1 = rand() % 8;
d = rand() % 4;
}
for(char i = 0; i <2; ++i){
graella1[22+2*i] = x1 + i*dx[d];
graella1[23+2*i] = y1 + i*dy[d];
}
}
// Si no utilitzem aquestes funcions el brunzidor no se sent
void obreportsbrun(void){
TRISC = 0b00100000; // Definim com volem les E/S del port C
// RC5 (sortida del PWM), de moment, com a entrada
CCP1CON = 0b00001100; // Configura el PWM, bits P1M (bits 7-6) a 00 mode senzill
// DC1B = 11 (bits 5-4) els dos bits de menys pes són 0
// CCP1M = 11xx en mode senzill els bit 0 i 1 no afecten
// Ho posa com a configuració del PWM
PIR1bits.TMR2IF = 0; // Desactiva el bit d'interrupció del Timer 2
T2CON = 0b00000011;
TMR0 = 0;
}
void tancaportsbrun(void){
TRISC = 0;
CCP1CON = 0;
T2CON = 0;
TMR0 = 150;
}
void tocat (void){
Esborra(); // Esborra la pantalla i posa el cursor a l'inici
unsigned short adressa = 0x260; // Variable de 16 bits per a l'adreça
for(char k = 0; k < 5; ++k){ //Enviem el missatge a pantalla
EnviaL(llegir_MemProg(adressa + k));
}
obreportsbrun(); //Fem sonar el brunzidor
TocaNota(141, 71, 0);
TocaNota(118, 59, 2);
tancaportsbrun();
}
void enfonsat (void){
Esborra(); // Esborra la pantalla i posa el cursor a l'inici
unsigned short adressa = 0x265; // Variable de 16 bits per a l'adreça
for(char k = 0; k < 8; ++k){ //Enviem el missatge a pantalla
EnviaL(llegir_MemProg(adressa + k));
}
obreportsbrun(); //Fem sonar el brunzidor
TocaNota(189, 95, 0);
TocaNota(189, 95, 0);
TocaNota(189, 95, 0);
TocaNota(212, 106, 2);
TocaNota(189, 95, 0);
tancaportsbrun();
}
void aigua (void){
Esborra(); // Esborra la pantalla i posa el cursor a l'inici
unsigned short adressa = 0x288; // Variable de 16 bits per a l'adreça
for(char k = 0; k < 5; ++k){ //Enviem el missatge a pantalla
EnviaL(llegir_MemProg(adressa + k));
}
obreportsbrun(); //Fem sonar el brunzidor
TocaNota(224, 112, 2);
TocaNota(238, 119, 2);
tancaportsbrun();
}
void victoria (void){
Esborra(); // Esborra la pantalla i posa el cursor a l'inici
unsigned short adressa = 0x293; // Variable de 16 bits per a l'adreça
for(char k = 0; k < 11; ++k){ // Enviem el missatge a pantalla
EnviaL(llegir_MemProg(adressa + k));
}
obreportsbrun(); // Fem sonar el brunzidor
TocaNota(168, 84, 2);
TocaNota(141, 71, 0);
TocaNota(212, 106, 2);
TocaNota(126, 63, 2);
TocaNota(118, 59, 2);
tancaportsbrun();
}
void inici (void){
Esborra(); // Esborra la pantalla i posa el cursor a l'inici
unsigned short adressa = 0x273; // Variable de 16 bits per a l'adreça
for(char k = 0; k < 15; ++k){ //Enviem el missatge a pantalla
EnviaL(llegir_MemProg(adressa + k));
if(k == 8)
Cursor(2, 1);
if(k == 10)
Cursor(2, 3);
}
}
void score (void){
Esborra(); // Esborra la pantalla i posa el cursor a l'inici
Cursor(1,1);
unsigned short adressa = 0x304; // Variable de 16 bits per a l'adreça
for(char k = 0; k < 7; ++k){ //Enviem el missatge a pantalla
EnviaL(llegir_MemProg(adressa + k));
}
unsigned char Valor=punts; // Valor a convertir (dos bytes, de 0 a 65535)
char Digits[3]; // Variable amb el número dígit a dígit
// Digits[0] són les unitats
if (punts<0){ // Si els punts son negatius enviar '-' a pantalla
EnviaL('-');
Valor=-punts;
}
if (punts==0){ // Si tenim 0 punts
EnviaL('0');
}
for (signed char j = 0; j < 3; j++){ // Guardem els tres dígits
Digits[j] = Valor % 10 +'0';
Valor = Valor / 10;
}
unsigned char c=0; //Si té menys de tres dígits començar per el primer diferent de zero
for(char k = 0; k < 3; k++){
if (Digits[2-k]!='0'){
c=1;
}
if (c==1){ // Envia la puntuació a pantalla
EnviaL(Digits[2-k]);
}
}
}
void polsador3(){
led_matriu=1;
for (signed char k=0;k<x;k++){ // Marquem la casella
led_matriu=led_matriu*2;
}
if ((vaixells[y]!=(vaixells[y]|led_matriu))&(figura[y]!=(figura[y]|led_matriu))){
pok=posok(x,y);
if (pok!=0)
polsador3toc(pok); // Si hem tocat un vaixell anem a aquesta funció
else { //Si hem tocat aigua
figura[y] = figura[y]|led_matriu; // Actualitzem la matriu
aigua();
punts-=5;
__delay_ms(500); //delay de 4 segons aprox
Esborra();
}
}
mirar = 0;
}
void polsador3toc(char j){
conta_vaixells[j-1]++;
// Mirem si hem enfonsat, encenem el Led corresponent i actualitzem la puntuació
if((j==1 && conta_vaixells[0]==4)||(j==2 && conta_vaixells[1]==2)||(j==3 && conta_vaixells[2]==3)||(j==4 && conta_vaixells[3]==4)){
if((j-1) == 0) {
led_vaixells=led_vaixells|0b00000001;
punts+=25;
}
if((j-1) == 1){
led_vaixells=led_vaixells|0b00000010;
punts+=35;
}
if((j-1) == 2){
led_vaixells=led_vaixells|0b00000100;
punts+=30;
}
if((j-1) == 3){
led_vaixells=led_vaixells|0b00001000;
punts+=20;
}
PORTC=led_vaixells;
enfonsat();
} else { //Si només hem tocat
tocat();
punts+=10;
}
__delay_ms(500); // delay de 4 segons aprox
Esborra();
vaixells[y] = vaixells[y]|led_matriu; // Actualitzem la matriu
if (led_vaixells==0b00001111){ // Si hem enfonsat els 4 vaixells
victoria();
__delay_ms(1500); // delay de 4 segons aprox
score();
__delay_ms(1500); // delay de 4 segons aprox
Esborra();
Polsad=6;
}
}
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 = 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 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
}
if (PORTAbits.RA3==0){
Pols=6;
}
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 ValPR2, char ValCCPR1L, char ValDC1B) {
TRISC = 0b00100000; // Definim com volem les E/S del port C
// RC5 (sortida del PWM), de moment, com a entrada
PR2 = ValPR2; // Carrega PR2
CCP1CON = CCP1CON & 0b11001111; // Posa a zero els bits que corresponen a DC1B
ValDC1B = ValDC1B % 4; // DC1B va de 0 a 3
ValDC1B = ValDC1B * 16; // Desplaça els bits a la posició que els correspon a CCP1CON
CCP1CON = CCP1CON | ValDC1B; // Coloca DC1B al seu lloc
CCPR1L = ValCCPR1L; // Carrega CCPR1L, registre que ens dona l'amplada de tON
PIR1bits.TMR2IF = 0; // Desactiva el bit d'interrupció del Timer 2
T2CON = 0b00000111; // Configura el Timer 2
// bits T2KCPS (bits 1-0) a 11 prescalat de 16
// bit 2 (TMR2ON) a 1, Timer activat
// Postscaler TOUTPS (bits 6-3) no afecten al PWM
while (PIR1bits.TMR2IF == 0) // Espera l'activació del bit d'interrupció del Timer 2
; // Esperem
TRISC = 0b00000000; // Posem RC5 (sortida del PWM) com a sortida
__delay_ms(200); // Retard de 0,2 s
TRISC = 0b00100000; // Posem RC5 (sortida del PWM) com a entrada
// O sigui, silenci
__delay_ms(200); // Retard de 0,2 s
}

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