viernes, 26 de enero de 2024

SPI Identificacion rfID con RC522

Uso del modulo RC522 con PIC

Fig1. Tarjetas y modulo RC522 rfID
 
Hola, te doy la bienvenida por visitar este blog, creado para compartir el mutuo interés en la electrónica y en especial la programación de microcontroladores PIC, te recuerdo que estoy atento a cualquier sugerencia o critica constructiva relacionada con esta publicación, al final dejo mis datos de contacto.
En esta ocasión veremos como comunicar un microcontrolador PIC16F con el modulo RC522, el cual permite llevar a cabo al lectura de tarjetas basadas en la tecnología rfID. El propósito sera de establecer la comunicación SPI, recuperar el numero serial de una tarjeta MiFARE y enviar este numero como mensaje a través del puerto serie UART del PIC16F.
 
La programación del microcontrolador se realizara utilizando el software  de diseño  MPLABX  y el compilador de lenguaje C para PIC XC8 ambos disponibles en la pagina de microchip de forma gratuita. Aquí dejo los enlaces de las versiones utilizadas para nuestro ejemplo:  <<MPLABX v6.20>>   <<XC8 v2.45>>
Mencionar también que es necesario contar con conocimientos mínimos sobre programación en lenguaje C y el uso de microcontroladores PIC16F.
 
Introducción a la Tecnología rfID
El termino RFID(Radio Frequency Identification), hace referencia al sistema de identificación basado en radiofrecuencia, el cual posibilita el almacenamiento y recuperación de datos en forma remota utilizando etiquetas o tarjetas de identificación diseñadas para este fin.
El sistema opera en los rangos de 125 134kHz, 140 148.5kHz clasificado como frecuencia baja y 13.56MHz en frecuencia alta. El conjunto esta formado de dos partes:

Fig2. Sistema rfID
  • Etiqueta(Transpondedor): formado por una antena(RF), la unidad de control digital(MCU) y una memoria(EEPROM).
  • Lector(Interrogador): compuesto por la antena(RF), un decodificador y el puerto de comunicación serial UART/SPI/I2C.
El lector mantiene a su alrededor un campo electromagnético de modo que al acercar una etiqueta al lector, ésta se alimenta de la energía inducida por el campo electromagnético, estableciendo así la comunicación.
La distancia de lectura depende de la potencia del módulo lector, en nuestro caso son aproximadamente 50mm(RC522), pero existen lectores con mayor rango de alcance. 
En cuanto a la etiqueta que utilizaremos, MIFARE es una tecnología de tarjetas inteligentes sin contacto, propiedad de NXP Semiconductors que cumplen con el estándar ISO-14443 tipo A. Siendo actualmente una de las que mayor uso tiene a nivel mundial.
En forma general podemos encontrarlos bajo la siguiente clasificación:
  • MIFARE Ultralight 512 bit Sin Seguridad
  • MIFARE Classic 1K-4Kbytes Seguridad Crypto-1
  • MIFARE Desfire 4Kbit Seguridad 3DES
El ISO-14443 consta de cuatro partes y se describen dos tipos de tarjetas, el tipo A y el tipo B, las principales diferencias entre ambas, se centra en el mecanismo de modulación, codificación y protocolo de inicialización.
 
Descripción del Modulo RC522.
Es un lector para tarjetas rfID basado en el circuito integrado MFRC522, opera en frecuencia 13.56MHz y soporta ISO14443 tipo A. El modulo es de fácil conexión al microcontrolador mediante la interfaz serial SPI el cual puede opera hasta los 10MHz, con alimentación de 3.3V y consumo inferior a los 100mA.  La fig3. ilustra la distribución de pines del modulo RC522, la conexión al modulo sera directa siempre que el microcontrolador trabaje con 3.3V, caso contrario era necesario convertidores de nivel en las lineas MISO/MOSI/SCK/SS.
Fig3. Pines modulo RC522

Descripción de la Tarjeta MiFare 1K.
Esta tarjeta desarrollada por NXP posibilita llevar a cabo transacciones en menos de 100ms, lo cual resulta adecuado para aplicaciones como el cobro de peaje, boletería y control de acceso. En cuanto a sus características describiremos tres:
 
1. Identificación.  Provee un mecanismo de Anti-colisión que posibilita la lectura simultanea de varias tarjetas, el proceso dura aproximadamente 3ms, con incremento de 1ms por cada colisión detectada.
 
2. Almacenamiento. Consta de una memoria EEPROM con capacidad de 1kB, la misma que se encuentra distribuida en 16 sectores, cada sector formado por 4 bloques y cada bloque formado por 16 bytes, ver fig4.
Fig4. Mapa de memoria EEPROM 1kbyte
El ultimo bloque de cada sector se utiliza para guardar las llaves y los bits de configuracion de acceso por cada sector, cada llave A/B se compone de 6 bytes con un valor por defecto de 0xFF-FF-FF-FF-FF-FF-FF, la llave A no se puede leer por esta razón es utilizada para la autenticación, mientras que la llave B que es opcional si puede leerse,  en este bloque también se encuentran los bits de acceso con un valor por defecto de 0xFF078069, donde el ultimo byte, puede usarse para guardar datos del usuario.
3. Seguridad. Cuenta con identificador único (4 bytes), autenticación mutua de tres pasos y clave de acceso por sector (KeyA/B). El proceso de autenticación de tres pasos se ilustra en la fig5.
Fig5. Procedimiento de autenticación de tres pasos
Observe que de acuerdo al esquema que muestra la Fig5. las operaciones en memoria requieren completar el proceso de autenticación, el cual implica validar las llaves A/B para acceder a cada bloque y efectuar cambios incluyendo la actualización de llaves, el proceso de autenticación esta limitado a una cantidad de intentos, pasado la cantidad de intentos el acceso quedara bloqueado de manera irreversible.
Con el valor por defecto 0xFF0780 que tiene los bits de control de cada bloque, se permiten el acceso autenticado con llave A para los siguiente:
  • Modificar la llave A, pero no es posible leer su valor.
  • Modificar los bits de acceso y la llave B del bloque.
  • Realizar operaciones de lectura, escritura, incremento y decremento.
  • Se puede leer la llave B, siendo posible usar este campo para datos.
