Programació en C del PIC 16F690

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

Rellotge

Programa del grup 4

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. També l'opció de mostrar l'hora a la matriu de leds, fent servir una porció de 3 ⨯ 4 leds per a cada dígit.

Per a la gestió del temps fan servir el temporitzador 0 i una interrupció, que també gestiona la matriu de leds.

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  // La freqüència del rellotge és 4 MHz
#define PolsadorS   RA3  // Li assigna un nom a l'adreça del polsador
#define FiTimer0 INTCONbits.T0IF  // Li assigna un nom al bit que indica el final del Timer 0
#define flipbit(var, bit) ((var) ^= (1<<(bit)))
char Port;  // Gestió del port a la funció Envia_max
char Compta;  // Comptador de bits a la funció Envia_max
unsigned char ComptaB = 0;
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 i;
char j;
char l;
char Menu=2;
char Comptar;  // Comptador de bits a la funció Envia3max
char fig1[3][8];
char numLed[10][4] = {{0b01000000, 0b10100000, 0b10100000, 0b01000000},  // Zero
                      {0b00100000, 0b01100000, 0b00100000, 0b00100000},  // U
                      {0b01100000, 0b10100000, 0b01000000, 0b11100000},  // Dos
                      {0b11100000, 0b01000000, 0b00100000, 0b11100000},  // Tres
                      {0b01100000, 0b10100000, 0b11110000, 0b00100000},  // Quatre
                      {0b11100000, 0b11000000, 0b00100000, 0b11000000},  // Cinc
                      {0b11000000, 0b10000000, 0b11100000, 0b11100000},  // Sis
                      {0b11100000, 0b00100000, 0b01000000, 0b01000000},  // Set
                      {0b11100000, 0b10100000, 0b11100000, 0b11100000},  // Vuit
                      {0b11100000, 0b10100000, 0b01100000, 0b00100000}};  // Nou
unsigned char Valor;  // Variable de 8 bits sense signe (0 a 255)
unsigned char ComptaT;  // Variable de 8 bits sense signe (0 a 255)
char h=0;
char min=0;
char s=0;
char d[8]={0, 1, 0, 1, 2, 0, 2, 5};
char dIni[8]={0, 1, 0, 1, 2, 0, 2, 5};
char alarmaH=0;
char alarmaM=0;
char aSet=0;
char selec=1;
char diaSetmana=2;
char lletresDS[7][3] = {{'L', 'U', 'N'}, {'M', 'A', 'R'}, {'M', 'I', 'E'}, {'J', 'U', 'E'},
                        {'V', 'I', 'E'}, {'S', 'A', 'B'}, {'D', 'O', 'M'}};
unsigned char Analogica (void);  // Funció de lectura del conversor
char Polsad;  // Polsador que s'ha premut
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);  // Posiciona el cursor
                                         // (filera 1 a 2 i columna 1 a 32, segons pantalla)
