Programació en C del PIC 16F690

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

Rellotge

Programa del grup 2

Aquest dispositiu mostra la data i l'hora. A més, es pot configurar una alarma que, a l'hora programada, fa sonar una melodia i mostra un dibuix a la matriu de leds.

Per a la gestió del temps fan servir el temporitzador 1 i una interrupció.

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
#define _XTAL_FREQ  4000000
#define clrbit(var, bit) ((var) &= ~(1 << (bit)))
#define flipbit(var, bit) ((var) ^= (1<<(bit)))
#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 FiTimer2 PIR1bits.TMR2IF  // Li assigna un nom al bit que indica el final del Timer 2
char Polsad;  // variable que et diu quin polsador està premut
char menu;  // indica en quina pantalla et trobes (hora, alarma o data). Es modifica amb el polsador RA3
char canvi;  // indica en quina posició està el cursor en la configuració de l'hora
             // (o quan ja està configurada, que val 2)
char canviala;  // indica en quina posició està el cursor en la configuració de l'alarma
             // (o quan ja està configurada, que val 2)
char canvidata;  // indica en quina posició està el cursor en la configuració de la data
             // (o quan ja està configurada, que val 3)
char hora;  // indica si l'hora està configurada i en funcionament
char conf_alarm;  // indica si l'alarma està activada (on) o desactivada (off). Es modifica amb el polsador 3
char alarma;  // indica si l'alarma està activada i configurada (llesta per sonar)
char so;  // indica si l'hora coincideix amb l'alarma (un cop aquesta està configurada i activada).
          // Es posa a sonar
char ComptaTimer;  // va comptant els cops que el Timer1 arriba a 0.05 s. Cada 20 repeticions se suma un segon
char Port;
char Compta;
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 fig1[3][8] = { {0b00111100, 0b01111110, 0b11111111, 0b11111111, 
                     0b11111111, 0b11111111, 0b01111110, 0b00111100},
                    {0b00000000, 0b00000000, 0b00000000, 0b01111110, 
                     0b01111110, 0b00000000, 0b00000000, 0b00000000},
                    {0b00000000, 0b00000000, 0b00000000, 0b01111110, 
                     0b01111110, 0b00000000, 0b00000000, 0b00000000} };
signed char seg_un = 0;  // variable que conta les unitats de segon
                         // (apareix en el menú de l'hora, un cop configurat)
signed char seg_des = 0;  // variable que conta les desenes de segon
                         // (apareix en el menú de l'hora, un cop configurat)
signed char min_un = 0;  // variable que conta les unitats de minut (apareix al menú de l'hora)
signed char min_des = 0;  // variable que conta les unitats de segon (apareix al menú de l'hora)
signed char hor_un = 0;  // variable que conta les unitats de segon (apareix al menú de l'hora)
signed char hor_des = 0;  // variable que conta les unitats de segon (apareix al menú de l'hora)
signed char min_un_ala = 0;  // variable que emmagatzema les unitats de minut (apareix al menú de l'alarma)
signed char min_des_ala = 0;  // variable que emmagatzema les desenes de minut (apareix al menú de l'alarma)
signed char hor_un_ala = 0;  // variable que emmagatzema les unitats de l'hora (apareix al menú de l'alarma)
signed char hor_des_ala = 0;  // variable que emmagatzema les desenes de l'hora (apareix al menú de l'alarma)
signed char dia_un = 1;  // variable que conta les unitats del dia (apareix en el menú de la data)
signed char dia_des = 0;  // variable que conta les desenes del dia (apareix en el menú de la data)
signed char mes_un = 1;  // variable que conta les unitats del mes (apareix en el menú de la data)
signed char mes_des = 0;  // variable que conta les desenes del mes (apareix en el menú de la data)
signed char any_un = 0;  // variable que conta les unitats de l'any (apareix en el menú de la data)
signed char any_des = 0;  // variable que conta les desenes de l'any (apareix en el menú de la data)
signed char repe;  // variable que compta 5 'comptaTimers', és a dir, 0.25s
char defrepe = 0;  // val 1 si l'alarma passa a començar a sonar
char inter_alarm = 0;  // variable que compta 0.25s i ens serveix per coordinar el so de l'alarma
                       // amb la matriu LED mitjançant interrupcions
