Els tres polsadors de l'esquerra de la part inferior serveixen per seleccionar la fila o la columna.
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 #define _XTAL_FREQ 8000000 #define rett 10000
char Matriu[3][3]={{0,0,0},{0,0,0},{0,0,0}};
char Jugador; // Variable que diu quin color està actiu
// Jugador = 0 Apagat
// matriu Vermell
// Jugador = 1 Verd
// Jugador = 2 Blau
char Actiu;
char Sortida[6];
char Polsad;
char x;
char y;
int compta=0;
char victoria=0;
char Polsador(void); char guanyar(); void Ini3max(void); void Apaga(void); void memoria (); void canvijugador(void); void Envia3max(char Valor[6]); void acabaireinicia(); void llegeixienvia(); void TocaNota(char ValPR2, char ValCCPR1L, char ValDC1B);
void main (void) {
OPTION_REG = 0b10000101;
TRISC = 0b00100000;
TRISB = 0;
TRISA = 0xFF;
ANSEL = 0b00000101; // Configura AN0 i AN2 com entrada analògica
ANSELH = 0;
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
PORTC = 0;
CCP1CON = 0b00001100;
CCPR1L = 49;
PIR1bits.TMR2IF = 0; // Desactiva el bit d'interrupció del Timer 2
T2CON = 0b00000011;
PORTB = 0;
Jugador=1;
Actiu=1;
Ini3max();
Apaga();
TMR0 = 139;
INTCON = 0b10100000;
while (1) {
llegeixienvia();
if (victoria!=0){
__delay_ms(1000);
acabaireinicia();
}
if (compta==9){
__delay_ms(500);
acabaireinicia();
}
while (Polsador()==0){
}
if (Polsador()<4){
x=Polsador();
}
_delay(rett);
while (Polsador()!=0){
}
_delay(rett);
while (Polsador()==0){
}
if (Polsador()<4){
y=Polsador();
}
_delay(rett);
while (Polsador()!=0){
}
_delay(rett);
memoria();
victoria= guanyar();
}
}
void interrupt temporit(void) {
INTCONbits.GIE = 0; // Desactiva les interrupcions momentàniament
if (INTCONbits.T0IF) { // Comprovem que hi ha interrupció per Timer 0
TMR0 = 139; // 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
Sortida[0] = 0x00; // Vermell
Sortida[2] = 0x00; // Verd
Sortida[4] = 0x00; // Blau
if (Actiu == 1) { // Si és vermell
Sortida[0] = 0x01; // Vermell activat
}
if (Actiu == 2) { // Si és verd
Sortida[2] = 0x01; // Verd activat
}
if (Actiu == 3) { // Si és blau
Sortida[4] = 0x01; // Blau activat
}
Sortida[1] = 0x0C; // Shutdown mode
Sortida[3] = 0x0C; // Shutdown mode
Sortida[5] = 0x0C; // Shutdown mode
Envia3max(Sortida); // Ho envia al MAX7221
}
INTCONbits.GIE = 1; // Reactiva les interrupcions a l'acabar
}
void memoria (){
for (int j = 2; j >= 0; j--){
for (int i = 2; i >= 0; i--){
if ((x==i+1) && (y==j+1)){
if (Matriu[i][j]==0){ // comprova que estigui apagat
Matriu[i][j]=Jugador;
canvijugador(); // si la casella esta buida canvia el jugador
compta++;
}
}
}
}
}
void canvijugador(void){ //canvia el jugador despres de tirar
if (Jugador==1){
Jugador=2;
} else if (Jugador==2){
Jugador=1;
}
}
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 llegeixienvia(){
int filera=1;
char graella = 0b00100100;
char temp1, temp2;
for (int j = 0; j<=2 ; j++){
char mascara=0b11000000;
Sortida[0]= graella;
Sortida[2]=0;
Sortida[4]=0;
for (int i=0;i<=2;i++){
if (Matriu[i][j]==1){
Sortida[2]=Sortida[2]|mascara;
}
if (Matriu[i][j]==2){
Sortida[4]=Sortida[4]|mascara;
}
mascara = mascara>>3;
}
temp1 = Sortida[2]; //guarda els valors de sortida
temp2 = Sortida[4];
Sortida[0]=graella;
Sortida[1]=filera;
Sortida[3]=filera;
Sortida[5]=filera;
Envia3max(Sortida);
filera++;
Sortida[0] = graella;
Sortida[2] = temp1; //torna a carregar els valors anteriors
Sortida[4] = temp2;
Sortida[1]=filera;
Sortida[3]=filera;
Sortida[5]=filera;
Envia3max(Sortida);
filera++;
if (filera!=9){
Sortida[1]=filera;
Sortida[3]=filera;
Sortida[5]=filera;
Sortida[0]=0b11111111;
Sortida[2]=0b00000000;
Sortida[4]=0b00000000;
Envia3max(Sortida);
filera++;
}
}
}
char guanyar(){
char guanyador =0;
if ((Matriu[0][0]==Matriu[0][1]) && (Matriu[0][1]==Matriu[0][2]) && (Matriu[0][0]!=0)){
guanyador=Matriu[0][0]; // columna 0
}
if ((Matriu[1][0]==Matriu[1][1]) && (Matriu[1][1]==Matriu[1][2]) && (Matriu[1][0]!=0)){
guanyador=Matriu[1][0]; // columna 1
}
if ((Matriu[2][0]==Matriu[2][1]) && (Matriu[2][1]==Matriu[2][2]) && (Matriu[2][0]!=0)){
guanyador=Matriu[2][0]; // columna 2
}
if ((Matriu[0][0]==Matriu[1][0]) && (Matriu[1][0]==Matriu[2][0]) && (Matriu[0][0]!=0)){
guanyador=Matriu[0][0]; // fila 0
}
if ((Matriu[0][1]==Matriu[1][1]) && (Matriu[1][1]==Matriu[2][1]) && (Matriu[0][1]!=0)){
guanyador=Matriu[0][1]; // fila 1
}
if ((Matriu[0][2]==Matriu[1][2]) && (Matriu[1][2]==Matriu[2][2]) && (Matriu[0][2]!=0)){
guanyador=Matriu[0][2]; // fila 2
}
if ((Matriu[0][0]==Matriu[1][1]) && (Matriu[1][1]==Matriu[2][2]) && (Matriu[0][0]!=0)){
guanyador=Matriu[0][0]; // diagonal
}
if ((Matriu[2][0]==Matriu[1][1]) && (Matriu[1][1]==Matriu[0][2]) && (Matriu[2][0]!=0)){
guanyador=Matriu[2][0]; // diagonal invertida
}
return guanyador;
}
void acabaireinicia (){
char tot= 0b11111111;
if (victoria!=0) {
for (int j = 1; j<=8 ; j++){
Sortida[0]=0;
Sortida[2]=0;
Sortida[4]=0;
if (victoria==1){
Sortida[2]=tot;
}
if (victoria==2){
Sortida[4]=tot;
}
Sortida[1]=j;
Sortida[3]=j;
Sortida[5]=j;
Envia3max(Sortida);
}
TocaNota(189, 95, 0); // mi
__delay_ms(10);
TocaNota(189, 95, 0); // mi
__delay_ms(10);
TocaNota(178, 89, 2); // fa
__delay_ms(10);
TocaNota(158, 79, 2); // sol
__delay_ms(10);
TocaNota(158, 79, 2); // sol
__delay_ms(10);
TocaNota(178, 89, 2); // fa
__delay_ms(10);
TocaNota(189, 95, 0); // mi
__delay_ms(10);
TocaNota(212, 106, 2); // re
__delay_ms(10);
TocaNota(238, 119, 2); // do
__delay_ms(10);
TocaNota(238, 119, 2); // do
__delay_ms(10);
TocaNota(212, 106, 2); // re
__delay_ms(10);
TocaNota(189, 95, 0); // mi
__delay_ms(10);
TocaNota(189, 95, 0); // mi
TocaNota(189, 95, 0); // mi
__delay_ms(5);
TocaNota(212, 106, 2); // re
__delay_ms(5);
TocaNota(212, 106, 2); // re
TocaNota(212, 106, 2); // re
TocaNota(212, 106, 2); // re
__delay_ms(5);
TocaNota(189, 95, 0); // mi
__delay_ms(10);
TocaNota(189, 95, 0); // mi
__delay_ms(10);
TocaNota(178, 89, 2); // fa
__delay_ms(10);
TocaNota(158, 79, 2); // sol
__delay_ms(10);
TocaNota(158, 79, 2); // sol
__delay_ms(10);
TocaNota(178, 89, 2); // fa
__delay_ms(10);
TocaNota(189, 95, 0); // mi
__delay_ms(10);
TocaNota(212, 106, 2); // re
__delay_ms(10);
TocaNota(238, 119, 2); // do
__delay_ms(10);
TocaNota(238, 119, 2); // do
__delay_ms(10);
TocaNota(212, 106, 2); // re
__delay_ms(10);
TocaNota(189, 95, 0); // mi
__delay_ms(10);
TocaNota(212, 106, 2); // re
TocaNota(212, 106, 2); // re
__delay_ms(5);
TocaNota(238, 119, 2); // do
__delay_ms(5);
TocaNota(238, 119, 2); // do
TocaNota(238, 119, 2); // do
TocaNota(238, 119, 2); // do
__delay_ms(1000);
}
for (int j = 2; j >= 0; j--){
for (int i = 2; i >= 0; i--){
Matriu[i][j]=0;
}
}
llegeixienvia();
compta=0;
}
void Envia3max(char Valor[6]) { // Envia un joc de valors als tres MAX7221
INTCONbits.GIE = 0; // Desactiva les interrupcions momentàniament
char Port = 0; // Variable on guardem l'estat del port B
char Temp; // Variable temporal
for (int j = 5; j >= 0; j--){ // Hem d'enviar 6 bytes
for (int 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.GIE = 1; // Reactiva les interrupcions a l'acabar
}
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 (int j = 0; 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
}
}
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(25); // Retard de 0,2 s
TRISC = 0b00100000; // Posem RC5 (sortida del PWM) com a entrada
// O sigui, silenci
}

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