Programació en C del PIC 16F690

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

Mesurador de corrent elèctric

Programa del grup 3

En aquest cas el dispositiu mesura el corrent i mostra a la pantalla la potència consumida i el cost de l'energia acumulat des de la posada en marxa de l'aparell. Aquest dispositiu està pensat per a un ús durant un espai de temps reduït, no per a una mesura contínua.

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
#include <math.h>
#define _XTAL_FREQ  4000000  // La freqüència del rellotge és 4 MHz
#define numEsp  2
unsigned int refer, mesura;
int Valor;
int Preu;
int comptaP = 0;
int temps = 1;
unsigned int suma = 0;
unsigned int sumatori = 0;
float mitjana, RMS;
unsigned int  compta = 0;
char Digits[5];  // Variable amb el número dígit a dígit
                 // Digits[0] són les unitats
// Definició de les funcions que farem servir 
void Esborra(void);  // Esborra la pantalla i posa el cursor a l'inici
void EnviaL(char Caracter);  // Envia un caràcter
void Cursor(char Filera, char Columna);         // Posiciona el cursor
                                                // (filera 1 a 2 i columna 1 a 32, segons pantalla)
void Llegir (void); // Llegeix la referència
void Escriure(char Nom);
void main (void) {
  // Configuració d'entrades i sortides
  TRISC = 0b11110000;  // Posa els bits 0 a 3 del port C com a sortida
  PORTC = 0;                     // i els altres quatre com a entrada
  TRISA = 0xFF;  // Tot el port A és d'entrada
  __delay_ms(2000);  // Esperem que arrenqui la pantalla
  // Configuració de la comunicació amb la pantalla
  BRGH = 1;  // Configuració de velocitat
  BRG16 = 0;  // Paràmetre de velocitat de 8 bits
  SPBRG = 25;  // Velocitat de 9600 baud
  SYNC = 0;  // Comunicació asíncrona
  TX9 = 0;  // Comunicació de 8 bits
  SPEN = 1;  // Activa comunicació sèrie
  TXEN = 1;  // Activa comunicació
  // Entrades analògiques
  ANSEL = 0b00000000;  // Desactiva totes les entrades analògiques
  ANSELH = 0b00000011;        // I activa AN8 i AN9
  ADCON1 = 0b00010000;  // Posa el conversor a 1/8 de la freqüència
  // Configuració d'interrupció
  INTCON = 0b01000000;  // Habilitem la interrupció per PIE
                        // i deshabilitem les altres
  PIE1 = 0b00000001;  // Activa la interrupció per Timer 1
  // Configuració del Timer 1
  TMR1IF = 0;  // Aquest bit es posarà a 1 quan el temporitzador acabi
               // cal desactivar-lo des del programa
  TMR1H = 253;  // Inicialitza el Timer1
  TMR1L = 143;
  T1CON = 0b00000000;  // Configuració de Timer1
                       // 00 - Factor d'escala de 1
                       // I el posem en marxa
  Llegir();
  // Preparem per a les lectures
  ADCON0 = 0b10100101;  // Activa el conversor connectat a AN9
                        // amb el resultat justificat per la dreta
  GO_DONE = 1;  // Posa en marxa el conversor
  while (GO_DONE == 1)  // Mentre no acabi
    ;                   // ens esperem
  // Descartem la primera lectura  
  GIE = 1;  // Habilitem les interrupcions a nivell general
  TMR1ON = 1;  // Posa en marxa el temporitzador, per començar les mesures
  Esborra();
  while (1){  // Inici del bucle de programa
    if(compta == 32){  // Quan ja tenim totes les mesures
      comptaP=comptaP+1;
      temps = temps + 1;
      mitjana = (float)suma / compta;  // Calculem la mitjana
      RMS = (30 / numEsp) *  115  * 1.1107 * mitjana / 1023.0;
      // Hem multiplicat per 100 per tenir dos decimals
      // El 115 ve de multiplicar 5*230V/1000 *100
      // A l'hora de mostrar-ho, posarem la coma convenientment
      Valor = (int)round(RMS);  // I el valor eficaç
      PORTC = 0b00000000;
      if (temps>60){
        PORTC = 0b00000001;  // Activa el bit 0  del port C i, per tant, encén el LED al cap d'un minut
      }
      if (temps>120){
        PORTC = 0b00000011;  // Activa els bits 0 i 1 del port C i, per tant, encén el LED al cap de dos minuts                        
      }
      if (temps>300){
        PORTC = 0b00000111;  // Activa els bits 0 1 i 2 del port C i, per tant, encén el LED al cap de cinc minuts
      }
      if (temps>600){
        PORTC = 0b00001111;  // Activa els bits 0 1 2 i 3 del port C i, per tant, encén el LED al cap de deu minuts
      }
      // Preparem per mostrar el valor
      // Descomposem en dígits
      sumatori=sumatori+Valor;
      Cursor(1, 1);
      Escriure(Valor);
      // Afegim les unitats
      EnviaL(' ');        // Espai
      EnviaL('k');
      EnviaL('W');
      suma = 0;
      if (comptaP == 60){
        // comptaP s'incrementa cada cop que compta = 32, és a dir, cada segon perquè compta arriba fins a 1600.
        // El preu s'actualitzarà cada minut
        Preu=(int)round(sumatori*0.0002387216);
        // dividim el sumatori entre 60 per obtenir la potència mitja en un minut.
        // 0.008594 és el preu mig del kW/h segons la 'Red Eléctrica de España'.
        // Dividim entre 60 per obtenir kW/min. Multipliquem per 100 per donar el preu en centims.
        // Per tant: 0,08594/60/60*100=0.0002387216 
        Cursor(2, 1);
        Escriure(Preu);
        // Afegim les unitats
        EnviaL(' ');        // Espai
        EnviaL('C');
        EnviaL('E');
        EnviaL('N');
        EnviaL('T');
        comptaP = 0;
      }
    }  
  }
}
void __interrupt() temporit(void){
  // No desactivem les interrupcions perquè només en tenim una que dura poc
  if(TMR1IF){  // Comprovem que hi ha interrupció per Timer 1
    TMR1ON = 0;  // Aturem el Timer
    TMR1H = 253;  // Inicialitza el Timer1
    TMR1L = 143;
    TMR1ON = 1;  // El tornem a engegar
    TMR1IF = 0;  // Tornem a posar el bit a zero
    // Anem a llegir el corrent
    if (compta<32){
      GO_DONE = 1;  // Posa en marxa el conversor
      while (GO_DONE == 1)  // Mentre no acabi
        ;                   // ens esperem
      mesura = ADRESH;
      mesura = mesura << 8;
      mesura = mesura | ADRESL;
      if(mesura < refer){
        suma = (suma + refer) - mesura;  // Ho sumem
      } else {
        suma = (suma + mesura) - refer;  // Ho sumem
      }
    }
    compta++;
    if (compta == 1590){
      Llegir();   
    }
    if (compta == 1600){
      compta = 0;     
    } 
  }
}
void EnviaL(char Caracter){
  TXREG = Caracter;  // Agafa el caràcter i l'envia
  __delay_ms(1);  // Donem temps
  while (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 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 Llegir(void) {
  ADCON0 = 0b10100001;  // Activa el conversor connectat a AN8
                        // amb el resultat justificat per la dreta
  GO_DONE = 1;  // Posa en marxa el conversor
  while (GO_DONE == 1)  // Mentre no acabi
    ;                   // ens esperem
  // Descartem la primera lectura
  GO_DONE = 1;  // Posa en marxa el conversor
  while (GO_DONE == 1)  // Mentre no acabi
    ;                   // ens esperem
  refer = ADRESH;
  refer = refer << 8;
  refer = refer | ADRESL;
  // Preparem per a les lectures
  ADCON0 = 0b10100101;  // Activa el conversor connectat a AN9
                        // amb el resultat justificat per la dreta    
}
void Escriure(char Nom){
  for (signed char j = 0; j < 5; j++){  // 5 dígits
    Digits[j] = Nom % 10;
    Nom = Nom / 10;
  }
  // Convertim a ASCII
  for (signed char j = 0; j < 5; j++){  // 5 dígits
    Digits[j] = Digits[j] + '0';  // Li sumem el codi ASCII de 0
  }
  // Eliminem zeros a l'esquerra
  if(Digits[4] == '0') {  // Mirem si el primer dígit és 0
    Digits[4] = ' ';  // Si ho és, hi posem un espai
    if(Digits[3] == '0') {  // Mirem si el segon dígit és 0
      Digits[3] = ' ';  // Si ho és, hi posem un espai
    }
  }
  // Enviem a la pantalla
  for (signed char j = 4; j >= 0; j--){        // 5 dígits
    if(j == 1){
      EnviaL(',');        // Coma
    }
    EnviaL(Digits[j]);        // Número
  }
}

 

 

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