Programació en C del PIC 16F690

Referència Trucs Perifèrics   Recursos CITCEA
Tutorial Exemples Projectes   Inici

Rellotge

Programa del grup 5

En aquest cas, tenim un rellotge que toca els quarts i fa sonar una melodia a les hores en punt. A més, la matriu de LED s'encén d'un color diferent en cada un dels quarts; així, l'usuari té una indicació visual cada cop que passa un quart. No van arribar a implementar cap sistema per posar el rellotge en hora i, per tant, cal enviar el programa cada cop que es vol fer un canvi.

Aquest grup va tenir problemes tècnics cap a final del quadrimestre i no va tenir temps de millorar el programa. La part de la matru de LED i el brunzidor es podrien simplificar significativament.

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
#define FiTimer0 INTCONbits.T0IF  // Li assigna un nom al bit que indica el final del Timer 0
#define FiTimer1 PIR1bits.TMR1IF  // Li assigna un nom al bit que indica el final del Timer 1
#define flipbit(var, bit) ((var) ^= (1<<(bit)))
#define _XTAL_FREQ  4000000  // La freqüència del rellotge és 4 MHz
unsigned char Valor=1;  // Variable de 8 bits sense signe (0 a 255)
unsigned char Compta=0;  // Variable de 8 bits sense signe (0 a 255)
char segdec=5;  //Conta les decenes dels segons
char seguni=5;  //Conta les unitats dels segons
char mindec=4;  //Conta les decenes els minuts
char minuni=4;  //Conta les unitats els minuts
char horesdec=0;  //Conta les decenes de les hores
char horesuni=9;  //Conta les unitats de les hores
char diadec=2;
char diauni=8;
char mesdec=0;
char mesuni=2;
char anymil=2;
char anycen=0;
char anydec=2;
char anyuni=4;
char pantalla=0;
char tocat=0;
char Port;  // Gestió del port a la funció Envia_max
char Compta1;  // 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 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 ValPR2, char ValCCPR1L, char ValDC1B);
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) {
  // Configuració d'entrades i sortides
  CCP1CON = 0b00001100;  // Configura el PWM, bits P1M (bits 7-6) a 00 mode senzill
  T2CON = 0b00000011;  // Configura el Timer 2
  TRISAbits.TRISA0 = 1;  // La pota RA0 és d'entrada
  ANSELH = 0;  
  ADCON1 = 0b00010000;  // Posa el conversor a 1/8 de la freqüència
  ADCON0 = 0b00000001;  // Activa el conversor connectat a AN0
                        // amb el resultat justificat per l'esquerra
  // Configuració d'interrupció
  INTCON = 0b00100000;  // Habilitem la interrupció per Timer0
                        // i deshabilitem les altres
                        // Configuració del Timer 0
  FiTimer1 = 0;  // Aquest bit es posarà a 1 quan el temporitzador acabi
                 // cal desactivar-lo des del programa
  OPTION_REG = 0b10000101;  // Configuració de Timer0
  TMR1H = 231;  // Inicialitza el Timer1
  TMR1L = 150;
  T1CON = 0b00110001;  // Configuració de Timer1
                       // Com a temporitzador basat en rellotge
                       // 110 - Factor d'escala de 128
                       // I resistències de pull-up desactivades (valor per defecte)
  ANSEL = 0b00000101;  // Configura AN0 i AN2 com entrada analògica
  TRISB = 0;  // Tot el port B és de sortida
  __delay_ms(2000);  // Esperem que arrenqui la pantalla
  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ó
  Esborra();  // Esborra la pantalla i posa el cursor a l'inici
  INTCONbits.GIE = 1;  // Habilitem les interrupcions a nivell general
  PIE1bits.TMR1IE =1;
  INTCONbits.PEIE =1;
  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
  __delay_ms(1400);  // Retard d'1,4 s teòrics
  Ini3max();  // Inicialitza els tres MAX7221
  Apaga();  // Apaga tots els LED
  __delay_ms(1400);  // Retard d'1,4 s teòrics
  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
  Cursor(2,7);
  EnviaL('.');
  Cursor(2,10);
  EnviaL('.');
  Cursor(1,6);
  EnviaL('/');
  Cursor(1,9);
  EnviaL('/');
  while (1)  {
    // Inici del bucle de programa
    if ((anymil*1000 + anycen*100 + anydec*10 + anyuni)<1970){
      Esborra();  // Esborra la pantalla i posa el cursor a l'inici
      EnviaL('E');
      EnviaL('R');
      EnviaL('R');
      EnviaL('O');
      EnviaL('R');
      break;
    }
    if (pantalla ==1){
      pantalla =0;
      if (seguni == 10) {
        seguni=0;
        segdec++;
      }
      Cursor(2,12);
      EnviaL(seguni + '0');  // Lletra
      if (segdec == 6) {
        segdec=0;
        minuni++;
      }
      Cursor(2,11);
      EnviaL(segdec + '0');  // Lletra
      if (minuni == 10) {
         minuni=0;
         mindec++;
      }
      Cursor(2,9);
      EnviaL(minuni + '0');  // Lletra
      if (mindec == 6) {
        mindec=0;
        horesuni++;
      }
      Cursor(2,8);
      EnviaL(mindec + '0');  // Lletra
      if (horesuni == 10) {
        horesuni=0;
        horesdec++;
      }
      Cursor(2,6);
      EnviaL(horesuni + '0');  // Lletra
      if (horesdec == 2 & horesuni==4) {
        horesdec=0;
        horesuni=0;
        diauni++;
      }
      Cursor(2,5);
      EnviaL(horesdec + '0');  // Lletra
      if (diadec == 3){
        if (diauni==2 && mesdec==0 && (mesuni==1 || mesuni==3 || mesuni==5 || mesuni==7 || mesuni==8 )){
          diauni=1;
          diadec=0;
          mesuni++;
        }
      }
      if (diadec == 3){    
        if (diauni==1 && mesdec==0 && (mesuni==4 || mesuni==6 || mesuni==9 )){
          diauni=1;
          diadec=0;
          mesuni++;
        }
      }
      if (diadec == 3){
        if (diauni==2 && mesdec==1 && (mesuni==0 || mesuni==2)){
          diauni=1;
          diadec=0;
          mesuni++;
        }
      }
      if (diadec == 3){
        if (diauni==1 && mesdec==1 && mesuni==1){
          diauni=1;
          diadec=0;
          mesuni++;
        }
      }
      if (mesuni==2 && mesdec==0){
        if (((anymil*1000 + anycen*100 + anydec*10 + anyuni) % 4)==0){
          if (((anymil*1000 + anycen*100 + anydec*10 + anyuni) % 100)==0){
            if (((anymil*1000 + anycen*100 + anydec*10 + anyuni) % 400)==0){
              if (diadec==3 && diauni==0){
                diauni=1;
                diadec=0;
                mesuni++;
              }
            } else {
              if (diadec==2 && diauni==9){
                diauni=1;
                diadec=0;
                mesuni++;
              }
            }
          } else {
            if (diadec==3 && diauni==0){
              diauni=1;
              diadec=0;
              mesuni++;
            }
          }
        } else {
          if (diadec==2 && diauni==9){
            diauni=1;
            diadec=0;
            mesuni++;
          }
        }   
      }
      Cursor(1,4);
      EnviaL(diadec + '0');
      if (diauni == 10) {
        diauni=0;
        diadec++;
      }
      Cursor(1,5);
      EnviaL(diauni + '0');
      if (mesuni == 10) {
        mesuni=0;
        mesdec++;
      }
      Cursor(1,8);
      EnviaL(mesuni + '0');
      if (mesdec == 1 && mesuni==3) {
        mesuni=1;
        mesdec=0;
        diauni=1;
        diadec=0;
        anyuni++;
      }
      Cursor(1,7);
      EnviaL(mesdec + '0');
      if (anyuni == 10) {
        anyuni=0;
        anydec++;
      }
      Cursor(1,13);
      EnviaL(anyuni + '0');
      if (anydec == 10) {
        anydec=0;
        anycen++;
      }
      Cursor(1,12);
      EnviaL(anydec + '0');
      if (anycen == 10) {
        anycen=0;
        anymil++;
      }
      Cursor(1,11);
      EnviaL(anycen + '0');
      Cursor(1,10);
      EnviaL(anymil + '0');
    }
    if ((horesdec*10+horesuni)>=8 &&(horesdec*10+horesuni)<=22 ){
      if (mindec==0 && minuni==0 && segdec==0 && seguni==0) {
        TRISC = 0b00100000;  // Definim com volem les E/S del port C
                             // RC5 (sortida del PWM), de moment, com a entrada
        PORTC = 0;  // Desactiva les sortides del port C
                    // DC1B = 00 (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
                              // bits T2KCPS (bits 1-0) a 11 prescalat de 16
                              // bit 2 (TMR2ON) a 0, Timer aturat
                              // Postscaler TOUTPS (bits 6-3) no afecten al PWM
        tocat++;
        TocaNota(238, 119, 2);  // Valor que correspon aproximadament a do3
        TocaNota(212, 106, 2);  // Valor que correspon aproximadament a re3
        TocaNota(189, 95, 0);  // Valor que correspon aproximadament a mi3
        TocaNota(178,89,2);
        TocaNota(158,79,2); 
        TocaNota(141,71,0); 
        TocaNota(126,63,2); 
        TocaNota(118,59,2);
        Sortida[1] = 0x01;  // Filera 1
        Sortida[3] = 0x01;
        Sortida[5] = 0x01;
        Sortida[0] = 0b11111111;  // Vermells
        Sortida[2] = 0b11111111;  // Verds
        Sortida[4] = 0b00000000;  // Blaus
		Envia3max(Sortida);  // Ho envia al MAX7221
        Sortida[1] = 0x02;  // Filera 2
        Sortida[3] = 0x02;
        Sortida[5] = 0x02;
        Sortida[0] = 0b11111111;  // Vermells
        Sortida[2] = 0b11111111;  // 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] = 0b11111111;  // 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] = 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] = 0b11111111;  // Vermells
        Sortida[2] = 0b11111111;  // Verds
        Sortida[4] = 0b00000000;  // Blaus
        Envia3max(Sortida);  // Ho envia al MAX7221
        Sortida[1] = 0x06;  // Filera 6
        Sortida[3] = 0x06;
        Sortida[5] = 0x06;
        Sortida[0] = 0b11111111;  // Vermells
        Sortida[2] = 0b11111111;  // Verds
        Sortida[4] = 0b00000000;  // Blaus
        Envia3max(Sortida);  // Ho envia al MAX7221
        Sortida[1] = 0x07;  // Filera 7
        Sortida[3] = 0x07;
        Sortida[5] = 0x07;
        Sortida[0] = 0b11111111;  // Vermells
        Sortida[2] = 0b11111111;  // Verds
        Sortida[4] = 0b00000000;  // Blaus
        Envia3max(Sortida);  // Ho envia al MAX7221
        Sortida[1] = 0x08;  // Filera 8
        Sortida[3] = 0x08;
        Sortida[5] = 0x08;
        Sortida[0] = 0b11111111;  // Vermells
        Sortida[2] = 0b11111111;  // Verds
        Sortida[4] = 0b00000000;  // Blaus
        Envia3max(Sortida);  // Ho envia al MAX7221
        __delay_ms(1400);  // Retard d'1,4 s teòrics
      }
      if (tocat==0){
        if (mindec==1 && minuni==5 && segdec==0 && seguni==0) {
          TRISC = 0b00100000;  // Definim com volem les E/S del port C
                               // RC5 (sortida del PWM), de moment, com a entrada
          PORTC = 0;  // Desactiva les sortides del port C
                      // DC1B = 00 (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
                                // bits T2KCPS (bits 1-0) a 11 prescalat de 16
                                // bit 2 (TMR2ON) a 0, Timer aturat
                                // Postscaler TOUTPS (bits 6-3) no afecten al PWM
          TocaNota(118,59,2);
          tocat++;
          Sortida[1] = 0x01;  // Filera 1
          Sortida[3] = 0x01;
          Sortida[5] = 0x01;
          Sortida[0] = 0b00000000;  // Vermells
          Sortida[2] = 0b11111111;  // 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] = 0b11111111;  // 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] = 0b11111111;  // 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] = 0b11111111;  // 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] = 0b11111111;  // 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] = 0b11111111;  // 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] = 0b11111111;  // Verds
          Sortida[4] = 0b00000000;  // Blaus
          Envia3max(Sortida);  // Ho envia al MAX7221
          __delay_ms(1400);  // Retard d'1,4 s teòrics
        }
      }
      if (tocat==0 || tocat==1){
        if (mindec==3 && minuni==0 && segdec==0 && seguni==0) {
          TRISC = 0b00100000;  // Definim com volem les E/S del port C
                               // RC5 (sortida del PWM), de moment, com a entrada
          PORTC = 0;  // Desactiva les sortides del port C
                      // DC1B = 00 (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
                                // bits T2KCPS (bits 1-0) a 11 prescalat de 16
                                // bit 2 (TMR2ON) a 0, Timer aturat
                                // Postscaler TOUTPS (bits 6-3) no afecten al PWM
          TocaNota(118,59,2);
          TocaNota(118,59,2);
          tocat++;
          Sortida[1] = 0x01;  // Filera 1
          Sortida[3] = 0x01;
          Sortida[5] = 0x01;
          Sortida[0] = 0b00000000;  // Vermells
          Sortida[2] = 0b00000000;  // Verds
          Sortida[4] = 0b11111111;  // Blaus
          Envia3max(Sortida);  // Ho envia al MAX7221
          Sortida[1] = 0x02;  // Filera 2
          Sortida[3] = 0x02;
          Sortida[5] = 0x02;
          Sortida[0] = 0b00000000;  // Vermells
          Sortida[2] = 0b00000000;  // Verds
          Sortida[4] = 0b11111111;  // Blaus
          Envia3max(Sortida);  // Ho envia al MAX7221
          Sortida[1] = 0x03;  // Filera 3
          Sortida[3] = 0x03;
          Sortida[5] = 0x03;
          Sortida[0] = 0b00000000;  // Vermells
          Sortida[2] = 0b00000000;  // Verds
          Sortida[4] = 0b11111111;  // Blaus
          Envia3max(Sortida);  // Ho envia al MAX7221
          Sortida[1] = 0x04;  // Filera 4
          Sortida[3] = 0x04;
          Sortida[5] = 0x04;
          Sortida[0] = 0b00000000;  // Vermells
          Sortida[2] = 0b00000000;  // Verds
          Sortida[4] = 0b11111111;  // Blaus
          Envia3max(Sortida);  // Ho envia al MAX7221
          Sortida[1] = 0x05;  // Filera 5
          Sortida[3] = 0x05;
          Sortida[5] = 0x05;
          Sortida[0] = 0b00000000;  // Vermells
          Sortida[2] = 0b00000000;  // Verds
          Sortida[4] = 0b11111111;  // Blaus
          Envia3max(Sortida);  // Ho envia al MAX7221
          Sortida[1] = 0x06;  // Filera 6
          Sortida[3] = 0x06;
          Sortida[5] = 0x06;
          Sortida[0] = 0b00000000;  // Vermells
          Sortida[2] = 0b00000000;  // Verds
          Sortida[4] = 0b11111111;  // Blaus
          Envia3max(Sortida);  // Ho envia al MAX7221
          Sortida[1] = 0x07;  // Filera 7
          Sortida[3] = 0x07;
          Sortida[5] = 0x07;
          Sortida[0] = 0b00000000;  // Vermells
          Sortida[2] = 0b00000000;  // Verds
          Sortida[4] = 0b11111111;  // Blaus
          Envia3max(Sortida);  // Ho envia al MAX7221
          Sortida[1] = 0x08;  // Filera 8
          Sortida[3] = 0x08;
          Sortida[5] = 0x08;
          Sortida[0] = 0b00000000;  // Vermells
          Sortida[2] = 0b00000000;  // Verds
          Sortida[4] = 0b11111111;  // Blaus
          Envia3max(Sortida);  // Ho envia al MAX7221
          __delay_ms(1400);  // Retard d'1,4 s teòrics
        }
      }
      if (tocat==0 || tocat==1 || tocat==2){
        if (mindec==4 && minuni==5 && segdec==0 && seguni==0) {
          TRISC = 0b00100000;  // Definim com volem les E/S del port C
                               // RC5 (sortida del PWM), de moment, com a entrada
          PORTC = 0;  // Desactiva les sortides del port C
                      // DC1B = 00 (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
                                // bits T2KCPS (bits 1-0) a 11 prescalat de 16
                                // bit 2 (TMR2ON) a 0, Timer aturat
                                // Postscaler TOUTPS (bits 6-3) no afecten al PWM
          TocaNota(118,59,2);
          TocaNota(118,59,2);
          TocaNota(118,59,2);
          tocat++;
          Sortida[1] = 0x01;  // Filera 1
          Sortida[3] = 0x01;
          Sortida[5] = 0x01;
          Sortida[0] = 0b11111111;  // 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] = 0b11111111;  // 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] = 0b00000000;  // Verds
          Sortida[4] = 0b00000000;  // Blaus
          Envia3max(Sortida);  // Ho envia al MAX7221
          Sortida[1] = 0x05;  // Filera 5
          Sortida[3] = 0x05;
          Sortida[5] = 0x05;
          Sortida[0] = 0b11111111;  // Vermells
          Sortida[2] = 0b00000000;  // Verds
          Sortida[4] = 0b00000000;  // 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] = 0b11111111;  // 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] = 0b11111111;  // Vermells
          Sortida[2] = 0b00000000;  // Verds
          Sortida[4] = 0b00000000;  // Blaus
          Envia3max(Sortida);  // Ho envia al MAX7221
          __delay_ms(1400);  // Retard d'1,4 s teòrics
        }
      }
      if (seguni!=0){
        tocat=0;
        Apaga();  // Apaga tots els LED
      }
    }
  }
}
void __interrupt () temporit(void){  // Línia alternativa
  if  (FiTimer1 == 1){
    T1CONbits.TMR1ON = 0;  // Atura momentàniament el Timer1
    TMR1H = 231;  // Inicialitza el Timer1
    TMR1L = 150;
    T1CONbits.TMR1ON = 1;  // Torna a engegar el Timer1
    Compta++;  // Incrementa Compta
    FiTimer1 = 0;  // Tornem a posar el bit a zero// Comprovem que hi ha interrupció per Timer 0
    if (Compta == 20) {  // Si ha acabat vint vegades
      PORTC = Valor;  // Copiem el valor al port (als LED)
      Compta = 0;  // Reinicialitza Compta
      seguni++;  // Incrementa segons
      pantalla=1;
    }
    FiTimer1 = 0;  // Tornem a posar el bit a zero
  }
  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 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);
}
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 _Compta1");
  asm("movlw 48");  // Número de bits a enviar
  asm("movwf (_Compta1&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 _Compta1");
  asm("decfsz (_Compta1&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
  }
}

 

 

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