Programació en C del PIC 16F690

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

Sensor de corrent elèctric

El sensor SCT-013-30 és un element que converteix un corrent altern en una tensió alterna que podem mesurar.

Sensor de corrent elèctric  [Sensorae.com]

Aquest dispositiu consta d'un transformador de corrent (relació 1800:1) amb una resistència de càrrega de 62 Ω entre els borns de sortida, de manera que dona una sortida d'1 V quan el corrent d'entrada és de 30 A (valor nominal del dispositiu). Per al valor nominal (30 A) el corrent de secundari serà:

equació

I la tensió de sortida serà:

equació

Hem de tenir en compte que, en tractar-se d'un transformador de corrent, només serveix per a mesurar corrent altern i ens donarà un senyal en el secundari (de tensió, ja que té la resistència) proporcional a la del primari. Per tant, si el corrent del primari és altern sinusoidal, la tensió de secundari serà alterna sinusoidal.

Un senyal de tensió altern té valors tant positius com negatius. Atès que no podem connectar tensions negatives al microcontrolador, haurem de fer alguna cosa per aconseguir que els valors de tensió llegíts pel microcontrolador siguin sempre positius.

En el nostre cas tenim el sensor connectat com es mostra a la figura. Fixem-nos que un dels dos borns de sortida del sensor (S1) està connectat en el centre d'un divisor de tensió format per dues resistències iguals. Això significa que, en principi, el born S1 estarà a una tensió constant de 2,5 V (la meitat de 5 V) respecte a terra (GND).

esquema

L'altre born de sortida del sensor (S2) està connectat a l'entrada analògica AN9 del microcontrolador. Entre els dos borns de sortida del sensor tindrem, com hem comentat, un máxim d'1 V (valor nominal del sensor). Així, doncs, entre l'entrada AN9 i terra tindrem una tensió que, com a máxim, oscil·larà entre 1,5 y 3,5 V; valors perfectament compatibles amb les entrades analògiques del microcontrolador. Per a un determinat valor llegit per l'entrada analògica AN9, podem trobar el corrent real mitjançant l'expressió:

equació

Observem que prenem la lectura de l'entrada AN9, la dividim per 1023 (valor de lectura corresponent a 5 V) i la multipliquem per 5 per obtenir la tensió corresponent a aquesta entrada. Al resultat li restem 2,5 per tenir el valor real de la tensió de sortida del sensor. Aquesta tensió la multipliquem per 30 per tenir el corrent, en ampers, que circula pel primari.

En cas que la tensió d'alimentació del microcontrolador fos diferent o si les dues resistències no fossin exactament iguals, ens trobaríem amb un cert error. Podem intentar reduir aquest error llegint la tensió del punt de referència (centre del divisor de tensió) i restant-la de la lectura de l'entrada AN9. Per aquest motiu, hem connectat el punt de referència a l'entrada AN8. Així, una forma més realista de llegir el sensor seria amb l'expressió:

equació

Els valors llegits pel sensor corresponen a un senyal altern que fluctua, en principi en forma sinusoidal, amb un període de 20 ms (corresponent a la freqüència de 50 Hz, normalitzada per a Europa). Aquests valors, agafats individualment, no ens permeten deduir el valor del corrent mesurat. Per poder tenir uns valors més útils, podríem provar de trobar la mitjana dels valors instantanis de corrent; pero la mitjana d'una funció sinusoidal és sempre nul·la i, per tant, no ens aportaria cap informació.

El que ens interessa és trobar el valor eficaç del corrent. Podem definir el valor eficaç d'un corrent altern concret com aquell valor de corrent continu que, en un període, dissipa sobre una resistència la mateixa energia que el corrent altern. En el cas d'un corrent sinusoidal, podem calcular el valor eficaç (en anglès, root mean square, RMS) de manera senzilla. Primerament cal calcular el valor mitjà del valor absolut del corrent i multiplicar el resultat pel factor de forma.

equació

Cal tenir en compte que aquest valor només és vàlid si l'ona és sinusoidal. El càlcul del valor eficaç també es pot fer directament a partir de les mesures; així sempre serà vàlid, encara que la forma d'ona no sigui sinusoidal. L'equació corresponent és:

equació

El que significa anar sumant els quadrats de n valors del corrent al llarg d'un període; a l'acabar, dividir pel nombre de valors i treure l'arrel quadrada del resultat. Amb un microcontrolador com el nostre, aquest càlcul requereix força temps i memòria i, per tant, en el programa d'exemple emprarem el càlcul aproximat, fent servir el factor de forma.

Suposant que la tensió és 230 V (no disposem de cap manera de mesurar-la), podem calcular la potència aparent multiplicar la tensió i el valor eficaç del corrent.

equació

Atès, que un endoll monofàsic sol estar limitat a 16 A, podem fer passar el cable dos cops per dins de la pinça (que correspon a tenir dues espires en el primari) per així tenir el doble de resolució. En el programa dividirem pel nombre d'espires (numEsp) per corregir el valor. Hem de tenir en compte, però, que el consum dels aparells que connectem no pot superar els 15 A, perquè el corrent que veu el sensor no superi el seu màxim de 30 A.

En el programa que posem d'exemple volem fer entre 25 i 80 mesures per cicle que, recordem, dura 20 ms. Amb la velocitat per defecte del microcontrolador, els temporitzadors s'incrementen cada 1 μs. A més, procurarem que el nombre de mesures per cicle sigui potència de dos perquè és molt més senzill dividir per valors que ho són. Si, per exemple, agafem 64 punts per cicle:

	20 000 μs / 64 = 312,5 μs

Ens surt una durada que no és múltiple d'1 μs. Provem amb 32:

	20 000 μs / 32 = 625 μs

Aquest valor és adequat. Farem una lectura cada 625 μs, de manera que tindrem 32 mesures per cicle.

Per mesurar el temps, farem servir el temporitzador 1 que, amb el prescalador a 1, s'incrementarà cada 1 μs. Per ajustar el temps a 625 μs, calculem quant hem de posar a TMR1.

	TMR1 = 65536 - 625 = 64911
	TMR1H = 64911 / 256 = 253
	TMR1L = 64911 % 256 = 143

Ens cal fer una darrera comprovació. El valor de la tensió entre les dues entrades analògiques serà d'1 V. Per tant, el valor màxim de la resta de lectures (en valor absolut) serà:

	1   1023 / 5 = 205

si llegim 32 valors, la suma serà, com a molt,

	32   205 = 5560

valor que cap sobradament en una variable int.

Atès que el corrent no hauria de passar de dos dígits i disposem de cinc, en podem aprofitar dos per tenir un parell de decimals. El que farem és calcular el corrent multiplicat per cent i afegir-hi la coma en el moment d'enviar el valor a la pantalla.

El programa següent llegeix els 32 valors, calcula el valor eficaç i el mostra a la pantalla. Quan compta val zero és l'inici del procés, llavors llegim el valor de referència per a tota una tongada de mesures. Després llegim els 32 valors i, en acabar, calculem el corrent i tornem a començar. La funció d'interrupció, que dura uns 110 μs, és la que fa les mesures.

#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;
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
// 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 main (void) {
  // Configuració d'entrades i sortides
  TRISC = 0b11110000;  // Posa els bits 0 a 3 del port C com a sortida
                       // 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
  GIE = 1;  // Habilitem les interrupcions a nivell general
  while (1){  // Inici del bucle de programa
    if(compta == 32){  // Quan ja tenim totes les mesures
      Esborra();  // Posició a la pantalla
      mitjana = (float)suma / compta;  // Calculem la mitjana
      RMS = (30 / numEsp) * 5 * 100 * 1.1107 * mitjana / 1023.0;
      // Hem pultiplicat per 100 per tenir dos decimals
      // A l'hora de mostrar-ho, posarem la coma convenientment
      Valor = (int)round(RMS);  // I el valor eficaç
      // Preparem per mostrar el valor
      // Descomposem en dígits
      for (signed char j = 0; j < 5; j++){  // 5 dígits
        Digits[j] = Valor % 10;
        Valor = Valor / 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
      }
      // 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;
      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
      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;
    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 == 32){
      TMR1ON = 0;  // Aturem les lectures
  }
}
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
}

 

 

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