A raíz de la amplia aceptación de esta tecnología y el buen éxito de la familia MiFARE Classic, los requerimiento de seguridad en la industria también se han incrementado, y por lo tanto es  importante considerar el de nuevos productos como la MiFARE Plus.
 
 Esquema del circuito PIC

La figura 6 nos muestra el esquema del circuito utilizado para las pruebas de nuestro programa, y donde se puede observar la conexión entre el microcontrolador PIC16F887 y el modulo RC522. Parte del circuito esta alimentado por una fuente de 5V, y a través de un regulador de voltaje lineal MCP1702, se consiguen los 3.3V necesarios para el funcionamiento del modulo RC522, por esta razón para garantizar la compatibilidad de los niveles lógicos en las lineas de comunicación del modulo RFID, se utilizan las resistencias como divisores de tensión.  Por otro lado la comunicación serial con la PC, utiliza un convertidor USB a UART, en nuestro caso es un modulo CP2102, pero puede ser cualquier otro modelo. Finalmente se dispone de tres diodos LED, uno conectado al pin RE2 que servirá para indicar la actividad del programa y dos conectados al pin RD0 y RD1 que nos indicaran mediante el color si el acceso esta autorizado(Verde) o denegado(Rojo), además un pulsador de entrada en RB0 permite realizar un procedimiento de carga de valor en la memoria de la tarjeta RFID.

Fig6. Esquema del circuito PIC16-RC522

Programa del Microcontrolador PIC
El objetivo de este programa es comprobar la conectividad PIC16F - RC522, para lo cual se realizara la identificación de una tarjeta MiFARE, para obtener la etiqueta del modelo de tarjeta y el numero de serie correspondiente, sin entrar en la fase de autenticación y operaciones en la memoria EEPROM, que veremos mas adelante con el programa final presente en el archivo de proyecto MPLABX cuyo enlace se encuentra al final. 

En el programa se hace uso de las interrupciones del temporizador TMR0 y el receptor USART del PIC, cabe resaltar que ninguna de las tareas en el programa representa un proceso bloqueante, la codificación en si utiliza una técnica de programación por estados, si quieres conocer mas detalles al respecto, te recomiendo revises antes de continuar, la siguiente publicación. 

En programa haremos usos de diversos procedimientos y funciones declarados en los archivos de cabecera de las librerías mrc522.h y spi.h, aclarar que el  código de estas librerías se crearon a partir de otras fuentes que encontré en la red.

Ahora describiré las secciones que tiene el código principal main.c con una breve explicación de lo que se pretende realizar. Recuerda que al final de esta publicación esta el enlace para descarga del proyecto MPLABX que contiene todos lo archivos utilizados.