char port;  // Variable auxiliar del port C
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
// Definició de les funcions que farem servir 
char Polsador(void);  // Funció 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);  // Polsador que s'ha premut
void TocaNota(char valPre, char valPos, char valPR2, int numbuc, int numsil);
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
void main (void) {
  __delay_ms(1500);
  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
  ANSEL = 0b00000101;  // Configura AN0 i AN2 com entrada analògica
  OPTION_REG = 0b10000101;  // Configuració de Timer0
  ANSELH = 0;  // Desactiva les altres entrades analògiques
  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
  ADCON1 = 0b00010000;  // Posa el conversor a 1/8 de la freqüència
  ADCON0 = 0b00001001;  // Activa el conversor A/D connectat a AN2
  port = 0;
  PORTC = 0;  // Desactiva les sortides del port C
  PORTB = 0;
  Ini3max();  // Inicialitza els tres MAX7221
  Actiu = 1;  // Activa el color vermell
  TMR0 = 100;  // Presselecció de 100, que són 156 iteracions
  INTCON = 0b11100000;  // Activa GIE, PEIE, T0IE
  Apaga();
  FiTimer1 = 0;  // Aquest bit es posarà a 1 quan el temporitzador acabi
  T1CON = 0b00110001;  // Configuració de Timer1
  INTCONbits.PEIE = 1;  // Habilitem les interrupcions a nivell genera
  INTCONbits.GIE = 1;  // Habilitem les interrupcions a nivell general
  TMR1H = 231;  // Inicialitza el Timer1
  TMR1L = 150;
  PIE1bits.TMR1IE = 1; // Habilita la interrupción del Timer1
  while (1) {
    Polsad = Polsador();    // Llegim els polsadors
    // pas de l'hora i la data automàticament a través de l'avançamnent progressiu dels seg_un:
    if (seg_un > 9){        
      seg_des++;
      seg_un = 0;
    }
    if (seg_des > 5){
      min_un++;
      seg_des = 0;
    }
    if (min_un>9) {
      min_un=0;
      min_des++;
    }
    if (min_des > 5){
      min_des = 0;
      if (hora == 1){
        hor_un++;
      }
    }
    if (hor_un>3 && hor_des == 2) {
      hor_un=0;
      hor_des=0;
      if ((hora == 1) && (canvidata == 3)){
        dia_un++;
      }
    }
    if (hor_un > 9){
      hor_des++;
      hor_un = 0;
    } 
    if (dia_un>9) {
      dia_un=0;
      dia_des++;
    }
    if(mes_des==0&&(mes_un==1||mes_un==3||mes_un==5||mes_un==7||mes_un==8)||(mes_des==1&&(mes_un==0||mes_un==2))){
      // mesos de 31 dies
      if (dia_des==3 && dia_un>1){
        dia_des=0;
        dia_un=1;
        if (canvidata == 3){
          mes_un++;
        }
      }
    } else {  //mesos de 30 dies
      if (dia_des==3 && dia_un>0){
        dia_des=0;
        dia_un=1;
        if (canvidata == 3){
          mes_un++;
        }
      }
    }
    if (mes_des==0 && mes_un==2){  //febrer
      if (any_un%4==0){
        if (dia_des>2){
          dia_des=0;
          dia_un = 1;
          if (canvidata == 3){
             mes_un++;
          }
        }
      } else {
        if ((dia_des == 3) || ((dia_des == 2) && (dia_un == 9))){
          dia_des=0;
          dia_un=1;
          if (canvidata == 3){
            mes_un++;
          }
        }
      } 
    }
    if (dia_des > 3){  // evitar errors innecessàris
      dia_des = 0;
    }
    if (((mes_un > 2)&&(mes_des == 1)) && (hora == 1)){
      mes_des = 0;
      mes_un = 1;
      any_un++;
    }
    if (any_un > 9){
      any_des++;
      any_un = 0;
    }
    if (any_des > 9){
      any_des = 0;
    }
    // útil per correcte funcionament a l'hora de configurar l'alarma:
    if (min_un_ala>9) {
      min_un_ala=0;
      min_des_ala++;
    }
    if (min_des_ala > 5){
      min_des_ala = 0;
    }
    if (hor_un_ala>3 && hor_des_ala == 2) {
      hor_un_ala=0;
      hor_des_ala=0;
    }
    if (hor_un_ala > 9){
      hor_des_ala++;
      hor_un_ala = 0;
    }
    if (menu == 0) {  // si estem al menú de l'hora
      __delay_ms(200);  // Esperem que arrenqui la pantalla
      Esborra();  // Neteja la pantalla
      Cursor(1,1);
      EnviaL('T'); 
      EnviaL('I');
      EnviaL('M');
      EnviaL('E');
      Cursor(2, 12);  
      EnviaL('0' + hor_des);
      EnviaL('0' + hor_un);
      EnviaL(':');
      EnviaL('0' + min_des);
      EnviaL('0' + min_un);
      // canvi de configuració (passar de minuts a hores o a mode configurat):
      if (Polsad == 5){       // si premem el polsador 5 canviem el cursor
        while (Polsador() > 0){
          ;
        }
        canvi++;
        if (canvi > 2){
          canvi = 0;
          seg_un = 0;
          seg_des = 0;
        }
      }
      if (canvi == 0){  // configurar minuts
        Cursor(1,15);
        EnviaL('_');
        EnviaL('_');
      }
      if (canvi == 1){  // configurar hores
        Cursor(1,12);
        EnviaL('_');
        EnviaL('_');
      }
      if (canvi == 2){  // mode ja configurat (l'hora passa automàticament)
        hora = 1;
        Esborra();  // Neteja la pantalla
        EnviaL('T'); 
        EnviaL('I');
        EnviaL('M');
        EnviaL('E');
        Cursor(2, 9);  
        EnviaL('0' + hor_des);
        EnviaL('0' + hor_un);
        EnviaL(':');
        EnviaL('0' + min_des);
        EnviaL('0' + min_un);
        EnviaL(':');
        EnviaL('0' + seg_des);
        EnviaL('0' + seg_un);
      }else{
        hora = 0;
      }
    }
    if (menu == 1) {  // si estem al menú de l'alarma
      __delay_ms(200);  // Esperem que arrenqui la pantalla
      Esborra();  // Esborra la pantalla
      EnviaL('A');        
      EnviaL('L');        
      EnviaL('A');        
      EnviaL('R');        
      EnviaL('M');        
      Cursor(2, 12);        
      EnviaL('0'+hor_des_ala);  
      EnviaL('0'+hor_un_ala);    
      EnviaL(':');        
      EnviaL('0'+min_des_ala);  
      EnviaL('0'+min_un_ala);  
      // canvi de configuració de l'alarma:
      if (Polsad == 5){  // si premem el polsador 5 canviem el cursor
        while (Polsador() > 0){
          ;
        }
        canviala++;
        if (canviala > 2){
          canviala = 0;
        }
      }
      if (canviala == 0){  // configurar minuts de l'alarma
        Cursor(1,15);
        EnviaL('_');
        EnviaL('_');
      }
      if (canviala == 1){  // configurar hores de l'alarma
        Cursor(1,12);
        EnviaL('_');
        EnviaL('_');
      }
      if (Polsad == 3){  // premer el polsador 3 per activar l'alarma    
        while (Polsador() > 0){
          ;
        }
        conf_alarm++; 
        if (conf_alarm > 1){
          conf_alarm = 0;
        }
      }
      if (conf_alarm == 0){  // alarma NO activada
        Cursor(2, 1);        
        EnviaL('o');        
        EnviaL('f');        
        EnviaL('f');        
      }
      if (conf_alarm == 1){  // alarma activada
        Cursor(2, 1);        
        EnviaL('o');        
        EnviaL('n');        
      }
      if (canviala == 2 && conf_alarm == 1){  // indica si, a més a més d'estar activada (on),
                                              // també està configurada
        alarma = 1;
      } else{
        alarma = 0;
      }
    }
    if (menu == 2) {  // si estem al menú de la data
      __delay_ms(200);  // Esperem que arrenqui la pantalla
      Esborra();  // Esborra la pantalla
      EnviaL('D');                    
      EnviaL('A');                    
      EnviaL('T');                    
      EnviaL('E');                    
      Cursor(2, 9);                   
      EnviaL('0' + dia_des);      
      EnviaL('0' + dia_un);      
      EnviaL('/');        
      EnviaL('0' + mes_des);    
      EnviaL('0' + mes_un);    
      EnviaL('/');        
      EnviaL('0' + any_des);    
      EnviaL('0' + any_un);
      // canvi de configuració de la data:
      if (Polsad == 5){  // si premem el polsador 5 canviem el cursor            
        while (Polsador() > 0){
          ;
        }
        canvidata++;
        if (canvidata > 3){
          canvidata = 0;
        }
      }
      if (canvidata == 0){  // configurar l'any
        Cursor(1,15);
        EnviaL('_');
        EnviaL('_');
      }
      if (canvidata == 1){  // configurar el mes
        Cursor(1,12);
        EnviaL('_');
        EnviaL('_');
      }
      if (canvidata == 2){  // configurar el dia
        Cursor(1,9);
        EnviaL('_');
        EnviaL('_');
      }
    }
    if (Polsad == 2) {  // polsador per pujar en el mode configuració (en qualsevol dels tres menús)
      if (menu == 0){  // pujar en el menú de l'hora
        if (canvi == 0){  // si estem amb el cursor sobre els minuts
          min_un++; 
        }
        if (canvi == 1){  // si estem amb el cursor sobre les hores
          hor_un++; 
        }
      }
      if (menu == 1){  // pujar en el menú de l'alarma
        if (canviala == 0){  // si hi ha el cursor sobre els minuts
          min_un_ala++; 
        }
        if (canviala == 1){  // si hi ha el cursor sobre les hores
          hor_un_ala++; 
        }
      }
      if (menu == 2){  // pujar en el menú de la data
        if (canvidata == 2){  // si el cursor està sobre els dies 
          dia_un++; 
        }
        if (canvidata == 1){  // si el cursor està sobre els mesos
          mes_un++; 
          // instruccions per aconseguir un correcte funcionament en el pas dels mesos:
          if (mes_un>9) {
            mes_un=0;
            mes_des++;
          }
          if (mes_des == 1 && mes_un > 2){
            mes_des = 0;
            mes_un = 1;
          }
        }
        if (canvidata == 0){  // si el cursor està sobre els anys
          any_un++; 
          // instruccions per aconseguir un correcte funcionament en el pas dels anys:
          if (any_un > 9 && any_des == 9){
            any_un = 0;
            any_des = 0;
          }
          if (any_un > 9){
            any_des++;
            any_un = 0;
          }
        }
      }
    }
    if (Polsad == 1) {  // polsador per baixar en el mode configuració (en qualsevol dels tres menús)
      if (menu == 0){  // si estem en el menú de l'hora
        if (canvi == 0){  // si el cursor està sobre els minuts
          min_un--; 
          if (min_un<0) {
            min_un=9;
            min_des--;
          }
          if (min_des < 0){
            min_des = 5;
          }
        }
        if (canvi == 1){  // si el cursor està sobre les hores
          hor_un--; 
          if (hor_un<0 && hor_des == 0) {
            hor_un=3;
            hor_des=2;
          }
          if (hor_un < 0){
            hor_des--;
            hor_un = 9;
          }
        }
      }
      if (menu == 1){  // si estem en el menú de l'alarma
        if (canviala == 0){  // si el cursor està sobre els minuts
          min_un_ala--; 
          if (min_un_ala<0) {
            min_un_ala=9;
            min_des_ala--;
          }
          if (min_des_ala < 0){
            min_des_ala = 5;
          }
        }
        if (canviala == 1){  // si el cursor està sobre les hores
          hor_un_ala--; 
          if (hor_un_ala<0 && hor_des_ala == 0) {
            hor_un_ala=3;
            hor_des_ala=2;
          }
          if (hor_un_ala < 0){
            hor_des_ala--;
            hor_un_ala = 9;
          }
        }
      }
      if (menu == 2){  // si estem en el menú de la data
        if (canvidata == 2){  // si el cursor està sobre els dies
          dia_un--; 
          if (dia_un < 0 && dia_des > 0) {    
            dia_un=9;
            dia_des--;
          }
          if(mes_des==0&&(mes_un==1||mes_un==3||mes_un==5||mes_un==7||mes_un==8)||(mes_des==1&&(mes_un==0||mes_un==2))){
            //  mesos de 31 dies
            if (dia_des==0 && dia_un < 1){
              dia_des=3;
              dia_un=1;
            }
          } else{             // mesos de 30 dies
            if (dia_des == 0 && dia_un < 1){
              dia_des = 3;
              dia_un = 0;
            }
          }
          if (mes_des==0 && mes_un==2){  // febrer
            if (any_un%4==0){
              if (dia_des == 0 && dia_un < 1){
                dia_des=2;
                dia_un = 9;
              }
            } else {
              if (dia_des == 0 && dia_un < 1){
                dia_des=2;
                dia_un=8;
              }
            }     
          }
        }
        if (canvidata == 1){  // si el cursor està sobre els mesos
          mes_un--; 
          if (mes_un<0 && mes_des == 1) {
            mes_un=9;
            mes_des--;
          }
          if (mes_des == 0 && mes_un < 1){
            mes_des = 1;
            mes_un = 2;
          }
        }
        if (canvidata == 0){  // si el cursor està sobre els anys
          any_un--; 
          if (any_un < 0 && any_des == 0){
            any_un = 9;
            any_des = 9;
          }
          if (any_un < 0){
            any_des--;
            any_un = 9;
          }
        }
      }
    }
    if (RA3 == 0){  //POLSADOR 0
      while (RA3 == 0){
        ;
      }
      menu = (menu +1) % 3;  // el polsador 0 ens servirà per canviar de menús
                             // (entre l'hora, l'alarma i la data)
    }
    if (alarma == 1 && hora == 1){  // si l'alarma està configurada i activada
                                    // i l'hora també està configurada
      if((min_un_ala==min_un)&&(min_des_ala==min_des)&&(hor_un_ala==hor_un)&&(hor_des_ala==hor_des)){
        // si l'hora de l'alarma és la mateixa que la real
        so = 1;     // variable que indica que l'alarma s'ha de posar a sonar
      }
    }
    if (so == 1){  // si sona l'alarma
      // Matriu 1
      defrepe++;
      if (inter_alarm == 0){  // aquesta variable va comptant mitjançant interrupcions 0.25s
        for (unsigned char k = 0; k < 8; k++){  // apareix una figura en la matriu LED
          Sortida[1] = k+1;  // Filera
          Sortida[3] = k+1;
          Sortida[5] = k+1;
          Sortida[0] = fig1[0][k];  // Vermells
          Sortida[2] = fig1[1][k];  // Verds
          Sortida[4] = fig1[2][k];  // Blaus
          Envia3max(Sortida);  // Ho envia al MAX7221
          __delay_ms(1);
        }
      }
      if (inter_alarm == 1){  // al cap de 0.25s comença a tocar la primera melodia
        TocaNota(0, 7, 239, 105, 105);  // Valor que correspon aproximadament a do3
        TocaNota(0, 6, 243, 118, 118);  // Valor que correspon aproximadament a re3
        TocaNota(0, 7, 239, 105, 105);  // Valor que correspon aproximadament a do3
        TocaNota(0, 6, 243, 118, 118);  // Valor que correspon aproximadament a re3
        TocaNota(0, 5, 253, 132, 132);  // Valor que correspon aproximadament a mi3
      }
      if (inter_alarm == 4){  // al cap d'1s comença a tocar la segona
        TocaNota(0, 7, 239, 105, 105);  // Valor que correspon aproximadament a do3
        TocaNota(0, 6, 243, 118, 118);  // Valor que correspon aproximadament a re3
        TocaNota(0, 7, 239, 105, 105);  // Valor que correspon aproximadament a do3
        TocaNota(0, 6, 243, 118, 118);  // Valor que correspon aproximadament a re3
        TocaNota(0, 5, 253, 132, 132);  // Valor que correspon aproximadament a mi3
      }
      if (inter_alarm == 7){  // al cap de 1.75s comença a tocar l'última
        TocaNota(0, 7, 239, 105, 105);  // Valor que correspon aproximadament a do3
        TocaNota(0, 6, 243, 118, 118);  // Valor que correspon aproximadament a re3
        TocaNota(0, 7, 239, 105, 105);  // Valor que correspon aproximadament a do3
        TocaNota(0, 6, 243, 118, 118);  // Valor que correspon aproximadament a re3
        TocaNota(0, 5, 253, 132, 132);  // Valor que correspon aproximadament a mi3
      }
      if (inter_alarm == 8){  // al cap de 2s s'apaga la figura de la matriu LED
        Apaga();  // Matriu 2
      }
      if (inter_alarm == 14){  // al cap de 3.5s es reinicia la variable i es torna a començar a dalt
        inter_alarm = 0;
      }
    }
    if (Polsad == 4 && so == 1){  // el polsador 4 ens servirà per parar l'alarma quan soni
      conf_alarm = 0; 
      so = 0;
      canviala = 0;
      hor_un_ala = 0;
      hor_des_ala = 0;
      min_un_ala = 0;
      min_des_ala = 0;
      Apaga();
    }
  } 
}
void __interrupt() temporit(void){
  if (FiTimer1 == 1){  // Si ha acabat el temporitzador
    T1CONbits.TMR1ON = 0;  // Atura momentàniament el Timer1
    TMR1H = 231;  // Inicialitza el Timer1
    TMR1L = 150;
    T1CONbits.TMR1ON = 1;  // Torna a engegar el Timer1
    FiTimer1 = 0;  // Tornem a posar el bit a zero
    if(hora == 1){    
      ComptaTimer++;  // Incrementa Compta
      if (ComptaTimer == 20) {  // Si ha acabat vint vegades
        seg_un++;
        ComptaTimer = 0;
      }
      if (so == 1 && defrepe == 1){
        if (ComptaTimer < 15){
          repe = ComptaTimer;
        }else{
          repe = ComptaTimer - 20;
        }
      }
      if (so == 1){
        if (ComptaTimer - repe == 5) {
          inter_alarm++;
        }
      }
    }
  }
  if (FiTimer2) {  // Comprovem que hi ha interrupció per Timer2
    FiTimer2 = 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 (FiTimer0 = 1) {  // Comprovem que hi ha interrupció per Timer 0
    TMR0 = 100;  // Preselecció de Timer0
    FiTimer0 == 0;
    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
  }
}
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--;  // 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
}
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("banksel PORTB");
  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("banksel PORTB");
  asm("movwf PORTB");  // I el posa al port B
  asm("banksel _Port");
  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("banksel PORTB");
  asm("movwf PORTB");  // I el posa al port B
  asm("banksel _Port");
  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("banksel PORTB");
  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 és zero, repeteix el bucle
  asm("banksel _Port");
  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("banksel PORTB");
  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.