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 4

En aquest cas el dispositiu mesura el corrent i en mostra el valor eficaç a la pantalla. A més, permet indicar-li quan l'aparell està en mode de repòs, prement el polsador 0, i llavors l'aparell informarà a l'usuari de quan l'aparell està en mode de repòs i quan no ho està; això s'indica amb els LED.

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
#define clrbit(var, bit) ((var) &= ~(1 << (bit)))
#define flipbit(var, bit) ((var) ^= (1<<(bit)))
unsigned int refer, mesura;
int Valor;
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
unsigned int suma = 0;
float mitjana, RMS;
unsigned char compta = 0;
char Digits[5];  // Variable amb el número dígit a dígit
                 // Digits[0] són les unitats
int Comp_val = 30;
int Avis = 0;
char caracter;
// 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 TocaNota(char valPre, char valPos, char valPR2, int numbuc, int numsil);
float TractaInput(unsigned int suma, unsigned int compta);
void main (void) {
  // Configuració d'entrades i sortides
  TRISC = 0b11010000;   // Posa els bits 0 a 3 (els LEDs: RC0, RC1, RC2, RC3) del port C com a sortida (0),
                        // tambe el bit 5 (el brunzidor: RC5) del port C ha d'estar com a sortida (0),
                        // i els altres quatre com a entrada (1)
  PORTC = 0;
  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 = 0b11000000;  // 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
  GIE = 1;  // Habilitem les interrupcions a nivell general
  while (1){  // Inici del bucle de programa
    // guarda el valor actual (Amp) i sera el que fara de comparacio maxima a partir d'ara
    if (PORTAbits.RA3 == 0) {
      Comp_val = RMS;
    }
    if(compta == 32){  // Quan ja tenim totes les mesures
      Esborra();  // Posició a la pantalla
      RMS = TractaInput(suma, compta);  // I el valor eficaç
      Valor = (int)round(RMS);
      //Pantalla surt un 10. valor es els digits mostrats a la pantalla en format enter (no ascii encara)
      if (RMS >= 10 && RMS > Comp_val && Avis == 0){       //12 per tenir marge
        //PINTEM VERD (no repos)
        PORTC = 0b00001100;               //Encen RC0, RC1
        Avis = 1;
        TocaNota(0, 7, 239, 105, 105);  // Valor que correspon aproximadament a do3
      } else if (RMS <= Comp_val){
        //Pintem vermell (repos)
        PORTC = 0b00000011;               //Encen RC2, RC3
        if (Avis == 1) {
          TocaNota(0, 5, 253, 132, 132);  // Valor que correspon aproximadament a mi3
          Avis = 0;
        }
      }
      // Preparem per mostrar el valor
      // Descomposem en dígits
      for (signed char j = 0; j < 5; j++){  // 5 dígits
        Digits[j] = Valor % 10 + '0';
        Valor = Valor / 10;
      }
      // 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
      }
      // Afegim les unitats
      EnviaL(' ');  // Espai
      EnviaL('A');
      compta = 0;
      suma = 0;
    }
    if(compta == 0){  // Preparem una sèrie de mesures
      // Llegim el valor de referència
      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 << 8 | ADRESL;
      // 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
      __delay_ms(1000);  // Esperem un segon
      TMR1H = 253;  // Inicialitza el Timer1
      TMR1L = 143;
      TMR1ON = 1;  // Posa en marxa el temporitzador, per començar les mesures
    }
  }
}
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
    GO_DONE = 1;  // Posa en marxa el conversor
    while (GO_DONE == 1)  // Mentre no acabi
      ;                   // ens esperem
    mesura = ADRESH << 8 | ADRESL;
    if(mesura < refer){
      suma = (suma + refer) - mesura;  // Ho sumem
    } else {
      suma = (suma + mesura) - refer;  // Ho sumem
    }
    compta++;
  }
  if(compta == 32){
    TMR1ON = 0;  // Aturem les lectures
  }
  if (PIR1bits.TMR2IF) {      // Comprovem que hi ha interrupció per Timer2
    PIR1bits.TMR2IF = 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 = 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 (es passa el RC5 a 0)
        PORTC = PORTC ^ port;      // Ho copia al port C (ara es 0, o LOW VOLTAGE, i apaga el brunzidor)
        if (silenci > 0){    // Si es preveu silenci
          bucles = silenci;  // Agafem la durada del silenci
          control = 1;    // Toca silenci
        }
      }
    }
  }
}
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 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
}
float TractaInput(unsigned int suma, unsigned int compta){
  mitjana = (float)suma / compta;  // Calculem la mitjana
  return ((30 / numEsp) * 5 * 100 * 1.1107 * mitjana / 1023.0);
}

 

 

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