#pragma config FOSC=INTRC_NOCLKOUT, WDTE = OFF, BOREN = OFF, LVP = OFF
#include <xc.h>
#include <stdio.h>
#include "spi.h"
#include "mrc522.h"
#define LEDpin PORTEbits.RE2
//Led de la tarjeta
#define DS1pin PORTDbits.RD0
//Led Verde
#define DS2pin PORTDbits.RD1
//Led Rojo
#define SW1pin PORTBbits.RB0
//Entrada Selector
volatile __bit tickms;
uint8_t buff[16];    
uint16_t tagtype;
//2-byre para el tag_id
uint32_t tagserial;
//4-byte para el tag_serial
uint8_t tagkey[6]={0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
//Default

void main(void)
{
    setupMCU();
//Configura el PIC
    MRCInit();
//Inicializa el modulo RC522
    printf("\r\nLISTA RFID\r\n");
    while(1)
    {
        if(tickms)
//Ejecuta cada 1ms
        {
            tickms = 0;
            taskLED();
//Destella LED
            taskAPP();
//Lectura y cambio del RFID
        }
    }
}

En las lineas luego de la configuracn e inicialización de los modulo, el programa ingresa en un bucle condicionado por la bandera tick1ms, que se activa cada milisegundo de acuerdo a la interrupción del temporizador TMR0, para este fin se utiliza la interrupción del temporizador TMR0. Por lo tanto podemos resumir que dentro del bucle del programa principal se realiza la llamada concurrente cada milisegundo de dos procedimientos:

taskLED: Es un procedimiento que se ejecuta en cada milisegundo, internamente utiliza una variable estática como contador para determinar la condición de encendido y apagado del LED conectado al pin RE2, el objetivo es destellar la luz cada segundo con un ciclo activo(encendido) de un 20%, para indicar la actividad del programa que corre el PIC. las siguientes lineas describen el código de este procedimiento. 

void taskLED(void) //Destello de LED1 1Hz al 20%
{
    static uint16_t cnt = 0;
    if(cnt++ > 999)
    {
        cnt = 0;
        LEDpin = 1;
//Activa LED
    }
    if(cnt == 200) LEDpin = 0;
//Apaga LED
}

taskAPP: Este procedimiento que internamente subdivide el trabajo en estados, se encarga de la comunicación con el modulo RFID llevando a cabo las siguientes operaciones:

- Detectar una tarjeta valida en el lector
- Recuperar su numero de serie
- Seleccionar la tarjeta para la autenticacion de un sector
- Efectuar las operaciones respectivas.

 Las siguientes lineas muestran el código de este procedimiento que describiremos por etapas. 

void taskAPP(void)
{
    static uint8_t state = 0;
    static uint16_t cnt = 0;
    int32_t value = 0;
    uint8_t res, i;
    switch(state)
    {
        case 0:
//Detecta tarjeta RFID,  con intervalos de 250ms
            if(MRCRequest(PICC_REQIDL, buff)== MI_OK)
//step1
            {
                tagtype = buff[0];
                tagtype <<= 8;
                tagtype |= buff[1];        
                state = 1;
//Estado de Tarjeta detectada
            }
            else
            {
                MRCHalt();
//Finaliza comunicación RFID
                state = 2;
//Estado de espera 250ms
            }
            break;
        case 1:
//Lectura del serial ID
            if(MRCAntiColl(buff) == MI_OK)
//step2   
            {
                tagserial = buff[0];
                tagserial <<= 8;
                tagserial |= buff[1];
                tagserial <<= 8;
                tagserial |= buff[2];
                tagserial <<= 8;
                tagserial |= buff[3];
                printf("\r\nID Card:%lX\r\n",tagserial);
                if(MRCSelectTag(buff) == 0x08) state = 4;
//step3                             else
                {
                    printf("SAK Incorrecto");
                    MRCHalt();
//Finaliza comunicación RFID
                    state = 3;
                }
            }
            else
            {
                MRCHalt();
//Finaliza comunicación RFID
                state = 2;
            }
            break;
        case 2:
//Espera de 250ms para detección
            if(cnt++ > 249)
            {
                cnt = 0;
                state = 0;
//Reinicia estado
            } else _nop();
            break;    
        case 3:
//Espera de 2000ms entre lecturas  
            if(cnt++ > 1999)
//Espera dos segundos entre lecturas
            {
                DS2pin = 0;
                DS1pin = 0;
                cnt = 0;
                state = 0;
            } else _nop();
            break;
        case 4:
//Autenticación y actualización del valor del bloque 2
                if(MRCAuth(PICC_AUTHENT1A, 2, tagkey, buff) == MI_OK)
                {
                    if(SW1pin == 0)
//Si pulsador esta presionado
                    {
                        MRCEncodeValue(5, 2, buff);
//Codifica Valor 5
                        MRCWrite(2, buff);
//Escribe en el bloque 2
                        printf("Recargado");
                    }
                    else
                    {
                        MRCUpdateValue(2, PICC_DECREMENT, 1);
//Decrementa
                        MRCRead(2, buff);
//Lectura del bloque 2
                        value = MRCDecodeValue(buff);
//Decodifica valor
                        if(value >=0)
                        {
                            printf("Credito:%ld", value);
                            DS1pin = 1;
                        }
                        else
                        {
                            printf("Sin credito");
                            DS2pin = 1;
                        }
                    }                
                }
                MRCHalt();
                state = 3;
            break;
    }
}

El primer estado (case 0) dentro del procedimiento, verifica la disponibilidad de un chip rfID valido con lector RC522, si no hay un chip identificado el procedimiento realizara una espera de 200ms para repetir el proceso. La función utilizada es MRCRequest(PICC_REQIDL, buff), que retornara 0 (MI_OK) si existe una tarjeta como la MiFARE dentro de la zona de proximidad del lector RC522, y guardara en el vector buff dos bytes de identificación cuyos valores corresponden con la siguiente tabla:

  • 0x4400 = Mifare_UltraLight
  • 0x0400 = Mifare_One(S50)
  • 0x0200 = Mifare_One(S70)
  • 0x0800 = Mifare_Pro(X)
  • 0x4403 = Mifare_DESFire

Si la identificación es correcta, el procedimiento pasara el segundo estado (case 1) para realizar la lectura del numero serial de la tarjeta y preparar la etapa de autenticacion. 

El numero de serie se obtiene con la función MRCAntiColl(buff), esta función recupera los primeros cuatro bytes del bloque 3, sector 0 que es de solo lectura y contiene el numero serial único establecido por el fabricante conforme a la figura 7.

Fig7. Datos del fabricante, solo para lectura
 
Una vez registrado el numero de serie de la tarjeta en el vector buff, se enviara por el puerto UART un mensaje ID Card: 03505010 y la tarjeta sera seleccionada para la autenticacion mediante la función MRCSelectTag(buff), para el caso de una tarjeta MiFARE el valor a retornar debe ser 0x08 para que el procedimiento inicie la autenticacion pasando al quinto estado (case 4), caso contrario se pasa el cuarto estado (case 3) que espera un tiempo de dos segundos para repetir nuevamente el proceso.

El ultimo estado del procedimiento es para la autenticacion de la tarjeta en el bloque 2 con la función MRCAuth(PICC_AUTHENT1A, 2, tagkey, buff), utilizando la llave A establecida por defecto, entonces dependiendo del resultado y el estado del pulsador SW1, se llevaran a cabo las siguientes operaciones: 

Si el pulsador SW1 se encuentra presionado, entonces se realizara la escritura del bloque 2 con la función MRCWrite(2, buff), donde los 16 bytes del bloque estarán codificados en un formato de Valor(ValueBlock) que se lleva a cabo utilizando el procedimiento MRCEncodeValue(5, 2, buff), es valor que se escribe es un numero 5 que representa en nuestro ejemplo la recarga de un valor de crédito a una tarjeta.

Si el pulsado SW1 no esta presionado, entonces se decrementa un uno al valor del bloque 2, con la función MRCUpdateValue(2, PICC_DECREMENT, 1) y luego se realizara la lectura del bloque con MRCRead(2, buff), para luego recuperar el Valor con el procedimiento MRCDecodeValue(buff).

El propósito de este ultimo estado es recargar una tarjeta con crédito y usar la operación para decremento unitario de forma automática cada vez que se realiza la lectura de la tarjeta, entonces una luz verde se activara siempre que la tarjeta tenga crédito y una luz roja cuando ya no cuente con saldo.

Seguidamente se describe el procedimiento de configuracion del PIC y la rutina de interrupción ISR.

void setupMCU(void) //Procedimiento para configurar el PIC
{
    OSCCONbits.IRCF = 0b111;
//Oscilador Interno 8MHz
    while(OSCCONbits.HTS == 0);
    ANSEL = 0;
//Desactiva pines ADC AN0 al AN7
    ANSELH = 0;
//Desactiva pines ADC AN8 al AN13
    TRISEbits.TRISE2 = 0;
//Salida Pin LED
    PORTEbits.RE2 = 0;
//Apaga el LED
    TRISDbits.TRISD0 = 0;
//Salida DS2 Verde
    TRISDbits.TRISD1 = 0;
//Sal;da DS1 Rojo
    PORTD = 0;
//Salidas en nivel bajo
    OPTION_REGbits.nRBPU = 0;
//Activa las pull-ups PORTB
  
  /* CONFIGURACION TIMER0 1MS a Fosc=8MHz*/
    OPTION_REGbits.T0CS = 0;
//Modo Termporizador
    OPTION_REGbits.PSA = 0;
//Con prescala
    OPTION_REGbits.PS = 0b011;
//Prescala 1:16
    TMR0 = 131;
//256-(time/((pre)*(4/Fosc))) time=0.001 seg
    INTCONbits.T0IF = 0;
//Limpia bandera
    INTCONbits.T0IE = 1;
//Activa interrupción del TMR0
   
/* CONFIGURACION UART 9600 BPS*/
    BAUDCTLbits.BRG16 = 0;
//8-bit BaudGen
    TXSTAbits.BRGH = 1;
//Modo High Speed
    TXSTAbits.TXEN = 1;
//Habilita el transmisor UART
    //RCSTAbits.CREN = 1;
//Habilita el receptor UART
    RCSTAbits.SPEN = 1;
//Activa el modulo UART
    SPBRG = 51;
//Formula [8M/(16 * 9600)] - 1
   
/* CONFIGURACION MSSP MODO SPI 500KHz 8MHz*/
    TRISCbits.TRISC5 = 0;
//SDO Salida en modo master
    TRISCbits.TRISC3 = 0;
//SCK Salida en modo master
    SSPCONbits.SSPM = 0b0001;
//Master SPI(Fosc/16)=500KHz
    SSPSTATbits.SMP = 1;
//Data sample at end SMP = 1    
    SSPCONbits.CKP = 0;
//Clock Idle low level SCK=0
    SSPSTATbits.CKE = 1;
//Positive edge clock enable CKE = 1;
    SSPCONbits.SSPEN = 1;
//Enable SSP Module
    INTCONbits.GIE = 1;
//Habilitador global ISR
}

void __interrupt() isr(void)
{
    uint8_t res;
    if(INTCONbits.T0IF)
    {
        INTCONbits.T0IF = 0;
        TMR0 += 131;
        tickms = 1;
    }
}

Pruebas de funcionamiento
Antes de abrir el proyecto en MPLABX, asegúrate de tener instalado la versión del compilador XC8, una vez confirmado procedemos a abrir el proyecto, y luego de llevar a cabo la exploración de los archivos, procedemos a compilar el programa, si no hay errores procedemos a cargar el código al microcontrolador y llevar a cabo las pruebas de funcionamiento. 

En primer lugar debe notar que el led de indicación destella una vez por segundo, esto nos indica la correcta ejecución del programa, restando únicamente acercar una tarjeta RFID para que se lleve a cabo la identificación y se muestre un mensaje a través del puerto serie. Para poder visualizar este mensaje utilizaremos un complemento disponible para MPLABX, accediendo a menu->tools->plugins, en esta ventana nos aseguramos de activar la instalación de Simple Serial Port Terminal

Fig8. Instalación de Simple Serial Port Terminal

Una vez instalado Simple Serial Port Terminal se debe configurar el puerto COM asignado al convertidor UART-USB, en windows la asignación tiene nombre COMxx, mientras que en linux es un acceso a ruta /dev/ttyUSBx.

Finalizada la configuracion del terminal, cada vez que se aproxime una tarjeta MiFARE, veremos un mensaje con el numero serial de la tarjeta y la cantidad de crédito que dispone como se observa en la Figura 9. Recuerde que para hacer una recarga es necesario aproximar la tarjeta manteniendo el pulsador SW1 presionado. 

Fig9. Mensajes recibidos en el Puerto Serie
 La figura 10, muestra el circuito utilizado para el proyecto, donde se puede observar una placa de pruebas PIC16F, circuito de conversion de nivel, modulo lector RC522 y llavero con chip MiFARE Classic.

Fig10. Circuito PIC utilizado para el programa

Conclusiones y Recomendaciones.
Verificado el funcionamiento adecuado de la comunicación entre el PIC16F y el modulo RC522 como parte del objetivo de esta publicación, si bien las características de las tarjetas MiFARE posibilitan mayores prestaciones de seguridad, tales como la Autenticación por bloque, y el almacenamiento de variables en memoria con operaciones de auto incremento o decremento. En muchas situaciones solo basta con llevar a cabo la lectura del numero serial, puesto que la identificación de la tarjeta posibilita asociarlo con un elemento u objeto sujeto al control, por ejemplo se puede consultar un base de datos del personal autorizado en base al numero de serie en su tarjeta de control.

Aquí dejo los enlaces para que puedas descargar el proyecto, se encuentra en formato gzip, debes descomprimir y abrir con MPLABX  
Si quieres ver como compilar e implementar los proyectos de este blog, elaborados con MPLABX mira este vídeo.<Compilando proyectos MPLABX>
 
Sin mas que mencionar agradezco tu visita al blog y espero que el ejemplo visto pueda ser útil en tu formación y el proyecto que desarrollas.

Atentamente, Pablo Zárate Arancibia  email: pablinza@me.com / pablinzte@gmail.com, @pablinzar

Santa Cruz de la Sierra - Bolivia

viernes, 19 de enero de 2024

ADC Lectura de corriente AC con ACS712

 Medir consumo de corriente AC220V

Fig1. Modulo ACS712



Este sitio fue creado para compartir el mutuo interés en la electrónica y en especial la programación de microcontroladores PIC. Descrita la introducción te agradezco por visitar mi blog recordando que estoy atento a cualquier consulta o critica constructiva relacionada con esta publicación.

En esta ocasión veremos como medir el consumo de corriente tipo alterna haciendo uso de un modulo muy accesible por su disponibilidad y precio, este modulo se basa en un circuito integrado ACS712.
El propósito que se desea lograr en esta oportunidad es medir con un microcontrolador PIC16F887, la corriente de consumo que tiene una carga conectada al suministro eléctrico domiciliario 220V/50Hz, y mostrar el valor en amperios (A) mediante mensajes de texto enviados por puerto serie UART a una terminal PC. Para llevar a cabo las pruebas se recomienda tomar las debidas precauciones de seguridad sobre todo en la interconexión del modulo AC712 con la carga.

La programación se realizara utilizando MPLABX y el compilador XC8 ambos disponibles en la pagina de microchip. Aquí dejo los enlaces de las versiones utilizadas para nuestro ejemplo:

 <<MPLABX v6.15>>   <<XC8 v2.45>>

La configuración del entorno se utiliza el pack PIC16Fxxx_DFP(1.5.151)
Mencionar también que es necesario contar con conocimientos mínimos sobre programación en lenguaje C y el uso de microcontroladores PIC16.

Acerca del efecto HALL 

Se conoce como efecto Hall a la aparición de un campo eléctrico por separación de cargas en el interior de un conductor por el que circula una corriente en presencia de un campo magnético con componente perpendicular al movimiento de las cargas(Wikipedia).

Haciendo referencia a la nota de aplicación del fabricante de sensores Honeywell (Hall Effect Sensing and Application). ilustraremos con mayor claridad este efecto en la tecnología de medición.

Imaginemos una pequeña lamina semiconductora(elemento Hall interno de un sensor) por la que atraviesa una corriente eléctrica; si medimos el voltaje eléctrico en los extremos perpendiculares al flujo de corriente notaremos que ante la ausencia de un campo magnético este voltaje es 0 debido a que la distribución de corriente es uniforme en toda superficie de la lamina.

Fig2. Efecto Hall en ausencia de un campo magnético 

Ahora con la presencia de un campo magnético se produce una fuerza conocida como fuerza de Lorentz que perturba el flujo de corriente ocasionando un diferencia de potencial eléctrico en los extremos, esta diferencia es el voltaje Hall.
 
Fig3. Efecto Hall en presencia de un campo magnético


Entonces podemos deducir que el voltaje Hall es proporcional al producto de la corriente que circula por el elemento y el campo magnético que lo atraviesa, siendo necesario amplificar este valor para que pueda ser capturado por el microcontrolador.


Modulo sensor ACS712

En el sensor de corriente ACS712, se incorpora internamente un camino o pista de cobre superficial por donde circula la corriente de carga, esta corriente de paso genera un campo magnético que a la vez deriva en una diferencia de potencial en los extremos de la sección de pista, esta diferencia es estabilizada y optimizada internamente para conseguir una salida con voltaje proporcional a la corriente. Este sensor posee poca perdida debido a que la resistencia interna de la pista de cobre es muy baja. Algo muy importante de mencionar que el circuito integrado ACS712 a fecha esta descontinuado y por lo tanto no esta recomendado para nuevos diseños, pero el fabricante dispone de nuevos modelo que ofrecen mejores prestaciones.
Como mencione previamente la razón de utilizar este sensor pese a estar descontinuo, es la disponibilidad que hay a un bajo costo económico, en cualquier caso tanto el hardware y software elaborado en este ejemplo adaptable a los modelos actuales del sensor.
Seguidamente listo alguna de las características mas relevantes del sensor ACS712 extraídos de la hoja de datos:
  • Resistencia interna de 1.2 milésimas de Ohm;
  • Error total en salida del 1.5% a 25°C;
  • Aislamiento mínima de 2.1kV RMS;
  • Voltaje de salida proporcional para AC y DC;
  • Voltaje de operación a 5V;
  • Sensibilidad en salida de 66 a 185mV/A.
Las variantes con respecto al sensor ACS712 se listan a continuación:
  • ACS712ELCTR-05B-T ±5A 185mV/A (Hasta 5A);
  • ACS712ELCTR-20A-T ±20A 100mV/A (Hasta 20A);
  • ACS712ELCTR-30A-T ±30A 66mV/A (Hasta 30A).
Fig4. Variantes del modulo ACS
La siguiente gráfica nos ilustra el comportamiento proporcional que tiene el voltaje de salida con respecto a la corriente que se mide con la variante 05B, las gráficas correspondientes a los demás modelos se encuentran en la hoja de datos del fabricante.

Fig5. Voltaje de salida / corriente medida ACS712-05B
Como detalle adicional en referencia a la fig5. notara que la salida del sensor sera de 2.5V sin consumo, por lo tanto el rango de salida considerando la relación de 185mV por amperio, sera de 1.57V — 3.42V. Esto se deduce considerando que el valor máximo de 5 A representa 0.925V (0.185 * 5), siendo el rango 2.5 ± 0.925V.

La siguiente figura muestra el esquema de circuito para el modulo de pruebas ACS-712, el cual posee los elementos esenciales para la operación y conexión al microcontrolador.

Fig6. Esquema de circuito del modulo sensor ACS712
 
Como ya vimos, la salida OUT, proporciona una señal de voltaje en el rango 2.5 ± 0.925V. según la corriente que circula por la pista IN+/ IN-, esta dependencia se visualiza en la figura 5. 
Como el voltaje aplicado a la carga es una onda sinusoidal alterna 220V con frecuencia de 50Hz en el caso de mi país, la salida del sensor también oscilara, manteniendo el periodo de 20ms. (t=1/f).
La medición que se realizara utilizando el modulo ADC del PIC16F dentro de un periodo de tiempo posibilitara calcular la corriente de consumo, aplicando uno de los siguientes métodos:
 
Método 1) Determinar los valores pico VPK de la señal alterna en un periodo de tiempo, y calcular el valor RMS(Root Mean Square), con el producto VRMS = VPK * 0.707 tal como se se muestra en la figura 7, este calculo es valido únicamente con señales sinusoidales.