void Envia3max(void);  // 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 TocaNota(char ValPR2, char ValCCPR1L, char ValDC1B);
void OperacioT(void);
void OperacioCAL(void);
void Alarma(void);
void main(void) {
  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
  Ini3max();  // Inicialitza els tres MAX7221
  Actiu = 1;  // Activa el color vermell
  TMR0 = 100;  // Presselecció de 100, que són 156 iteracions
  // Correspon a una interrupció cada 7,5 ms
  CCP1CON = 0b00001100;  // Configura el PWM, bits P1M (bits 7-6) a 00 mode senzill
  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
  PIR1bits.TMR2IF = 0;  // Desactiva el bit d'interrupció del Timer 2
  T2CON = 0b00000011;  // Configura el Timer 2
  ADCON1 = 0b00010000;  // Posa el conversor a 1/8 de la freqüència
  ADCON0 = 0b00001001;
  INTCON = 0b10100000;  // Habilitem la interrupció per Timer0
  // Configuració del Timer 0
  FiTimer0 = 0;  // Aquest bit es posarà a 1 quan el temporitzador acabi
  // cal desactivar-lo des del programa
  OPTION_REG = 0b10000100;  // Configuració de Timer0
  // Com a temporitzador basat en rellotge
  // 111 - Factor d'escala de 256
  // I resistències de pull-up desactivades (valor per defecte)
  INTCONbits.GIE = 1;  // Habilitem les interrupcions a nivell general
  Apaga();  // Apaga tots els LED
  while (1){
    if (Menu==1) {  // Menu 1
      Apaga();
      PORTC = 0b00000001;  // Activem el LED 0 com a indicació visual del menu on estem
      Esborra();  // Enviem a la pantalla l'hora actual
      Cursor(2,1);  // Enviem a la pantalla la data actual
      EnviaL(d[0]+'0');
      EnviaL(d[1]+'0');
      EnviaL('/');
      EnviaL(d[2]+'0');
      EnviaL(d[3]+'0');
      EnviaL('/');
      EnviaL(d[4]+'0');
      EnviaL(d[5]+'0');
      EnviaL(d[6]+'0');
      EnviaL(d[7]+'0');
      Cursor(2,14);  // Enviem a la pantalla el dia de la setmana actual
      for (i=0;i<3;i++){
        EnviaL(lletresDS[diaSetmana][i]);
      }
      do {  // Bucle que s'executa mentre estem al menu 1
        OperacioT();
        Cursor(1,1);
        EnviaL(h/10 + '0');        
        EnviaL(h%10 + '0');  
        EnviaL(':');  
        EnviaL(min/10 + '0');  
        EnviaL(min%10 + '0');  
        EnviaL(':');  
        EnviaL(s/10 + '0');  
        EnviaL(s%10 + '0');
        Alarma();
        if (PolsadorS==0) {  // Comprova l'estat del polsador per veure si s'ha canviat de menu
          __delay_ms(250);  // Retard de 250 ms per evitar canvis de menu extres
          Menu = 2;  // Canvi de menu
        }
      } while (Menu==1);
    }
    if (Menu==2) {
      PORTC = 0b00000010;  // Activem el LED 1 com a indicació visual del menu on estem
      Polsad = Polsador();
      Esborra();      
      Cursor(1,6);
      EnviaL(alarmaH/10+'0');
      EnviaL(alarmaH%10+'0');
      EnviaL(':');
      EnviaL(alarmaM/10+'0');
      EnviaL(alarmaM%10+'0');  
      Cursor(1,16);
      EnviaL(aSet+'0');
      selec=1;
      Cursor(2,6);
      EnviaL('^');
      EnviaL('^');
      EnviaL(' ');
      EnviaL(' ');
      EnviaL(' ');
      do {  // Bucle que s'executa mentre estem al menu 2
        Polsad = Polsador();  // Llegim els polsadors
        if (Polsad == 4) {  // Si s'ha premut el polsador 4
          aSet=2;
          Cursor(1,16);
          EnviaL(aSet+'0');
        }
        if (Polsad == 3) {  // Si s'ha premut el polsador 3
          aSet=1;
          Cursor(1,16);
          EnviaL(aSet+'0');
        }
        if (Polsad == 2) {  // Si s'ha premut el polsador 2
          aSet=0;
          Cursor(1,16);
          EnviaL(aSet+'0');
        }
        if (Polsad == 5) {  // Si s'ha premut el polsador 5
          ComptaB = 0;
          if(selec==2){
            selec=1;
            Cursor(2,6);
            EnviaL('^');
            EnviaL('^');
            EnviaL(' ');
            EnviaL(' ');
            EnviaL(' ');
          } else {
            selec=2;
            Cursor(2,6);
            EnviaL(' ');
            EnviaL(' ');
            EnviaL(' ');
            EnviaL('^');
            EnviaL('^');
          }
          while(Polsador() == 5)  // Esperem a que el polsador es deixi anar
            ;  // No fem res
          do {  // Bucle per comptar quants cops detectem el polsador premut
            if (Polsad == 5)  // Si el polsador està premut
              ComptaB++;  // Incrementa Compta
            else  // Si no està premut
              ComptaB = 0;  // Posa el comptador zero
            _delay(1000);  // Retard de 1000 cicles
          } while (ComptaB < 5);  // Es repeteix fins que hem comptat 5 cops
        }
        if (Polsad == 1) {  // Si s'ha premut el polsador 1
          ComptaB = 0;
          if(selec==1){
            alarmaH++;
            if(alarmaH==24)
              alarmaH=0;
          }
          if(selec==2){
            alarmaM++;
            if(alarmaM==60)
              alarmaM=0;
          }
          Cursor(1,6);
          EnviaL(alarmaH/10+'0');
          EnviaL(alarmaH%10+'0');
          EnviaL(':');
          EnviaL(alarmaM/10+'0');
          EnviaL(alarmaM%10+'0');
          while(Polsador() == 1)  // Esperem a que el polsador es deixi anar
            ;  // No fem res
          do {  // Bucle per comptar quants cops detectem el polsador premut
            if (Polsad == 1)  // Si el polsador està premut
              ComptaB++;  // Incrementa Compta
            else  // Si no està premut
              ComptaB = 0;  // Posa el comptador zero
            _delay(1000);  // Retard de 1000 cicles
          } while (ComptaB < 5);  // Es repeteix fins que hem comptat 5 cops
        }
        OperacioT();
        Alarma();
        if (PolsadorS==0) {  // Comprova l'estat del polsador per veure si s'ha canviat de menu
          __delay_ms(250);  // Retard de 250 ms per evitar canvis de menu extres
          Menu = 3;  // Canvi de menu
        }
      } while (Menu==2);
    }
    if (Menu==3) {
      PORTC = 0b00000100;  // Activem el LED 2 com a indicació visual del menu on estem
      Esborra();
      for (i=0;i<8;i++){  // Guardem la data inicial abans d'entrar al menu
        dIni[i]=d[i];
      }
      do {  // Bucle que s'executa mentre estem al menu 3
        Polsad = Polsador();  // Llegim els polsadors
        if (Polsad == 1) {  // Si s'ha premut el polsador 1
          ComptaB = 0;
          h++;
          s=0;
          if(h==24){
            h=0;
          }
          while(Polsador() == 1)  // Esperem a que el polsador es deixi anar
            ;  // No fem res
          do {  // Bucle per comptar quants cops detectem el polsador premut
            if (Polsad == 1)  // Si el polsador està premut
              ComptaB++;  // Incrementa Compta
            else  // Si no està premut
              ComptaB = 0;  // Posa el comptador zero
            _delay(1000);  // Retard de 1000 cicles
          } while (ComptaB < 5);  // Es repeteix fins que hem comptat 5 cops
        }
        if (Polsad == 2) {  // Si s'ha premut el polsador 2
          ComptaB = 0;
          min++;
          s=0;
          if(min==60){
            min=0;
          }
          while(Polsador() == 2)  // Esperem a que el polsador es deixi anar
            ;  // No fem res
          do {  // Bucle per comptar quants cops detectem el polsador premut
            if (Polsad == 2)  // Si el polsador està premut
              ComptaB++;  // Incrementa Compta
            else  // Si no està premut
              ComptaB = 0;  // Posa el comptador zero
            _delay(1000);  // Retard de 1000 cicles
          } while (ComptaB < 5);  // Es repeteix fins que hem comptat 5 cops
        }
        if (Polsad == 3) {  // Si s'ha premut el polsador 3
          ComptaB = 0;
          d[1]++;
          OperacioCAL();
          diaSetmana = (diaSetmana + 1)%7;
          while(Polsador() == 3)  // Esperem a que el polsador es deixi anar
            ;  // No fem res
          do {  // Bucle per comptar quants cops detectem el polsador premut
            if (Polsad == 3)  // Si el polsador està premut
              ComptaB++;  // Incrementa Compta
            else  // Si no està premut
              ComptaB = 0;  // Posa el comptador zero
            _delay(1000);  // Retard de 1000 cicles
          } while (ComptaB < 5);  // Es repeteix fins que hem comptat 5 cops
        }
        if (Polsad == 4) {  // Si s'ha premut el polsador 4
          for (i=0;i<8;i++){          
            d[i]=dIni[i];
          }
        }
        if (Polsad == 5) {  // Si s'ha premut el polsador 5
          d[0]=0;  // La data torna als valors de fábrica (01/01/2025)
          d[1]=1;
          d[2]=0;
          d[3]=1;
          d[4]=2;
          d[5]=0;
          d[6]=2;
          d[7]=5;
        }
        Cursor(1,1);
        EnviaL(h/10+'0');  // Enviem la hora i data actuals
        EnviaL(h%10+'0');
        EnviaL(':');
        EnviaL(min/10+'0');
        EnviaL(min%10+'0');
        EnviaL(' ');
        EnviaL(d[0]+'0');
        EnviaL(d[1]+'0');
        EnviaL('/');
        EnviaL(d[2]+'0');
        EnviaL(d[3]+'0');
        EnviaL('/');
        EnviaL(d[4]+'0');
        EnviaL(d[5]+'0');
        EnviaL(d[6]+'0');
        EnviaL(d[7]+'0');
        if (s==60)
          s=0;
        if (PolsadorS==0) {  // Comprova l'estat del polsador per veure si s'ha canviat de menu
          __delay_ms(250);  // Retard de 250 ms per evitar canvis de menu extres
          Menu = 4;  // Canvi de menu
        }
      } while (Menu==3);
    }
    if (Menu==4) {
      PORTC = 0b00001000;  // Activem el LED 3 com a indicació visual del menu on estem
      Esborra();  // Esborra la pantalla i posa el cursor a l'inici
      do {  // Bucle que s'executa mentre estem al menu 4
        Cursor(1,1);
        EnviaL(h/10+'0');        
        EnviaL(h%10+'0');
        EnviaL(' ');
        EnviaL('H');
        Cursor(2,1);
        EnviaL(min/10+'0');        
        EnviaL(min%10+'0');        
        EnviaL(' ');        
        EnviaL('M');
        EnviaL('i');
        EnviaL('n');
        for (j=0; j<8; j++) {
          if (j<4)
            fig1[0][j] = numLed[h/10][j];
          else
            fig1[0][j] = (numLed[min%10][j-4])>>4;
        }
        for (j=0; j<8; j++) {
          if (j<4)
            fig1[1][j] = (numLed[h%10][j])>>4;
          else
            fig1[1][j] = (numLed[min%10][j-4])>>4;
        }
        for (j=4; j<8; j++) {
          fig1[2][j] = numLed[min/10][j-4];
        }
        for (unsigned char k = 0; k < 8; k++){
          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();  // Ho envia al MAX7221
          __delay_ms(1);
        }
        OperacioT();
        Alarma();
        if (PolsadorS==0) {  // Comprova l'estat del polsador per veure si s'ha canviat de menu
          __delay_ms(250);  // Retard de 250 ms per evitar canvis de menu extres
          Menu = 1;  // Canvi de menu
        }
      } while (Menu==4);
    }
  }
}
void __interrupt() temporit(void){
  if (INTCONbits.T0IF) {  // Comprovem que hi ha interrupció per Timer 0
    TMR0 = 100;  // Preselecció de Timer0
    if  (FiTimer0){  // Comprovem que hi ha interrupció per Timer 0
      ComptaT++;  // Incrementa Compta
      if (ComptaT == 120) {  // Si ha acabat vint vegades
        ComptaT = 0;  // Reinicialitza Compta
        s++;
      }
      FiTimer0 = 0;  // Tornem a posar el bit a zero
      TMR0 = Analogica();  // Cridem a la funció de lectura del conversor i
      // copiem el resultat llegit com a precàrrega del Timer
    }
    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
  }
}
unsigned char Analogica (void){ // Funció de lectura del conversor
  ADCON0bits.GO_DONE = 1;  // Posa en marxa el conversor
  while (ADCON0bits.GO_DONE == 1)  // Mentre no acabi
    ;  // ens esperem
  return ADRESH;  // Retornem el resultat llegit
}
char Polsador(void) {
  char Pols = 0;
  ADCON0bits.GO = 1;  // Posa en marxa el conversor
  while (ADCON0bits.GO == 1)  // Mentre no acabi
    ;  // ens esperem
  if (ADRESH < 220 && ADRESH > 200) {
    Pols = 1;  // Comprova polsador 1
  }
  if (ADRESH < 194 && ADRESH > 174) {
    Pols = 2;  // Comprova polsador 2
  }
  if (ADRESH < 163 && ADRESH > 143) {
    Pols = 3;  // Comprova polsador 3
  }
  if (ADRESH < 90 && ADRESH > 70) {
    Pols = 4;  // Comprova polsador 4
  }
  if (ADRESH < 55 && ADRESH > 35) {
    Pols = 5;  // Comprova polsador 5
  }
  return Pols;
}
void EnviaL(char Caracter) {
  INTCONbits.GIE = 0;  // Desactiva les interrupcions momentàniament
  RCSTAbits.SPEN = 1;  // Activa comunicació sèrie
  TXSTAbits.TXEN = 1;  // Activa comunicació
  TXREG = Caracter;  // Agafa el caràcter i l'envia
  __delay_ms(1);  // Donem temps
  while (PIR1bits.TXIF == 0)  // Esperem que s'acabi d'enviar
    ;  // No fem res
  RCSTAbits.SPEN = 0;  // Desactiva comunicació sèrie
  TXSTAbits.TXEN = 0;  // Desactiva comunicació
  INTCONbits.GIE = 1;  // Activa les interrupcions
}
void Esborra(void) {
  EnviaL(254);  // Caràcter de control
  EnviaL(1);  // Esborra la pantalla i posa el cursor a l'inici
}
void Cursor(char Filera, char Columna) {
  char Posicio = 0;  // Variable per a calcular la posició
  if (Filera == 2) {
    Posicio = 64;  // La primera columna de la segona fila és 64;
  }
  if (Columna > 0 && Columna < 33) {  // Comprovem que sigui un valor raonable
    Posicio = Posicio + Columna;  // Sumem les adreces
    Posicio = Posicio - 1;  // Restem 1 perquè numera des de 0
  }
  Posicio = Posicio + 128;  // Posa el bit de posicionat a 1
  EnviaL(254);  // Control de la posició del cursor
  EnviaL(Posicio);  // Canvia el cursor de lloc
}
void Envia3max(void) {  // Envia un joc de valors als tres MAX7221
  asm("bcf INTCON,5");  // Desactiva les interrupcions momentàniament
  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 _Comptar");
  asm("movlw 48");  // Número de bits a enviar
  asm("movwf (_Comptar&7fh)");  // Variable per comptar els bits
  asm("Bucles:");
  asm("banksel _Port");
  asm("bcf (_Port&7fh),4");  // Desactiva Data. Si toca activar-ho, ja ho farem
  asm("banksel _Sorti");
  asm("rlf (_Sortida&7fh),f");  // Fa sortir el bit de més a l'esquerra cap a C
  asm("rlf ((_Sortida+1)&7fh),f");  // i roda els altres a l'esquerra
  asm("rlf ((_Sortida+2)&7fh),f");
  asm("rlf ((_Sortida+3)&7fh),f");
  asm("rlf ((_Sortida+4)&7fh),f");
  asm("rlf ((_Sortida+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 _Comptar");
  asm("decfsz (_Comptar&7fh),f");  // Decrementa Compta
  asm("goto (Bucles&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
  asm("bsf INTCON,5");  // 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
  Sortida[0] = 0x00;  // Desactivat
  Sortida[1] = 0x0C;  // Shutdown mode
  Sortida[2] = 0x00;
  Sortida[3] = 0x0C;
  Sortida[4] = 0x00;
  Sortida[5] = 0x0C;
  Envia3max();  // Els envia
  Sortida[0] = 0x00;  // No decode
  Sortida[1] = 0x09;  // Decode mode
  Sortida[2] = 0x00;
  Sortida[3] = 0x09;
  Sortida[4] = 0x00;
  Sortida[5] = 0x09;
  Envia3max();  // Els envia
  Sortida[0] = 0x07;  // Vuit fileres
  Sortida[1] = 0x0B;  // Scan limit
  Sortida[2] = 0x07;
  Sortida[3] = 0x0B;
  Sortida[4] = 0x07;
  Sortida[5] = 0x0B;
  Envia3max();  // Els envia
}
void Apaga(void) {  // Apaga tots els LED
  for (unsigned char j = 1; j <= 8; j++){  // Hem d'enviar 8 fileres
    Sortida[1] = j;  // Filera
    Sortida[3] = j;
    Sortida[5] = j;
    Sortida[0] = 0x00;  // Vermells
    Sortida[2] = 0x00;  // Verds
    Sortida[4] = 0x00;  // Blaus
    Envia3max();  // 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(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
}
void OperacioT(void) {
  if(s==60) {
    s=0;
    min++;
  }
  if(min==60) {
    min=0;
    h++;
  }
  if(h==24) {
    diaSetmana = (diaSetmana + 1)%7;
    d[1]++;  // incrementem el dia
    OperacioCAL();
    h=0;
  }
}
void OperacioCAL(void) {
  if (d[1]==10) {  // Canvi decenes dia
    d[1]=0;
    d[0]++;
  }
  if (d[2]==0) {  // mesos 1-9
    if (d[3]==1) {  // Gener
      if (d[0]==3 && d[1]==2) {  // Canvi a Febrer
        d[0]=0;
        d[1]=1;
        d[3]=2;
      }    
    }
    if (d[3]==2) {  // Febrer
      if (d[0]==2 && d[1]==9) {  // Canvi a Març
        d[0]=0;
        d[1]=1;
        d[3]=3;
      }    
    }
    if (d[3]==3) {  // Març
      if (d[0]==3 && d[1]==2) {  // Canvi a Abril
        d[0]=0;
        d[1]=1;
        d[3]=4;
      }    
    }
    if (d[3]==4) {  // Abril
      if (d[0]==3 && d[1]==1) {  // Canvi a Maig
        d[0]=0;
        d[1]=1;
        d[3]=5;
      }    
    }
    if (d[3]==5) {  // Maig
      if (d[0]==3 && d[1]==2) {  // Canvi a Juny
        d[0]=0;
        d[1]=1;
        d[3]=6;
      }    
    }
    if (d[3]==6) {  // Juny
      if (d[0]==3 && d[1]==1) {  // Canvi a Juliol
        d[0]=0;
        d[1]=1;
        d[3]=7;
      }    
    }
    if (d[3]==7) {  // Juliol
      if (d[0]==3 && d[1]==2) {  // Canvi a Agost
        d[0]=0;
        d[1]=1;
        d[3]=8;
      }    
    }
    if (d[3]==8) {  // Agost
      if (d[0]==3 && d[1]==2) {  // Canvi a Setembre
        d[0]=0;
        d[1]=1;
        d[3]=9;
      }    
    }
    if (d[3]==9) {  // Setembre
      if (d[0]==3 && d[1]==1) {  // Canvi a Octubre
        d[0]=0;
        d[1]=1;
        d[2]=1;
        d[3]=0;
      }    
    }
  } else {  // mesos 10-12
    if (d[3]==0) {  // Octubre
      if (d[0]==3 && d[1]==2) {  // Canvi a Novembre
        d[0]=0;
        d[1]=1;
        d[3]=1;
      }    
    }
    if (d[3]==1) {  // Novembre
      if (d[0]==3 && d[1]==1) {  // Canvi a Desembre
        d[0]=0;
        d[1]=1;
        d[3]=2;
      }    
    }
    if (d[3]==2) {  // Desembre
      if (d[0]==3 && d[1]==2) {  // Canvi a Gener
        d[0]=0;
        d[1]=1;
        d[2]=0;
        d[3]=1;
        d[7]++;
        if (d[7]==10) {  // Canvi decenes any
          d[7]=0;
          d[6]++;
        }
        if (d[6]==10) {  // Canvi centenes any
          d[6]=0;
          d[5]++;
        }
        if (d[5]==10) {  // Canvi milers any
          d[5]=0;
          d[4]++;
        }
      }    
    }
  }
}
void Alarma(void) {
  if(alarmaH==h && alarmaM==min && s==0){
    if(aSet==1){
      for (l=1; l<8; l++) {
        TocaNota(238, 119, 2);
      }
    }    
    if(aSet==2){
      for (l=1; l<8; l++) {
        TocaNota(189, 95, 0);
      }
    }
  }
}

 

 

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