Programació en C del PIC 16F690

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

Rellotge

Programa del grup 3

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. També incorpora funcions de cronòmetre i temporitzador.

Per a la gestió del temps fan servir el temporitzador 0 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  // La freqüència del rellotge és 4 MHz
#define clrbit(var, bit) ((var) &= ~(1 << (bit)))
#define FiTimer0 INTCONbits.T0IF  // Li assigna un nom al bit que indica el final del Timer 0
#define flipbit(var, bit) ((var) ^= (1<<(bit)))
#define PolsadorGeneral   RA3  // Li assigna un nom a l'adreça del polsador
char Cuenta;                   
char Primero;                   
char ActivaAlarma;  // 0 desactivado, 1 activado, 2 listo para ejecutar alarma
char ActivaTempo;  // 0 desactivado, 1 activado, 2 listo para ejecutar alarma
char ActivaCrono;  // 0 desactivado, 1 activado
char Polsad;  // Polsador que s'ha premut 
char Polsad2;
char H[8] = {0,0,0,0,0,0};  // Vector hora
char A[8] = {0,0,0,0,0,0};  // Vector alarma
char T[8] = {0,0,0,0,0,0};  // Vector temporizador
char C[8] = {0,0,0,0,0,0};  // Vector cronometro
// Definició de les funcions que farem servir 
void EnviaL(char Caracter);  // Envia un caràcter
void Esborra(void);
void EnviaVector (char V[]);
void SuenaAlarma(void);
void FormatoHora(char V[]);
void Hora(char V[]);
void CambioHora (char V[],char Valor);
void TocaNota(char ValPR2, char ValCCPR1L, char ValDC1B);
char VectorIgual(char V[],char U[], char Valor);
char Temporizador (char V[]);
char OnOff (char Boton, char Valor, char V[]); 
char Polsador(void);  // Funció de lectura dels polsadors
void main (void) {
  TRISA = 0xFF;  // Tot el port A és d'entrada
  TRISB = 0;  // Tot el port B és de sortida
  TRISC = 0b11110000;  // Posa els bit 0 a 3 del port C com a sortida
  PORTC = 0;  // Desactiva les sortides del port C
  ANSEL = 0b00000101;  // Configura AN0 i AN2 com entrada analògica
  ANSELH = 0;  // Desactiva les altres entrades analògiques
  ADCON1 = 0b00010000;  // Posa el conversor a 1/8 de la freqüència
  ADCON0 = 0b00001001;  // Activa el conversor A/D connectat a AN2
  CCP1CON = 0b00001100;  // Configura el PWM, mode senzill
  PIR1bits.TMR2IF = 0;  // Desactiva el bit d'interrupció del Timer 2
  T2CON = 0b00000011;  // Configura el Timer 2
  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 transmissió
  OPTION_REG = 0b10000111;  // Configuració de Timer0
  TMR0 = 61;  // Inicialitza el Timer0
  INTCON = 0b00100000;  // Habilitem la interrupció per Timer0
  INTCONbits.GIE = 1;  // Habilitem les interrupcions a nivell general
  ActivaAlarma = 0;
  ActivaTempo = 0;
  ActivaCrono = 0;
  Cuenta = 0;
  FiTimer0 = 0;  // Aquest bit es posarà a 1 quan el temporitzador acabi
  __delay_ms(1000);  // Esperem que arrenqui la pantalla
  while(1){
    Polsad = Polsador();  // Llegim els polsadors
    Primero = 0;
    // Cambio de Hora
    while (Polsad==5){  // Si s'ha premut el polsador 5
      RC0 = 1;  // LED1
      Polsad2 = Polsador();
      Esborra();
      if (Primero <= 3){  // Dejamos un rato para mostrar el modo
        EnviaL('A');
        EnviaL('D');
        EnviaL('J');
        Primero++;
        Polsad2 = 0;
        __delay_ms(500);
      } else
        EnviaVector(H);
      __delay_ms(100);
      CambioHora(H,Polsad2);
      if (Polsad2 == 5)
        ;                          
      else
        OnOff(Polsad2,0,H);
      if (PolsadorGeneral == 0){
        RC0 = 0;  // LED1
        Esborra();
        EnviaL('R');
        EnviaL('T');
        __delay_ms(500);
        break;
      }
    }
    // Configuración Alarma
    while (Polsad==4){
      RC1 = 1;  // LED2
      Polsad2 = Polsador();
      Esborra();
      if (Primero <= 3){  // Dejamos un rato para mostrar el modo
        EnviaL('A');
        EnviaL('L');
        EnviaL('M');
        Primero++;
        Polsad2 = 0;
        __delay_ms(500);
      } else
        EnviaVector(A);
      __delay_ms(100);
      CambioHora(A,Polsad2);
      ActivaAlarma = OnOff(Polsad2, ActivaAlarma, A);
      if (PolsadorGeneral == 0){
        if(ActivaAlarma !=1)
          RC1 = 0;  // LED2
        Esborra();
        EnviaL('R');
        EnviaL('T');
        __delay_ms(500);
        break;
      }
    }
    // Configuración Temporizador
    while(Polsad == 3){
      RC2 = 1;  // LED3
      Polsad2 = Polsador();
      Esborra();
      if (Primero <= 3){  // Dejamos un rato para mostrar el modo
        EnviaL('T');
        EnviaL('M');
        EnviaL('R');
        Primero++;
        Polsad2 = 0;
        __delay_ms(500);
      } else
        EnviaVector(T);
      __delay_ms(100);
      CambioHora(T,Polsad2);
      ActivaTempo = OnOff (Polsad2, ActivaTempo, T);
      if (ActivaTempo == 2){
        ActivaTempo = 0;
        SuenaAlarma();
      }
      if (PolsadorGeneral == 0){
        if(ActivaTempo !=1)
            RC2 = 0;  // LED3                
        Esborra();
        EnviaL('R');
        EnviaL('T');
        __delay_ms(500);
        break;
      }
    }
    // Activa Cronometro
    while(Polsad == 2){
      RC3 = 1;  // LED4            
      Polsad2 = Polsador();
      Esborra();
      if (Primero <= 3){  // Dejamos un rato para mostrar el modo
        EnviaL('S');
        EnviaL('T');
        EnviaL('W');
        Primero++;
        Polsad2 = 0;
        __delay_ms(500);
      } else
        EnviaVector(C);
      __delay_ms(100);
      ActivaCrono = OnOff (Polsad2, ActivaCrono, C);
      if (PolsadorGeneral == 0){
        if (ActivaCrono !=1)
          RC3 = 0;  // LED4
        Esborra();
        EnviaL('R');
        EnviaL('T');
        __delay_ms(500);
        break;
      }
    }
    // Reloj
    Esborra();            
    EnviaVector(H);
    __delay_ms(100);
    // Temporizador y Alarma
    if (ActivaTempo == 2){
      ActivaTempo = 0;  // Paramos el temporizador
      SuenaAlarma();
    }
    if(ActivaAlarma == 2){
      ActivaAlarma = 1;  // Mantenemos la alarma encendida para las siguentes 24h
      Esborra();            
      for (unsigned char i=0; i<5; i++){  // Dejamos que suene un rato
        SuenaAlarma();
        if (PolsadorGeneral == 0)  // Forzamos que pare
          break;
      }
    }
  }
}
void __interrupt() reloj(void){
  if(FiTimer0 == 1){  // Si ha acabat el temporitzador
    Cuenta++;
    // Incrementa Contador
    if (Cuenta == 20){
      Cuenta = 0;
      H[5]++;  // Sumamos 1 segundo
      Hora(H);  // Formato de la hora
      if (ActivaCrono == 1){
        C[5]++;  // Sumamos 1 segundo
        Hora(C);  // Formato de la hora
      }
      if (ActivaTempo == 1)
        ActivaTempo = Temporizador(T);      
      if(ActivaAlarma == 1)
        ActivaAlarma = VectorIgual(H,A,ActivaAlarma); 
    }
    TMR0 = 61;  // Inicialitza el Timer0
    FiTimer0 = 0;  // Tornem a posar el bit a zero
  }
}
void EnviaL(char Caracter) {
  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
}
void Esborra(void) {
  EnviaL(254);  // Caràcter de control
  EnviaL(1);  // Esborra la pantalla i posa el cursor a l'inici
}
void EnviaVector(char V[]){
  for (unsigned char i = 0; i<6;i++){
    if (i==2 || i == 4)  // Colocamos los ":"
      EnviaL(':');
    EnviaL(V[i]+'0');  // Convertimos a ASCII
  }
}
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 SuenaAlarma(void){  // Definimos melodia en una matriz
  char mat[13][3] = {{213, 156, 156},{213, 78, 156},{215, 93, 186}, {239, 104, 209},
                     {239, 52, 209}, {215, 47, 186},{213, 78, 156}, {239, 104, 209},{215, 93, 186},
                     {239, 104, 209},{253, 99, 198},{239, 104, 209},{239, 69, 139}};
  for (unsigned char i = 0;i<13; i++ )
    TocaNota(mat[i][0],mat[i][1],mat[i][2]);
}
// {H1,H2,M1,M2,S1,S2}
void FormatoHora(char V[]){
  if (V[5]>9){  // 00:00:0"10" 
    V[5]=0;  // 00:00:00    
    V[4]++;  // 00:00:10
  }
  if (V[4]>5){  // 00:00:"6"0
    V[4]=0;  // 00:00:00    
    V[3]++;  // 00:01:00    
  }
  if (V[3]>9){  // 00:0"10":00    
    V[3]=0;  // 00:00:00    
    V[2]++;  // 00:10:00    
  }
  if (V[2]>5){  // 00:"6"0:00    
    V[2]=0;  // 00:00:00    
    V[1]++;  // 01:00:00    
  }
  if (V[1]>9 && V[0]<2){  // 1"10":00:00
    V[1]=0;  // 10:00:00    
    V[0]++;  // 20:00:00    
  }
  if (V[1]>3 && V[0] == 2){  // 2"4":00:00
    V[1] = 0;  // 20:00:00
    V[0] = 0;  // 00:00:00
  }
}
void Hora(char V[]){  // Misma función que la anterior para evitar problemas en las interrupciones
  if (V[5]>9){
    V[5]=0;
    V[4]++;
  }
  if (V[4]>5){
    V[4]=0;
    V[3]++;
  }
  if (V[3]>9){
    V[3]=0;
    V[2]++;
  }
  if (V[2]>5){
    V[2]=0;
    V[1]++;
  }
  if (V[1]>9 && V[0]<2){
    V[1]=0;
    V[0]++;
  }
  if (V[1]>3 && V[0] == 2){
    V[1] = 0;
    V[0] = 0;
  }
}
void CambioHora (char V[],char Valor){
  if (Valor ==1){
    V[1]++;  // Sumamos 1 a las horas
    FormatoHora(V);
  }
  if (Valor ==2){
    V[3]++;  // Sumamos 1 a los minutos
    if(V[2] == 5 && V[3] > 9){  // Inicializamos minutos, no suma horas
      V[2] = 0;
      V[3] = 0;
    } else    
      FormatoHora(V);
  }
  if (Valor ==3){
    V[5]++;  // Sumamos 1 a los segundos
    if(V[4] == 5 && V[5] > 9){  // Inicializamos segundos, no suma minutos
      V[5] = 0;
      V[4] = 0;
    } else
      FormatoHora(V);
  }
}
char VectorIgual (char V[],char U[], char Valor){
  char n = 0;
  for (unsigned char i = 0; i<6; i++){
    if (V[i] == U[i])
      n++;  // Contamos si coinciden
  }
  if (n==6)
    return 2;
  return Valor;
}
char OnOff (char Boton, char Valor, char V[]){
  Esborra();
  if (Boton == 4){
    for (unsigned char i=0; i<6;i++)
      V[i] = 0;  // Igualamos a 0 cada componente
    EnviaL('R');
    EnviaL('E');
    EnviaL('S');
    EnviaL('E');
    EnviaL('T');
    __delay_ms(500);
  }
  if (Boton == 5){
    if (Valor != 1){
      Valor = 1;
      EnviaL('O');
      EnviaL('N');
      __delay_ms(500);
    } else{
      Valor = 0;
      EnviaL('O');
      EnviaL('F');
      EnviaL('F');
      __delay_ms(500);
    }
  }
  return Valor;
}
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;
}
char Temporizador (char V[]){
  if (V[0] == 0 && V[1] == 0 && V[2] == 0 && V[3] == 0 && V[4] == 0 && V[5] == 0){
    return 2;
  }
  if (V[5] > 0){
    V[5]--;
    return 1;
  }
  V[5] = 9;
  if(V[4] > 0){
    V[4]--;
    return 1;
  }
  V[4] = 5;
  if (V[3]> 0){
    V[3]--;
    return 1;
  }
  V[3] = 9;
  if (V[2] > 0){
    V[2]--;
    return 1;
  }
  V[2] = 5;
  if (V[1] > 0){
    V[1]--;
    return 1;
  }    
  V[1] = 9;
  if (V[0] > 0){ 
    V[0]--;
    return 1;
  }
  return 1;
}

 

 

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