Fig7. Calculo de Valor RMS

Método 2) Esta técnica es aplicable a cualquier tipo de señal y consiste en tomar una muestra de los valores absolutos en cada semi-ciclo para determinar un promedio,. Entonces el valor RMS se obtiene aplicando la formula que se muestra en la figura 8.
 
Fig8. Calculo de valor RMS
Si se integra la función seno para un semi-ciclo, se encuentra que el voltaje promedio VPM = VPK * (2/π ).

Una vez calculado el valor RMS(Root Mean Square) la corriente podrá determinarse por la relación de salida Voltaje / Corriente del sensor. En nuestro caso utilizaremos el modulo ACS-712-05B el cual según la hoja de datos posee una sensibilidad de 185mV/A. 
 
Esquema de conexión PIC16F y ACS712
La figura 9 muestra el esquema de conexión del microcontrolador PIC16F al modulo ACS712. El circuito se alimenta con +5V y la salida OUT del modulo ACS712 se conecta de forma directa al canal AN0 del PIC16F.
Fig9. Diagrama de conexión del circuito
El conversor ADC del PIC16F posee una resolución de 10-bits, y el rango de voltaje para la conversion sera de 2.5 ± 0.925V(ACS712-05), con el fin de mejorar la sensibilidad de cambio, se utilizara como voltaje de referencia positivo el pin AN3/Vref+, mismo que se conectara al divisor de tensión formado por las resistencias. El voltaje del divisor sera 3.75V (+5 * 10k/(10k+3.3k). 
Con esta configuracion podemos determinar que la sensibilidad en mV por cada bit sera:

(Vref+ - Vref-) / 2^10-bits = (3.75V - 0V) / 1024 = 3.66 mV.

Conociendo este resultado, la relación de cambio en bits por cada amperio sera 185mV/3.66mV = 50.5 bits. (ACS712-05)
 
Por otro lado la comunicación serial con la PC, utiliza un convertidor USB a UART, en nuestro caso es un CP-2102, pero puede ser cualquier otro conversor, porque solo se requiere un par de conexiones a los pines TXD y RXD del PIC16F, finalmente existe un diodo LED conectado al pin RE2 que destellara para indicar la actividad del programa.
 
Programa del Microcontrolador PIC
El objetivo de este programa es medir la corriente de consumo para una carga alterna de 100W utilizando el modulo sensor ACS712, el valor determinado por el PIC16F, se enviara cada segundo por el puerto serie como un mensaje de texto a 9600bps. El método aplicado para el calculo de la corriente es la medición del valor pico Ipk y división por raíz cuadrada como se observa en la figura 7.
El PIC16F opera con un cristal de 20MHz, siendo esta la base de calculo para la configuracion del tiempo de adquisición del convertidor ADC, modulo USART y el temporizador TMR0. Para mayores referencias sobre la operación del convertidor ADC del PIC16F puedes ir al siguiente enlace de una publicación previa de este blog:

En cuanto a los procedimiento y funciones utilizadas en el programa, todo se resume en el código principal main.c con sus respectivos comentarios. En la parte final dejo el enlace para descarga del proyecto MPLABX que contiene todos lo archivos utilizados.
 
void main(void)
{
    setup();
//Configuración de puertos y periféricos
    while(1)
    {
        if(tick1ms)
//Bandera activa cada 1ms
        {
            tick1ms = 0;
//Limpia bandera
          
  taskAPP(); //Ejecuta cada 1ms
        }
        taskADC();
//Ejecuta la tarea continuamente
    }

void setup(void)
{
   
//Oscilador Externo HS=20MHz Tcy = 0.2us
    ANSEL = 0;     
//Pines AN0-AN7 en modo digital
    ANSELH = 0;    
//Pines AN8-AN13 en modo digital
    TRISA = 0xFF;
    ANSELbits.ANS0 = 1;
//Habilita el canal AN0
    ANSELbits.ANS3 = 1;
//Habilita Vref+ AN3
    TRISEbits.TRISE2 = 0;
//Pin de salida LED
   
/* CONFIGURACION UART 9600 BPS*/
    BAUDCTLbits.BRG16 = 0;
//8-bit BaudGen
    TXSTAbits.BRGH = 1;
    TXSTAbits.TXEN = 1;
    RCSTAbits.SPEN = 1;
    SPBRG = 129;
//Formula [20M/(16 * 9600)] - 1
   
/* CONFIGURACION ADC VRAF+*/
    ADCON0bits.ADCS = 0b10; //TAD Fosc/32 = 1.6uS a 20MHz
    ADCON0bits.CHS = 0b0000; //Canal AN0
    ADCON1bits.VCFG0 = 1; //Activa Vref+ = pin AN3/RA3
    ADCON0bits.ADON = 1; //Activa modulo ADC.
   
/* CONFIGURACION TIMER0 1MS*/
    OPTION_REGbits.T0CS = 0;
//Modo temporizador
    OPTION_REGbits.PSA = 0;
//Con prescala
    OPTION_REGbits.PS = 0b100;
//Prescala 1:32
    TMR0 = 100;
//256-(time/[(pre)*(4/Fosc)]) time=0.001 seg
    INTCONbits.T0IF = 0;
//Limpia bandera
    INTCONbits.T0IE = 1;
//Activa interrupción del TMR0
    INTCONbits.GIE = 1;
//Habilita las interrupciones
}

void __interrupt() isr()
{
    if(INTCONbits.T0IF)
//Activa cada 1ms
     {
        INTCONbits.T0IF = 0;
//Limpia bandera
        TMR0 += 100;
//Reinicia contador
        tick1ms = 1;
//Activa bandera 1ms
        if(tickcnt++ > 999)
//Control 0-999 ms
            tickcnt = 0;
//Reinicia contador 1s
    }
}

void taskADC(void) //Procedimiento para lectura ADC
{
    static uint8_t cnt = 0;
    static uint16_t valmax, valmin;
    uint16_t val;
    switch(adst)
    {
        case ADSTART:
//Activa ADC, inicia variables
            ADCON0bits.ADON = 1;
            valmax = 0x0000;
            valmin = 0xFFFF;
            adst = ADREAD;
            break;
        case ADREAD:
//Inicia la lectura
            ADCON0bits.GO = 1;
            adst = ADWAIT;
            break;
        case ADWAIT:
//Espera conversion ADC
            if(ADCON0bits.GO == 0)
            {
                val = ADRESH;
                val = val << 8;
                val = val | ADRESL;
                val = val >> 6;
                if(val > valmax) valmax = val;
                if(val < valmin) valmin = val;
                if(adst == ADWAIT) adst = ADREAD;
            }
            break;
        case ADSTOP:
//Desactiva el ADC
            ADCON0bits.ADON = 0;
            if(valmax > valmin) adraw = valmax - valmin;
            else adraw = 0;
            adst = ADIDLE;
        break;
        case ADIDLE:
//Estado de reposo
            _nop();
    }
}

Luego de llevar a cabo la configuración de los pines y periféricos con el procedimiento setup(), el programa principal debe llevar a cabo las siguientes tareas por cada segundo transcurrido: 
  • Muestreo de señal, por 50m;
  • Enviar mensaje con valor de corriente;
  • Destello de LED de actividad.
Estas tres tareas se llevan cabo con el procedimiento taskAPP() en intervalos de 1ms. mismos que se controlar por la bandera de interrupción del TMR0.

void taskAPP(void)
{
    if(tickcnt == 0)
//Inicia captura ADC en 0ms
        adst = ADSTART;
    if(tickcnt == 50)
        adst = ADSTOP;
//Fin de captura ADC en 50ms
    if(tickcnt == 600) 
//Procesa y muestra datos
    {
        current = (1000UL * adraw) / 50;
//valor en ma
        current = (50UL * current) / 142;
//[100*(current/2)]/142
        printf("AMP=%lu\r\n", current);
    }
    if(tickcnt == 700) LEDpin = 1;
//Activa led en 700ms
    if(tickcnt == 900) LEDpin = 0;
//Desactiva led en 900ms
}


Pruebas de funcionamiento
Antes de abrir el proyecto en MPLABX, asegúrate de tener instalado la ultima versión del compilador XC8, una vez abierto el proyecto, en la ventana del explorador veremos los archivos del programa. Luego de revisar el codigo procedemos a compilar, y si no hay errores todo estara lista para cargar el código al microcontrolador utilizando un programador de PIC. En este punto para llevar a cabo las pruebas de funcionamiento deberás contar con un circuito montado, en mi caso utilice el circuito que se observa en la siguiente imagen.


Fig10. Circuito de pruebas PIC16F
Ya con el programa cargado en memoria del PIC16F y con el suminitro conectado, notara que el led destella una vez por segundo, indicando la correcta ejecución del programa.
Luego debemos conectar una carga a las terminales INA/INB del modulo ADC712, el valor de corriente se mostrara en el ordenador utilizando una terminal serial asociado a un puerto COM del ordenador, yo utilice en este caso HTerm, un programa gratuito y multi-plataforma que puedes descargar con el siguiente enlace: <<HTERM>>.

Para comprender mejor los valores calculados en el microcontrolador, he realizado varias capturas en cada etapa del medición dentro del programa. estos se muestran a continuación.

Fig11. Referencia AN0 con GND/VCC (valmax-valmin)
Considerar que la captura que se muestra en la figura 11, solo es referencial para comprobar el procedimiento de muestreo, dado que en ambas situaciones el voltaje de entrada es constante GND=0V y VCC=5V, la deferencia de los valores picos muestreados deberia ser idealmente 0V, aquí se puede notar que cuando AN0 va conectado directamente a GND, muestra una diferencia de 3 a 6 puntos, que asumo su origen a la improvisación de las conexiones en el protoboard y el ruido propio del sensor
que según la hoja de datos es de ±20mV. A posterior con unas pruebas adicionales sobre el circuito, veré detallar mas esta diferentes que representa un error para la medición.

Fig12. AN0 Conectado al ACS712 (valmax-valmin)

Ya con la entrada AN0 conectado al sensor ACS712, cuando no hay consumo(sin carga), el resultado ya nos muestra un valor debido al error descrito previamente, y con el consumo de 100W (con carga), el resultado aproximado es 62 bits, este valor es pico a pico, es decir la diferencia entre el valor máximo y mínimo registrado, por lo tanto si consideramos solo un semi-ciclo, representaría a la mitad de valor mostrado, esto es Vpk≈31 bits. Para obtener el valor eficaz de estos bits multiplicamos 31 * 0.701 ≈ 22 bits.  
 
Recordemos que la relación de cambio es igual a 50 bits/A, y para una carga de 100W, la corriente eficaz calculara sera 0.45A (100W/220V), entonces el valor en bits considerando la relación de cambio seria 50 * 0.45A ≈ 22 bits. 
 
La captura que se observa en la figura 13, muestra el valor de corriente pico a pico (Ipp) calculado en miliamperios, este calculo se aplico utilizando la regla de tres simple a la diferencia (valmax-valmin) y la relación de cambio de 50bits/A.

Fig13. Valor pico a pico (Ipp) en mA

Como resultado final de la medición, la captura en la figura 14, muestra el calculo del valor eficaz para el valor pico a pico de corriente, lo cual nos arroja un promedio de Irms=420mA, considerando las siete lecturas observadas.

Fig14. Valor eficaz Irms en mA
 
Para contrastar este resultado teórico con la carga de 100W, se conecto un amperímetro en serie con la carga y se procedió a medir la corriente de consumo, misma que se muestra en la figura 15.
Fig15. Valores registrados con Amperímetro
El valor promedio registrado con el instrumento fue de 0.363A es decir 363mA, que representa un valor pico de 570mA (Ipk = Ipm / (2/π )), siendo su valor eficaz  Irms ≈ 403 mA.

Recomendación y Conclusión
Si bien se ha completado la meta de medir la corriente de consumo en alterna para una carga de 100W, el ruido que se presenta en las lecturas incluso si no hay consumo, es un punto a considerar en la aplicación final, recordar este sensor ya fue descontinuado por el fabricante, recomendándose usar el ACS723.
La técnica empleada para medir la corriente eficaz consistió en medir los valores picos de la señal y calcular su valor eficaz, si bien es una manera simple para implementar, es también la mas susceptible al ruido y cambios en la forma sinusoidal de la señal alterna, por eso como una alternativa seria llevar a cabo los calculo basado en el segundo método, lo que requiere a su vez añadir al circuito un rectificador. 
Recomendar nuevamente que la conexión de carga 220VAC a los pines INA / INB del modulo ACS712 debe efectuarse con mucha precaución, considerando todas la medidas de seguridad posible, una mala conexión puede provocar severos daños personales y materiales.

Aquí dejo los enlaces para que puedas descargar el proyecto MPLABX, se encuentra en formato gzip recordando que soy usuario de linux y es probable que necesites modificar algunas referencias para compilar con windows.


Proyecto <<MPLABX ac712p16f>>

Sin mas que mencionar agradezco tu visita al blog y espero que el ejemplo visto pueda ser útil en tu formación y el proyecto que desarrollas.
Atte. Pablo Zárate Arancibia
email: pablinza@me.com / pablinzte@gmail.com
@pablinzar
Santa Cruz de la Sierra - Bolivia