Programació en C del PIC 16F690

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

Rellotge

Programa del grup 2

En aquest cas és un rellotge amb alarma. Els polsadors permeten posar el rellotge en hora i ajustar l'alarma. Durant el funcionament, es va guardant la data i l'hora a la memòria EEPROM; així si es reinicia el rellotge l'hora que es mostri s'assemblarà més a la real, facilitant el seu ajust.

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 FiTimer1 PIR1bits.TMR1IF  // Li assigna un nom al bit que indica el final del Timer 1
#define flipbit(var, bit) ((var) ^= (1<<(bit)))
#define P3 RA3
char Valor;
unsigned char compta;
char Temps[3];
char set;
char Polsad;
char Alarma[2];
char Digits[5];
unsigned char mostra;
char menu;
char activada;
char activada2;
char encen;
char on;
char sona;
// Definició de les funcions que farem servir 
void EnviaL(char Caracter); // Envia un caràcter
void Esborra(char a); // 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)
char PolsadorAN(void); // Funció de lectura dels polsadors
void Mostra(char variable[30], signed char a);
  // Funció per canviar de format als números i mostrarlos a la pantalla
char Operacio(char signe, char valor, char max); // Funció suma o resta a la variable depenent del polsador 
void Musica(void); // Guarda la melodia
void SonaAlarma(void); // Funció per fer sonar l'alarma
void Paraules(char paraula[], signed char j, char a, char b); // Per mostrar paraules de la pantalla
void Encen(void);// Per recuperar les variables guardades a la EEPROM
void TocaNota(char ValPR2, char ValCCPR1L, char ValDC1B);
void DO(void);
void RE(void);
void MI(void);
void FA(void);
void SOL(void);
void escriu_EEPROM(unsigned char adre, unsigned char dada);
unsigned char llegir_EEPROM(unsigned char adre);
void main(void) {
  menu = 7;
  encen = 1;
  on = 1;
  ANSEL = 0b00000101; // Configura AN0 i AN2 com entrada analògica
  ANSELH = 0; // Desactiva les altres entrades analògiques
  TRISC = 0b00100000; // Definim com volem les E/S del port C
  TRISB = 0; // Tot el port B és de sortids
  TRISA = 0xFF; // Tot el port A és d'entrada
  PORTC = 0; // Desactiva les sortides del port C
  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, bits P1M (bits 7-6) a 00 mode senzill
  TRISC = 0b00100000; // Definim com volem les E/S del port C
  PORTC = 0; // Desactiva les sortides del port C
  __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(1); // Esborra la pantalla i posa el cursor a l'inici
  Esborra(12); // Esborra la pantalla i posa el cursor a l'inici
  FiTimer1 = 0; // Aquest bit es posarà a 1 quan el temporitzador acabi
                // cal desactivar-lo des del programa
  TMR1H = 231; // Inicialitza el Timer1
  TMR1L = 150;
  T1CON = 0b00110001; // Configuració de Timer1
  PIE1 = 1;
  INTCONbits.PEIE = 1; // Habilitem les interrupcions a nivell genera
  INTCONbits.GIE = 1; // Habilitem les interrupcions a nivell general
  while (1) { // Mentre el contingut del parèntesi sigui 1
    Polsad = PolsadorAN();
    if (menu == 7 && encen == 1) {
      Encen();
    } 
    if (Temps[0] != Alarma[0] || Temps[1] != Alarma[1]) {
      activada = llegir_EEPROM(1);
    }
    if (Polsad == 1) {
      menu = (menu + 1) % 7;
      mostra = 1;
    } else if (Polsad == 2 || Polsad == 3) {
      // 1- activada
      // 2- hores
      // 3- minuts
      // 4- horesA
      // 5- minutsA
      // 6- setmana
      if (menu == 1) { //Modifica l'hora
        Temps[0] = Operacio(Polsad, Temps[0], 23);
      } else if (menu == 2) { //Modifica els minuts
        Temps[1] = Operacio(Polsad, Temps[1], 59);
      } else if (menu == 3) { //Modifica l'hora de l'alarma
        Alarma[0] = Operacio(Polsad, Alarma[0], 23);
        escriu_EEPROM(4, Alarma[0]);
      } else if (menu == 4) {//Modifica els minuts de l'alarma
        Alarma[1] = Operacio(Polsad, Alarma[1], 59);
        escriu_EEPROM(5, Alarma[1]);
      } else if (menu == 5) { //Activa/desactiva l'alarma
        activada = (activada + 1) % 2;
        escriu_EEPROM(1, activada);
      } else if (menu == 6) { //Modifica el dia de la setmana 
        set = Operacio(Polsad, set, 7);
        escriu_EEPROM(6, set);
      }
    }
    while (Polsad > 0) {
      Polsad = PolsadorAN();
    }
    if (mostra == 1) { 
      escriu_EEPROM(2, Temps[0]);
      escriu_EEPROM(3, Temps[1]);
      mostra = 0;
      if (menu == 1 || menu == 2) { //Pantalla 2 (edició: hora)
        Esborra(12);
        Esborra(1);
        Temps[2] = 0;
        char paraula[] = "HORA:";
        Paraules(paraula, 5, 1, 1);
        Cursor(2, 6);
        Mostra(Temps, 2);
        if (menu == 1) {
          Esborra(12);
          Cursor(2, 7);
          Esborra(14);
        }
        if (menu == 2) {
          Esborra(12);
          Cursor(2, 10);
          Esborra(14);
        }
      } else if (menu == 3 || menu == 4 || menu == 5) { //Pantalla 3(Edició: Alarma)
        Esborra(12);
        Esborra(1);
        char paraula[] = "ALARMA:";
        Paraules(paraula, 7, 1, 1);
        Cursor(2, 8);
        Mostra(Alarma, 2);
        if (menu == 3) {
          Esborra(12);
          Cursor(2, 9);
          Esborra(14);
        }
        if (menu == 4) {
          Esborra(12);
          Cursor(2, 12);
          Esborra(14);
        }
        if (menu == 5) {
          if (activada == 1) {
            char paraula[] = "ACT";
            Paraules(paraula, 3, 2, 1);
          }
          if (activada == 0) {
            char paraula[] = "DES";
            Paraules(paraula, 3, 2, 1);
          }
        }
      } else if (menu == 6) { // Pantalla 4 (Edició: Dia setmana)
        Esborra(12);
        Esborra(1);
        char paraula[] = "DIA SET:";
        Paraules(paraula, 8, 1, 1);
        if (set == 0) {
          char paraula[] = "DL";
          Paraules(paraula, 2, 2, 9);
        }
        if (set == 1) {
          char paraula[] = "DM";
          Paraules(paraula, 2, 2, 9);
        }
        if (set == 2) {
          char paraula[] = "DC";
          Paraules(paraula, 2, 2, 9);
        }
        if (set == 3) {
          char paraula[] = "DJ";
          Paraules(paraula, 2, 2, 9);
        }
        if (set == 4) {
          char paraula[] = "DV";
          Paraules(paraula, 2, 2, 9);
        }
        if (set == 5) {
          char paraula[] = "DS";
          Paraules(paraula, 2, 2, 9);
        }
        if (set == 6) {
          char paraula[] = "DG";
          Paraules(paraula, 2, 2, 9);
        }
      } else if (menu == 7) { //Pantalla 0 (rellotge acabat d'encendre)
        if (on == 1) {
          Esborra(12);
          Esborra(1);
          Cursor(1, 2);
          Mostra(Temps, 2);
        }
        if (on == 0) {
          Esborra(12);
          Esborra(1);
        }
      } else { //Pantalla 1 (pantalla principal)
        Esborra(12);
        Esborra(1);
        Cursor(1, 7);
        Mostra(Temps, 2);
        if (set == 0) {                    
          char paraula[] = "DL";
          Paraules(paraula, 2, 2, 1);
        }
        if (set == 1) {
          char paraula[] = "DM";
          Paraules(paraula, 2, 2, 1);
        }
        if (set == 2) {
          char paraula[] = "DC";
          Paraules(paraula, 2, 2, 1);
        }
        if (set == 3) {
          char paraula[] = "DJ";
          Paraules(paraula, 2, 2, 1);
        }
        if (set == 4) {
          char paraula[] = "DV";
          Paraules(paraula, 2, 2, 1);
        }
        if (set == 5) {
          char paraula[] = "DS";
          Paraules(paraula, 2, 2, 1);
        }
        if (set == 6) {
          char paraula[] = "DG";
          Paraules(paraula, 2, 2, 1);
        }
        SonaAlarma(); //L'alarma només sona si el rellotge està a la pantalla principal
      }
    }
  }
}
void __interrupt() temporit(void) { // Línia alternativa
  //s'utilitza pq el timer no s'endarrereixi
  if (FiTimer1) {
    T1CONbits.TMR1ON = 0; // Atura momentàniament el Timer1
    TMR1H = 231; // Inicialitza el Timer1
    TMR1L = 150;
    T1CONbits.TMR1ON = 1; // Torna a engegar el Timer1
    compta++; //Cada cop que el timer acaba suma 1 al comptador
    FiTimer1 = 0;
    mostra = 0;
    if (compta == 10) {
      on = 0;
      mostra = 1;
    }
    if (compta == 20) { // quan el comptador arriba a 20 vol dir que ha passat un segon
      on = 1;
      compta = 0;
      mostra = 1;
      Temps[2]++; //sumem segons fins q arriben a 60
      if (Temps[2] == 60) {
        Temps[2] = 0; // segons = 0 i sumem minuts fins que arriben a 60 
        Temps[1]++;
        if (Temps[1] == 60) {
          Temps[1] = 0; // min=60 i sumem hores
          Temps[0]++;
          if (Temps[0] > 23) {
            Temps[0] = 0; // quan les hores arriben a 24 ja ha passat un dia i tornen a ser 0
            set = (set + 1) % 7;
          }
        }
      }
    }
  }
}
void EnviaL(char Caracter) { //Programa del Exemple (envia caracters a la pantalla))
  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(char a) { // Programa del exemple (esborra tot el que hi ha a la pantalla)
  EnviaL(254); // Caràcter de control
  EnviaL(a); // Esborra la pantalla i posa el cursor a l'inici
}
void Cursor(char Filera, char Columna) { //Programa del exemple (posiciona els caracters a la pantalla)
  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
}
char PolsadorAN(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 Paraules(char paraula[], signed char i,  char a,  char b) {
  Cursor(a, b);
  for (signed char j = 0; j < i; j++) { // 5 dígits
    EnviaL(paraula[j]);
  }
}
void Mostra(char variable[3], signed char a) {
  // es canvien el format del números per poder dibuixar números reals
  for (signed char i = 0; i < a; i++) {
    Valor = variable[i];
    for (signed char j = 0; j < 5; j++) { // 5 dígits
      Digits[j] = Valor % 10;
      Valor = Valor / 10;
    }
    for (signed char j = 0; j < 5; j++) { // 5 dígits
      Digits[j] = Digits[j] + '0'; // Li sumem el codi ASCII de 0
    }
    EnviaL(Digits[1]);
    EnviaL(Digits[0]);
    if (i < 1) {
      EnviaL(':');
    }
  }
}
char Operacio(char signe, char valor, char max) {
  if (signe == 3) {
    if (valor == 0) {
      valor = max;
    } else {
      valor--;
    }
  }
  if (signe == 2) {
    valor++;
    if (valor > max) {
      valor = 0;
    }
  }
  return valor;
}
void SonaAlarma(void) {
  sona = 0;
  if (activada == 1) {
    if (Temps[0] == Alarma[0] && Temps[1] == Alarma[1]) {
      sona = 1;
    }
  }
  while (sona == 1) {
    Musica();
  }
}
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
  if (P3 == 0) {
    activada = 0;
    sona = 0;
  }
}
void DO(void) {
  TocaNota(238, 119, 2);
  __delay_ms(100);
}
void RE(void) {
  TocaNota(212, 106, 2);
  __delay_ms(100);
}
void MI(void) {
  TocaNota(189, 95, 0);
  __delay_ms(100);
}
void FA(void) {
  TocaNota(178, 89, 2);
  __delay_ms(100);
}
void SOL(void) {
  TocaNota(158, 79, 2);
  __delay_ms(100);
}
void Musica() {
  MI();
  MI();
  FA();
  SOL();
  SOL();
  FA();
  MI();
  RE();
  DO();
  DO();
  RE();
  MI();
  MI();
  RE();
  RE();
  MI();
  MI();
  FA();
  SOL();
  SOL();
  FA();
  MI();
  RE();
  DO();
  DO();
  RE();
  MI();
  RE();
  DO();
  DO();
}
void escriu_EEPROM(unsigned char adre, unsigned char dada) {
  // Escriu el valor donat a l'adreça EEPROM indicada
  EECON1bits.EEPGD = 0; // Seleccionem EEPROM i no memòria de programa
  EEDATA = dada; // Valor que volem escriure
  EEADR = adre; // Adreça que volem escriure
  EECON1bits.WREN = 1; // Habilita l'escriptura
  INTCONbits.GIE = 0; // Desactiva interrupcions
  EECON2 = 0x55; // Cal escriure uns valors predeterminats (55h i AAh)
  EECON2 = 0xAA; // a EECON2 per activar el procés d'escriptura
  EECON1bits.WR = 1; // Activa l'escriptura
  while (EECON1bits.WR == 1) // Esperem a que l'escriptura acabi
    ;
  EECON1bits.WREN = 0; // Deshabilitem l'escriptura
  INTCONbits.GIE = 1; // Reactivem interrupcions
}
unsigned char llegir_EEPROM(unsigned char adre) {
  // Llegeix el contingut de l'EEPROM
  // a la posició indicada per l'adreça
  EECON1bits.EEPGD = 0; // Seleccionem EEPROM i no memòria de programa
  EEADR = adre; // Adreça que volem llegir
  EECON1bits.RD = 1; // Activa la lectura
  return EEDATA; // Llegeix i retorna el resultat
}
void Encen(void) {
  encen = 0;
  activada = llegir_EEPROM(1);
  Temps[0] = llegir_EEPROM(2);
  Temps[1] = llegir_EEPROM(3);
  Temps[2] = 0;
  Alarma[0] = llegir_EEPROM(4);
  Alarma[1] = llegir_EEPROM(5);
  set = llegir_EEPROM(6);
}

 

 

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