El sensor SCT-013-30 és un element que converteix un corrent altern en una tensió alterna que podem mesurar.
[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à:

I la tensió de sortida serà:

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).

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ó:

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ó:

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.

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:

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.
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
També ens cal fer una 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.
A l'hora de calcular el valor eficaç, haurem de fer el següent càlcul:

La mitjana del corrent la multipliquem per 30, valor nominal del sensor, i la dividim per les dues espires que hem posat. Per convertir la lectura en tensió, multipliquem per 5 i dividim per 1023 i, finalment, multipliquem pel factor de forma. Atès que hi ha 32 lectures, la mitjana és la suma dividida per 32.
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.
Atès que no és fàcil dividir en assemblador, cerquem un quocient equivalent però que tingui una potència de dos com a denominador.

El programa següent llegeix els 32 valors, calcula el valor eficaç i el mostra a la pantalla.
El programa següent llegeix els 32 valors, calcula el valor eficaç i el mostra a la pantalla. Primer 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 90 μs, és la que fa les mesures.
PROCESSOR 16F690 #include <xc.inc> config FOSC = INTRCIO, WDTE = OFF, PWRTE = OFF, MCLRE = OFF, CP = OFF config CPD = OFF, BOREN = OFF, IESO = OFF, FCMEN = OFF
refer EQU 0x20 ; Lectura de la referència (2 bytes)
mesura EQU 0x22 ; Lectura del sensor (2 bytes)
Valor EQU 0x24 ; Suma de valors (2 bytes)
digits EQU 0x26 ; Valor dígit a dígit (5 bytes)
Compta EQU 0x2B ; Comptador de mesures
; També s'empra a la funció BCD5
ref EQU 0x2C ; Còpia de la referència (2 bytes)
mes EQU 0x2E ; Còpia de la mesura (2 bytes)
Caracter EQU 0x30 ; Caràcter o codi a enviar
Retard EQU 0x31 ; Variables de retard (3 bytes)
Temp EQU 0x34 ; Variable temporal a BCD5
Resul EQU 0x35 ; Valor de sortida de BCD5 (5 bytes)
Actiu EQU 0x3A ; A 1 si estem mesurant
Comptar EQU 0x3B ; Comptador de la funció BCD5
;
; Zona de memòria de dades que no depèn del banc triat
W_Copia EQU 0x70 ; Guardarà el contingut de W durant la interrupció
ST_Copia EQU 0x71 ; Guardarà STATUS durant la interrupció
PSECT code, class=CODE, delta=2, abs main: ; Adreça 0 h goto Inici ; Saltem al lloc on hi ha el programa principal nop ; Zona de memòria de programa que no utilitzem nop nop
Interrup: ; Adreça 4 h
movwf W_Copia ; Copiem l'acumulador a W_Copia
swapf STATUS,w ; Copiem STATUS a l'acumulador permutant els nibbles
clrf STATUS ; Posa a 0 i així segur que el banc és el 0
movwf ST_Copia ; Guarda STATUS permutat a ST_Copia
btfss TMR1IF ; Comprovem que hi ha interrupció per Timer 1
goto FiInt ; Si no, ja estem
bcf TMR1ON ; Aturem el Timer
movlw 253 ; Inicialitzem el timer
movwf TMR1H
movlw 143
movwf TMR1L
bsf TMR1ON ; El tornem a engegar
bcf TMR1IF ; Tornem a posar el bit a zero
; Anem a llegir el corrent
bsf GO_DONE ; Posa en marxa el conversor
btfsc GO_DONE ; Mentre no acabi
goto $-1 ; ens esperem
bsf RP0 ; Anem al banc 1
movf ADRESL,w ; Byte menys significatiu de la lectura
bcf RP0 ; Anem al banc 0
movwf mesura
movf ADRESH,w ; Byte més significatiu de la lectura
movwf mesura+1
; Anem a mirar si mesura és més gran o més petit que refer
; Restarem: mesura - refer
; Si mesuraH < referH, mesura és menor que refer
; Si mesuraH = referH mirem bytes L
; Si mesuraL < referL, mesura és menor que refer
movf refer+1,w
subwf mesura+1,w ; W = mesuraH - referH
; CARRY val 0 si el resultat és negatiu
btfss CARRY ; CARRY = 1 si mesuraH >= referH
goto MesPetit ; mesuraH < referH
; No és més petit, mirem si és igual
btfsc ZERO ; ZERO = 1 si mesuraH = referH
goto Igual ; mesuraH = referH
goto MesGran ; mesuraH > referH
Igual: ; mesuraH = referH
movf refer,w
subwf mesura,w ; W = mesuraL - referL
btfss CARRY ; CARRY = 1 si mesuraL >= referL
goto MesPetit ; mesuraL < referL
; mesura < refer
MesGran: ; mesura > refer
; Restem: mesura = mesura - refer
; Treballem amb les còpies (mes i ref)
movf mesura,w
movwf mes
movf mesura+1,w
movwf mes+1
movf refer,w
movwf ref
movf refer+1,w
movwf ref+1
comf ref,f ; Complementa referL
incf ref,f ; I l'incrementa (el conjunt equival a canviar el signe)
btfsc ZERO ; Mirem si s'activa ZERO
decf ref+1,f ; Si era zero cal decrementar referH
comf ref+1,f ; Complementem referH
movf ref,w ; Llegim a W la variable que hem de sumar
addwf mes,f ; L'afegim al byte de la dreta
btfsc CARRY ; Mirem si s'activa CARRY
incf mes+1,f ; Si s'activa, incrementem el byte superior
movf ref+1,w ; Llegim a W la variable que hem de sumar
addwf mes+1,f ; L'afegim al byte de la dreta
movf mes,w ; Guardem el resultat a mesura
movwf mesura
movf mes+1,w
movwf mesura+1
goto fiCalc
MesPetit: ; mesura < refer
; Restem: mesura = refer - mesura
; Treballem amb les còpies (mes i ref)
movf mesura,w
movwf mes
movf mesura+1,w
movwf mes+1
movf refer,w
movwf ref
movf refer+1,w
movwf ref+1
comf mes,f ; Complementa mesuraL
incf mes,f ; I l'incrementa (el conjunt equival a canviar el signe)
btfsc ZERO ; Mirem si s'activa Z
decf mes+1,f ; Si era zero cal decrementar mesuraH
comf mes+1,f ; Complementem mesuraH
movf mes,w ; Llegim a W la variable que hem de sumar
addwf ref,f ; L'afegim al byte de la dreta
btfsc CARRY ; Mirem si s'activa C
incf ref+1,f ; Si s'activa, incrementem el byte superior
movf mes+1,w ; Llegim a W la variable que hem de sumar
addwf ref+1,f ; L'afegim al byte de la dreta
movf ref,w ; Guardem el resultat a mesura
movwf mesura
movf ref+1,w
movwf mesura+1
fiCalc:
movf mesura,w ; Llegim a W la variable que hem de sumar
addwf Valor,f ; L'afegim al byte de la dreta
btfsc CARRY ; Mirem si s'activa C
incf Valor+1,f ; Si s'activa, incrementem el byte superior
movf mesura+1,w ; Llegim a W la variable que hem de sumar
addwf Valor+1,f ; L'afegim al byte de la dreta
decfsz Compta,f ; Ja hem fet una altra mesura
goto FiInt
bcf Actiu,0 ; Fi de les lectures
bcf TMR1ON ; Aturem les lectures
FiInt:
swapf ST_Copia,w ; Copia permutant ST_Copia a l'acumulador
movwf STATUS ; I ho passa a STATUS recuperant el valor d'abans
; de la interrupció
swapf W_Copia,f ; Permuta els bits de W_Copia
swapf W_Copia,w ; Torna a permutar els bits de W_Copia
; i els guarda a l'acumulador sense variar STATUS
retfie ; Torna al programa principal, on s'havia quedat
Inici:
bsf RP1 ; Anem al banc 2
; Entrades analògiques
clrf ANSEL ; Desactiva totes les entrades analògiques
movlw 00000011B ; I activa AN8 i AN9
movwf ANSELH
bcf RP1 ; Anem al banc 0
bsf RP0 ; Anem al banc 1
; Configuració d'entrades i sortides
movlw 0xF0 ; Posa els bits 0 a 3 del port C com a sortida
movwf TRISC ; i els altres quatre com a entrada
movlw 0xFF
movwf TRISA ; Tot el port A és d'entrada
; Configuració de la comunicació amb la pantalla
bsf BRGH ; Configuració de velocitat
bcf BRG16 ; Paràmetre de velocitat de 8 bits
movlw 25 ; Velocitat de 9600 baud
movwf SPBRG
bcf SYNC ; Comunicació asíncrona
bcf TX9 ; Comunicació de 8 bits
bcf RP0 ; Anem al banc 0
movlw 10 ; Retard de 2 s
call Rets ; Esperem que arrenqui la pantalla
bsf SPEN ; Activa comunicació sèrie
bsf RP0 ; Anem al banc 1
bsf TXEN ; Activa comunicació
movlw 00010000B ; Posa el conversor a 1/8 de la freqüència
movwf ADCON1
; Configuració d'interrupció
movlw 01000000B ; Habilitem la interrupció per PIE
movwf INTCON ; i deshabilitem les altres
movlw 00000001B ; Activa la interrupció per Timer 1
movwf PIE1
bcf RP0 ; Anem al banc 0
; Configuració del Timer 1
bcf TMR1IF ; Aquest bit es posarà a 1 quan el temporitzador acabi
; cal desactivar-lo des del programa
movlw 00000000B ; Configuració de Timer1
; 00 - Factor d'escala de 1
movwf T1CON
bsf GIE ; Habilitem les interrupcions a nivell general
goto Cicle
Bucle:
btfsc Actiu,0 ; Mirem si està fent lectures
goto EnCurs ; Si no ho és, esperem
movlw 254 ; Caràcter de control
movwf Caracter ; Ho guarda a la variable
call EnviaL ; Ho envia
movlw 1 ; Esborra la pantalla i posa el cursor a l'inici
movwf Caracter ; Ho guarda a la variable
call EnviaL ; Ho envia
; La suma de lectures està a suma
; Calculem el valor eficaç dividint per 4
bcf CARRY ; Quan rodem, volem que entri un zero
rrf Valor+1,f ; Primer el byte més significatiu
; El byte que surt per la dreta és a CARRY
rrf Valor,f ; i l'entrem al rodar la part menys significativa
; Ja hem dividit per 2, tornem-hi
bcf CARRY ; Quan rodem, volem que entri un zero
rrf Valor+1,f ; Primer el byte més significatiu
; El byte que surt per la dreta és a CARRY
rrf Valor,f ; i l'entrem al rodar la part menys significativa
; Ara preparem el resultat per mostrar-lo a la pantalla
call BCD5 ; Descomposem en dígits, el resultat està a Resul
call Separa ; Separem els dígits i els passem a ASCII
; Suprimim els zeros de l'esquerra
movf Resul+4,w ; Llegeix el dígit
xorlw '0' ; Compara amb 0
btfss ZERO ; Si Z està activat eren iguals
goto Enviar ; Si no eren iguals, ja estem
movlw ' ' ; Carrega un espai en blanc
movwf Resul+4 ; Substitueix el 0 per l'espai
movf Resul+3,w ; Llegeix el dígit
xorlw '0' ; Compara amb 0
btfss ZERO ; Si Z està activat eren iguals
goto Enviar ; Si no eren iguals, ja estem
movlw ' ' ; Carrega un espai en blanc
movwf Resul+3 ; Substitueix el 0 per l'espai
Enviar:
; Anem a enviar la lectura
movf Resul+4,w ; Primera xifra
movwf Caracter ; Ho guarda a la variable
call EnviaL ; Ho envia
movf Resul+3,w ; Segona xifra
movwf Caracter ; Ho guarda a la variable
call EnviaL ; Ho envia
movf Resul+2,w ; Tercera xifra
movwf Caracter ; Ho guarda a la variable
call EnviaL ; Ho envia
movlw ',' ; Carrega una coma
movwf Caracter ; Ho guarda a la variable
call EnviaL ; Ho envia
movf Resul+1,w ; Quarta xifra
movwf Caracter ; Ho guarda a la variable
call EnviaL ; Ho envia
movf Resul,w ; Cinquena xifra
movwf Caracter ; Ho guarda a la variable
call EnviaL ; Ho envia
movlw ' ' ; Carrega un espai
movwf Caracter ; Ho guarda a la variable
call EnviaL ; Ho envia
movlw 'A' ; Unitats
movwf Caracter ; Ho guarda a la variable
call EnviaL ; Ho envia
Cicle:
; Preparem una nova tongada de mesures
movlw 10100001B ; Activa el conversor connectat a AN8
movwf ADCON0 ; amb el resultat justificat per la dreta
bsf GO_DONE ; Posa en marxa el conversor
btfsc GO_DONE ; Mentre no acabi
goto $-1 ; ens esperem
; Descartem la primera lectura
bsf GO_DONE ; Posa en marxa el conversor
btfsc GO_DONE ; Mentre no acabi
goto $-1 ; ens esperem
bsf RP0 ; Anem al banc 1
movf ADRESL,w ; Byte menys significatiu de la lectura
bcf RP0 ; Anem al banc 0
movwf refer
movf ADRESH,w ; Byte més significatiu de la lectura
movwf refer+1
movlw 10100101B ; Activa el conversor connectat a AN9
movwf ADCON0 ; amb el resultat justificat per la dreta
bsf GO_DONE ; Posa en marxa el conversor
btfsc GO_DONE ; Mentre no acabi
goto $-1 ; ens esperem
; Descartem la primera lectura
movlw 5 ; Retard d'1 s
call Rets ; Esperem abans de fer una nova lectura
clrf Valor ; Començarem a sumar des de zero
clrf Valor+1
movlw 32 ; Hem de llegir 32 punts
movwf Compta
movlw 253 ; Inicialitzem el timer
movwf TMR1H
movlw 143
movwf TMR1L
bsf Actiu,0 ; Activa les lectures
bsf TMR1ON ; El posem en marxa
EnCurs:
goto Bucle
;
; Enviem caràcters a visualitzar
;
EnviaL:
movf Caracter,w ; Agafa el caràcter
movwf TXREG ; L'envia
nop
nop ; Espera 2 us
btfss TXIF ; El registre TXREG ha quedat lliure?
goto $-1 ; No, doncs esperem
return ; Tornem al lloc des d'on hem vingut
;
; Funció que converteix un número de 16 bits a BCD (5 dígits)
; El valor retornat ja està en ASCII en 5 bytes
;
BCD5:
bcf CARRY ; Posa a zero C per entrar zeros a les rotacions
movlw 16 ; Nombre d'iteracions
movwf Comptar ; Comptador d'iteracions
clrf Resul+2 ; Desenes de miler
clrf Resul+1 ; Unitats de miler i centenes
clrf Resul ; Desenes i unitats
BucleBCD:
rlf Valor,f ; Girem bits a l'esquerra a valor
rlf Valor+1,f ; Cap a valor+1
rlf Resul,f ; I cap als resultats
rlf Resul+1,f
rlf Resul+2,f
decfsz Comptar,f ; Decrementa Compta
goto ajust ; Si no és zero, ajustem el resultat
retlw 0 ; Si és zero ja estem; tornem un 0 a W
ajust: ; funció d'ajust dels resultats
movlw Resul ; Agafem l'adreça del byte de menys pes
movwf FSR ; La posa a l'adreçament indirecte
call ajustBCD ; Ajusta el byte de més a la dreta
movlw Resul+1 ; Agafem l'adreça del byte del mig
movwf FSR ; La posa a l'adreçament indirecte
call ajustBCD ; Ajusta el byte del mig
movlw Resul+2 ; Agafem l'adreça del byte de més pes
movwf FSR ; La posa a l'adreçament indirecte
call ajustBCD ; Ajusta el byte de més a l'esquerra
goto BucleBCD ; Torna a repetir el bucle (fins a 16 cops)
;
; Funció d'ajust d'un byte, primer el nibble de la dreta, després l'altre
;
ajustBCD:
movlw 0x03 ; Agafa el valor 03h
addwf INDF,w ; El suma al byte que ajustem
movwf Temp ; Ho guarda a Temp
btfsc Temp,3 ; És més gran que 07h (s'ha activat el bit 3)?
movwf INDF ; Si és cert, sobreposa el resultat
movlw 0x30 ; Agafa el valor 30h
addwf INDF,w ; El suma al byte que ajustem
movwf Temp ; Ho guarda a Temp
btfsc Temp,7 ; És més gran que 70h (s'ha activat el bit 7)?
movwf INDF ; Si és cert, sobreposa el resultat
retlw 0 ; Retorna amb un zero a W
;
; Funció que separa els dígits i converteix a ASCII
;
Separa:
movf Resul+2,w ; Agafa les desenes de miler
movwf Resul+4 ; Les posa al seu lloc
swapf Resul+1,w ; Llegeix les unitats de miler i les centenes i les guarda, permutades, a w
andlw 0x0F ; Es queda amb les unitats de miler
movwf Resul+3 ; Les posa al seu lloc
movf Resul+1,w ; Llegeix les unitats de miler i les centenes i les guarda a w
andlw 0x0F ; Es queda amb les centenes
movwf Resul+2 ; Les posa al seu lloc
swapf Resul,w ; Llegeix les desenes i les unitats i les guarda, permutades, a w
andlw 0x0F ; Es queda amb les desenes
movwf Resul+1 ; Les posa al seu lloc
movf Resul,w ; Llegeix les desenes i les unitats i les guarda a w
andlw 0x0F ; Es queda amb les unitats
movwf Resul ; Les posa al seu lloc
; Ara anem a convertir a ASCII
movlw 5 ; Cal fer-ho 5 cops
movwf Comptar ; Ho posem al comptador
movlw Resul+4 ; Adreça de la darrera xifra
movwf FSR ; Adreçament indirecte
movlw '0' ; Carrega el codi ASCII del número 0
; Sumant-li la xifra tindrem el codi ASCII
Bucle1:
addwf INDF,f ; Ho afegeix al dígit
decf FSR ; Decrementa FSR
decfsz Comptar,f ; Decrementa el comptador
goto Bucle1 ; Si no és zero, repetim
return
;
; Funció de retard de 0,2 W s
;
Rets:
movwf Retard+2
Bucles:
decfsz Retard,f
goto Bucles
decfsz Retard+1,f
goto Bucles
decfsz Retard+2,f
goto Bucles
return
END main

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