viernes, 16 de febrero de 2024

TMR0 Configuración y usos

 Contador y Temporizador con PIC16F


Este sitio fue creado para compartir el mutuo interés en la electrónica y en especial la programación de microcontroladores PIC. Agradecido por visitar mi blog te quiero recordar que estoy atento a critica constructiva relacionada con esta publicación. 

En esta ocasión veremos como hacer uso del modulo TMR0 del PIC16F en aplicaciones que requieran un contador de eventos, y también un temporizador para la gestión de tareas en el programa. 

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 v4.01>>   <<XC8 v1.45>>

Mencionar también que es necesario contar con conocimientos mínimos sobre programación en lenguaje C y el uso de microcontroladores PIC16.


Introducción al Tema
Los contadores y temporizadores son recursos de hardware que están presentes en la mayoría de los microcontroladores. Con este elemento es posible contar pulsos de origen interno o externo con la mínima intervención del programa, con la configuración de dos modos:
  • Temporizador: opera como contador de pulsos internos del oscilador principal
  • Contador: opera como contador pulsos que provienen desde una entrada externa.

Fig1. Contador / Temporizador

El registro contador se incrementa con cada pulso hasta su desbordamiento, o en algunos llega a un valor predefinido, esta condición se notifica con una bandera de interrupción para que el programa lleve gestione la actividad.  

Gracias a un temporizador el desarrollador puede programar la ejecución de tareas controlando el tiempo de forma precisa.
Los contadores facilitan la creación de rutinas para medir el ancho o cantidad de pulsos externos que transcurren de forma periódica o no periódica.

Los microcontroladores PIC16F de gama media, disponen de al menos tres módulos de conteo y están designados como:

  • TMR0: Temporizador y/o Contador de 8-bit
  • TMR1: Temporizador y/o Contador de 16-bit
  • TMR2: Temporizador de 8-bit

Descripción del TMR0 

La figura 2 corresponde al diagrama de bloques del módulo TMR0, toda la informacion descrita en esta sección proviene de la hora de datos correspondiente al PIC16F887. 

Fig2. Modulo TMR0 del PIC16F

Como ya vimos este modulo es un Temporizador y/o Contador de 8-bit debido al ancho que tiene el registro de conteo TMR0, el esquema identifica las diferentes partes con el siguiente detalle: 

  1. Esta entrada se utiliza cuando el modulo opera en modo temporizador (T0CS= 0), donde la frecuencia de trabajo genera un tren de impulsos con periodo igual al ciclo de instrucción.
  2. Es la entrada asociada al pin T0CKI, por donde ingresan los pulsos cuando el modulo opera como contador (T0CS=1), como estos pulsos no siempre son periódicos, la frecuencia de trabajo no es un factor que influya en la secuencia del contador, pero si es posible determinar el flanco de validación de cada impulso a través del bit T0SE, por defecto esta configurado como flanco descendente (T0SE=1), algo a tomar en cuenta es que el pin debe configurarse como una entrada digital, y deben desactivarse cualquier funcionalidad asociada a un canal o comparador analógico,
  3. La sección corresponde al bloque de pre-escala programable, se trata de un divisor de frecuencia con ocho escalas seleccionables a través de los bits PS2, PS1 y PS0, las escalas permitidas se muestran en la figura 3, registro. El uso de esta etapa es opcional, siendo necesaria su activación con el bit PSA=0.
  4. El punto corresponde al registro contador que incrementa su valor con cada pulso que proviene directamente de la entrada Fosc/4 / T0CKI o el bloque de pre-escala, en cualquier modo operativo este registro se autoincremento desde un valor 0 hasta el 255, para luego reiniciar
  5. Finalmente cada vez que el registro contador llega a su valor limite de 255, con el siguiente pulso de entrada se reinicia a 000, este hecho se conoce como desbordamiento, y ante su ocurrencia la bandera T0IF se activa.  La bandera deberá limpiarse una vez atendido el evento. 

Fig3. Registros SFR del modulo TMR0

Debe tomar en cuenta que los registros SFR que se muestran en la figura 3 tiene valores por defecto, en muchos casos podría no ser necesario limpiar los bits.

Esquema del circuito

De aquí en vamos revisaremos algunos ejemplos de programación utilizando el modulo TMR0, para lo cual en esta ocasión utilice el circuito que se muestra en la figura 4. Este circuito servirá para ensayar el código que trabajaremos en las siguientes secciones,  tome como referencia el microcontrolador PIC16F687 utilizando el software de simulación Proteus versión 8.

Fig4. Esquema del circuito PIC16F687

Configuración de un Contador

Para configurar el modulo como un contador de pulsos, debe llevarse a cabo la siguiente configuracion considerando el circuito de la figura 4.

  • Como la entrada T0CKI esta asociado al pin RA2, este debe configurarse como una entrada digital utilizando a través del registro TRISA.
  • El modo contador controlado por el bit T0CS=1, por defecto ya esta activo, por lo que no necesita modificar el bit.
  • Si va utilizar la etapa de pre-escala, entonces debe establecer el bit PSA=0, caso contrario aplicara el valor por defecto.
  • Deberá seleccionar una escala de división con los bits PS2:0 si hace uso de la etapa de pre-escala, por defecto la selección es 256:1.
  • Asignar el valor requerido para el registro TMR0, utilizando la ecuación que se muestra en la figura 5.
  • Limpiar la bandera T0IF, y esperar la ocurrencia del evento, verificando si la bandera se activa en un futuro. 

Fig5. Cálculos del Contador

Veamos un ejemplo practico para el contador. Considerando que el PIC16F628 trabaja con su oscilador interno de 4MHz, configurar el modulo TMR0 para indicar la llegada de 15 pulsos no periódicos en el pin RA4, e indicar el evento activando un LED conectado al pin RC0.

#pragma config FOSC = INTRCIO, WDTE = OFF
#include <xc.h>
#include <stdio.h>
void setup()
//Procedimiento de configuracion
{
  OSCCONbits.IRCF = 0b110;
//Selecciona 4MHz por Defecto
  ANSEL = 0x00;
//Desactiva los canales AN0-AN7
  TRISAbits.TRISA2 = 1;
//Pin RA2/T0CKI como entrada
  TRISCbits.TRISC0 = 0;
//Pin RC0 como salida
  OPTION_REGbits.T0CS = 1;
//Modo Contador
  OPTION_REGbits.PSA = 1;
//Sin prescala, 1:1
  TMR0 = 241;
//(256-pulsos/pre) = 256 - 15/1
  INTCONbits.T0IF = 0;
//Limpia bandera
}
void main()
{
  setup();
//Procedimiento de configuracion
  PORTCbits.RC0 = 0;
//Apaga el LED
  while(1)
  {
    if(INTCONbits.T0IF == 1)
//Verifica bandera
    {
       PORTCbits.RC0 = 1;
//Activa el LED
       INTCONbits.T0IF = 0;
//Limpia bandera
    }
  } 
}

Cambiando un poco las cosas, modificaremos el programa para contar la llegada de 1724 pulsos (pulsos de salida por cada litro que emite un flujo metro FS-3400),  e indicar el evento (1 litro) activando el LED conectado al pin RC0.

Para este requerimiento el único cambio necesario sera en el procedimiento de configuracion setup,  con las siguientes consideraciones:

Debido a que la cantidad de pulsos superan el valor del registro contador TMR0, el cual puede contar hasta 256, sera necesario utilizar la etapa de pre-escala, pero esta etapa trabaja con escalas ya definidas por lo que no conseguiremos un numero exacto con ninguna de ellas, salvo la 2:1 o 4:1 pero estos el resultado superaría la capacidad del contador TMR0. Ahora si utilizamos 8:1, tendríamos 1724/8=215.5 y si fuera 64:1, seria 1724/64=26.93, entonces con cualquiera de estas relaciones habrá un error debido a que el registro contador se carga solo con la parte entera. 

Tomemos el primer caso para nuestro analisis,  si utilizamos 8:1(1724/8=215.5), el registro contador redondeado podrá ser 215 o 216, si fuera 215, la ocurrencia seria 215*8 = 1720, cuatro pulsos menos de lo esperado; Y si el contador se ajusta con 216, la ocurrencia nos da 1728, cuatro pulsos mas de los esperado. En resumen con cualquiera de los valores el error provocado seria un 0.23%, si el error es aceptable el procedimiento de configuracion seria el siguiente:

void setup() //Procedimiento de configuracion
{
  OSCCONbits.IRCF = 0b110;
//Selecciona 4MHz por Defecto
  ANSEL = 0x00;
//Desactiva los canales AN0-AN7
  TRISAbits.TRISA2 = 1;
//Pin RA2/T0CKI como entrada
  TRISCbits.TRISC0 = 0;
//Pin RC0 como salida
  OPTION_REGbits.T0CS = 1;
//Modo Contador
  OPTION_REGbits.PSA = 0; //con pre-escala
  OPTION_REGbits.PS = 0b010;
//Escala 8:1
  TMR0 = 41;
//256-(1724/8) = 256 - 215 = 41
  INTCONbits.T0IF = 0;
//Limpia bandera
}

En caso de no ser aceptable el error, se tendría que pensar en llevar el conteo de pulsos individuales o en todo caso ajustar la configuracion del registro contador durante la ultima actualización del evento. No se abordara este punto.

Configuración del Temporizador

Para configurar el modulo como temporizador, debemos llevar a cabo la siguiente configuracion:

  • Seleccionar el modo temporizador estableciendo el bit T0CS=0
  • Si va utilizar la etapa de pre-escala, entonces debe establecer el bit PSA=0
  • Deberá seleccionar una escala de división con los bits PS2:0 si hace uso de la etapa de pre-escala.
  • Asignar el valor requerido para el registro TMR0, utilizando la ecuación que se muestra en la figura 7.
  • Limpiar la bandera T0IF, es la ocurrencia del evento, verificando si la bandera se activo.
  • Después de cada evento, la bandera debe limpiarse y el valor del registro TMR0 debe ser nuevamente asignado para un siguiente ciclo.

Fig7. Calculo temporizador

Veamos un ejemplo practico para el uso del un temporizador considerando que el PIC16F trabaja a una frecuencia de 4MHz, ver figura 4. Configurar el modulo TMR0 para un tiempo de 1ms y reflejar con este tiempo el cambio de nivel en el pin RC0.

Para este caso seleccionamos un valor de pre-escala, en este caso 8:1 debido a que sin pre-escala lo máximo para ajustar seria (4/Fosc)* (256-0) = 0.000256 o 256us, y el requerimiento es 0.001 o 1ms. El programa quedaría así:

#pragma config FOSC = INTRCIO, WDTE = OFF
#include <xc.h>
#include <stdio.h>
char ledst;
//variable que mantiene estado del led
void setup()
{
  OSCCONbits.IRCF = 0b110;
//Ajusta INTOSC=4MHz
  TRISCbits.TRISC0 = 0;
//Pin RC0 como salida
  OPTION_REGbits.T0CS = 0;
//Modo termporizador
  OPTION_REGbits.PSA = 0;
//Con pre-escala
  OPTION_REGbits.PS = 0b010;
//Pre-escala 8:1
  TMR0 = 131;
//256-(time/(pre*(4/Fosc))) time=0.001s
  INTCONbits.T0IF = 0;
//Limpia bandera
}
void main()
{
  setup();
  while(1)
  {
    if(INTCONbits.T0IF == 1)
//Verifica bandera de 1ms
    {
        TMR0 = 131;
//Ajusta el registro
        PORTCbits.RC0 = ledst;
//Pin se carga con el estado
        ledst = !ledst;
//Invierte el valor logico
        INTCONbits.T0IF = 0;
//Limpia bandera de 1ms
    }
  }
}

Realizada la simulación en Proteus, la figura 8 muestra una captura del osciloscopio conectado al pin RC0, donde se observa la señal con los tiempos calculados, cabe mencionar que el periodo total es 2ms, con una frecuencia de 500 Hz.

Fig8. Captura del pin RC0, escala 1ms
 

Modificaremos el programa para que la señal a través de pin RC0, tenga un periodo de 1 segundo, es decir 1Hz de frecuencia.

Vamos a analisis el nuevo requerimiento de tiempo para 1 segundo. si consideramos la maxima relación 256:1, aplicando la ecuación de figura 7 el tiempo máximo posible, seria 0.065536 segundos, este valor esta lejos de lo requerido por lo tanto sera necesario hacer uso de una variable contador dentro del programa, manteniendo la configuracion del temporizador para 1ms. 

La variable deberá contar la cantidad de 1ms necesarias para general una señal con frecuencia de 1Hz, este valor seria 500, que corresponde la mitad del periodo total, recuerde que la primera mitad de ciclo la luz esta apagad y le otra mitad estará encendida, consiguiendo un destello cada segundo. 

La al código anterior sera únicamente en el programa principal, quedando de la siguiente manera:

void main()
{
  unsigned int cnt = 0;
//Contador de 1ms
  setup();
  while(1)
  {
    if(INTCONbits.T0IF == 1)
//Verifica bandera de 1ms
    {
      TMR0 = 131;
      cnt ++;
      if(cnt > 499)
//hasta llegar a 500 x 1ms
      {

        cnt = 0;
//reinicia la variable contador
        PORTCbits.RC0 = ledst;
        ledst = !ledst;
//Invierte el calor logico
      }
      INTCONbits.T0IF = 0;
//Limpia bandera de 1ms
    }
  }
}

TMR0 con interrupciones

Sin duda que unos de los recursos mas valiosos que posee el microcontrolador, son las interrupciones, gracias a ello es posible manejar los eventos asociados el modulo TMR0 con la mínima intervención del programa principal. 

Como ejemplo practico vamos hacer uso del  temporizador utilizando la interrupción, en base al ejemplo anterior que permitía destellar un LED con frecuencia de un segundo. Note que se adicionara la rutina de servicio a la interrupción ISR para atender el evento del temporizador.

#pragma config FOSC = INTRCIO, WDTE = OFF
#include <xc.h>
#include <stdio.h>
char ledst = 0;
//variable que mantiene estado del led
unsigned int cnt = 0;
//variable contador
volatile char tick1ms;
//bandera indicador 1ms
void __interrupt() isr()
//Rutina de interrupción
{
  if(INTCONbits.T0IF)
//Activa cada 1ms
  {
    TMR0 = 131;
//Reinicia contador
    INTCONbits.T0IF = 0; 
//Limpia bandera
    tick1ms = 1;
//Activa bandera 1ms
  }
}
void setup()
{
  OSCCONbits.IRCF = 0b110;
//Ajusta INTOSC=4MHz
  TRISCbits.TRISC0 = 0;
//Pin RC0 como salida
  OPTION_REGbits.T0CS = 0;
//Modo Termporizador
  OPTION_REGbits.PSA = 0;
//Con pre-escala
  OPTION_REGbits.PS = 0b010;
//Pre-escala 8:1
  TMR0 = 131;
//256-(time/(pre*(4/Fosc))) time=0.001 seg
  INTCONbits.T0IF = 0;
//Limpia bandera
  INTCONbits.T0IE = 1;
//Habilita la interrupción del TMR0
  INTCONbits.GIE = 1;
//Habilitador Global ISR
}
void main()
{
    setup();
    while(1)
    {
        if(tick1ms)
//Verifica bandera de 1ms
        {
          tick1ms = 0;
          cnt ++;
//incrementa variable contador
          if(cnt > 499)
//hasta llegar a 500 x 1ms
          {
            cnt = 0;
            PORTCbits.RC0 = ledst;
            ledst = !ledst;
//Invierte el calor logico
          }
        }
    }
}

Como ultimo caso practico modificaremos el programa para el LED se  mantenga activo solo un 20% del periodo, es decir 200ms. Para este caso solo bastara modificar el programa principal y realizar una comparativa del valor en el contador para determinar en que instante activar y apagar el LED.

void main()
{
    setup();
    while(1)
    {
        if(tick1ms)
//Verifica bandera de 1ms
        {
          tick1ms = 0;
          cnt ++;
          if(cnt > 999) cnt = 0;
//hasta 1000 x 1ms
          if(cnt == 200) PORTCbits.RC0 = 1;
//Activa led
          if(cnt == 400) PORTCbits.RC0 = 0;
//Apaga led
        }
    }
}

Conclusiones y recomendaciones

En general hemos visto como configurar el modulo TMR0 ya sea como contador y temporizador, los códigos de ejemplo presentados fueron ensayados en el simulador Proteus, con los resultados esperados.  Si quiere ver como configurar el modulo TMR1 te invito a revisar esta publicación. <<TMR1>>
Como recomendación, solo indicar que en todos los ejemplos no se tomo en cuenta la latencia o tiempo para atender el evento, para aclarar este punto recordemos que el registro TMR0 del temporizador incrementa su valor continuamente, y en el peor de los casos este tiempo sera un ciclo de instrucción(sin pre-escala), entonces si la latencia supera el tiempo necesario para el incremento del contador, este ya no sera 0 al momento de reconfigurar, por lo tanto sera necesario agregar el valor que contiene para ajustar el tiempo del siguiente ciclo, en todo caso podría aplicar la siguiente linea para hacer la corrección.

TMR0 = TMR0 + 131; //Reinicia contador, considerando la cuenta actual
 
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



viernes, 26 de enero de 2024

SPI Identificacion rfID con RC522

Uso del modulo RC522 con PIC

Fig1. Elementos para rfID


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 siempre estamos abiertos a cualquier critica constructiva relacionada con esta publicación.
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 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.

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

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 una cantidad de intentos, pasado la cantidad de intentos el acceso quedara bloqueado de manera irreversible. Este proceso se comentara en una próxima actualización de la presente publicación.
 
A raíz de la amplia aceptación de esta tecnología y el buen éxito de la familia MiFARE Classic, los requisitos de aplicación y las necesidades de seguridad se han incrementado, por lo tanto, ya no se recomienda su uso en aplicaciones de seguridad relevantes, siendo una alternativa la serie MiFARE Plus.
 
 Esquema del circuito PIC

La Fig6. muestra el esquema de conexión del microcontrolador PIC16F al modulo RC522. En este circuito el PIC16F esta alimentado con voltaje de 5V, y se utiliza un regulador MCP1702 para alimentar al modulo RC522 con 3.3V, debido a que las lineas de salida SDO, SCK y SS del PIC16F operan con 5V, se utilizan divisores resistivos para limitar el nivel de voltaje en las entradas del modulo RC522. Por otro lado la comunicación serial con la PC, utiliza un convertidor USB a UART, en nuestro caso es el CP-2102, pero puede ser cualquier otro conversor, porque solo se requiere un par de conexiones TXD y RXD con PIC16F. Finalmente existe un diodo LED conectado al pin RE2 que servirá para indicar la actividad del programa.

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. Pero quedo comprometido a futuro publicar otra entrada explicando con mas detalle todo el proceso y operaciones adicionales que se pueden realizar en la tarjeta.

En cuanto a los procedimiento y funciones utilizadas en el programa, estos se resumen en los archivos de cabecera rc522.h y spi.h, aclarar el código ha sido modificado a partir de fuentes encontradas en la red. 

Ahora exploraremos las secciones que tiene el código principal main.c con una breve explicación de lo que se pretende realizar. En la parte final dejo el enlace para descarga del proyecto MPLABX que contiene todos lo archivos utilizados. 

#pragma config FOSC = INTRC_NOCLKOUT, WDTE = OFF, LVP = OFF
#include <xc.h>
#include <stdint.h>
#include <stdio.h>
#include "spi.h"
#include "rc522.h"
#define LEDpin PORTEbits.RE2
//Pin para indicador led
volatile uint8_t tick1ms;
//Bandera de tiempo para 1ms
volatile uint16_t tickcnt;
//Contador de 1ms, reinicia cada seg.
uint8_t buff[8];    
uint16_t rfid_tagtype;
//Variable para el tag_id
uint32_t rfid_serialnum;
//Variable para el serial number

void main(void) //Código principal
{
  setup();
//Configura los puertos y módulos
  RC522_Init();
//Inicializa el modulo
  while(1)
  {
    if(tick1ms)
//Condición por cada 1ms
    {
      tick1ms = 0;
      taskled();
      if(tickcnt == 100)
//Solo cuando pasen 100ms
      {
        if(RC522_Request(PICC_REQIDL, buff) == MI_OK)
        {
          rfid_tagtype = buff[0];
          rfid_tagtype <<= 8;
          rfid_tagtype |= buff[1];
          if(RC522_ReadCardSerial(buff) == MI_OK)    
          {
            rfid_serialnum = buff[0];
            rfid_serialnum <<= 8;
            rfid_serialnum |= buff[1];
            rfid_serialnum <<= 8;
            rfid_serialnum |= buff[2];
            rfid_serialnum <<= 8;
            rfid_serialnum |= buff[3];
            printf("ID:%Xh N:%lu\r\n", rfid_tagtype, rfid_serialnum);
          }
          RC522_Halt();
        }
      }
    }
  }
}

En las lineas luego de la configuracn e inicialización de los modulo, el programa ingresa en un bucle condicionado a la bandera tick1ms, que se activa cada milisegundo, para este fin se utiliza la interrupción del temporizador TMR0, la rutina de servicio a la interrupción también controla el incremento de la variable tickcnt  reiniciando cuando su valor completa un mil. Dentro del bucle se llama al procedimiento  taskled cada 1ms para indicar actividad del programa con un destello de luz. Así mismo dentro del rango del contador tickcnt, cuando este llega al valor de 100ms, se procederá a la identificación de tarjeta, llevando a cabo la detección una vez por segundo, debido que este contador se reinicia a los 1000ms. 

Entonces, con intervalo de un segundo se lleva a cabo la detección de tarjetas, a través de la función RC522_Request(PICC_REQIDL, buff), esta función retornara 0 ante la presencia de una tarjeta MiFARE dentro de la zona de proximidad del lector RC522, además copiara en el vector buff dos bytes de identificación de acuerdo a la siguiente tabla:

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

Cuando la identificación es correcta en función a la tabla, se procede a leer el numero de serie con la función RC522_ReadCardSerial(buff), ambas funciones obtiene esta informacion del sector 0, bloque 0 el cual esta destinado únicamente solo para lectura de la informacion proporcionada por el fabricante. vea la fig7.

Fig7. Datos del fabricante, solo para lectura
Una vez recuperado el identificador y numero de serie de la tarjeta, en las variables rfid_tagtype y rfid_serialnum, se procede a enviar por el puerto UART un mensaje con la siguiente escrutura: ID: 0000h N:00000000

Puesto que el proceso transcurre en un periodo menor a 100ms, se procede a colocar el modulo en espera por tiempo restante antes de completar el segundo, con el procedimiento RC522_Halt().

Seguidamente se describe el procedimiento de configuracion de los periféricos, la rutina de interrupción ISR y la tarea para el destello del indicador led.

void setup(void)
{
    OSCCONbits.IRCF = 0b111;
//Oscilador 8MHz Tcy = 0.5us
    while(OSCCONbits.HTS == 0){};
    ANSEL = 0;     
//Pines AN0-AN7 en modo digital
    ANSELH = 0;    
//Pines AN8-AN13 en modo digital
    TRISAbits.TRISA5 = 0;
//Salida para RC522_CS
    TRISEbits.TRISE2 = 0;
//Pin de salida LED
    OPTION_REGbits.nRBPU = 0;
   
/* 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 */
    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
   
/* CONFIGURACION TIMER0 1MS*/
    OPTION_REGbits.T0CS = 0;
//Modo Termporizador
    OPTION_REGbits.PSA = 0;
//Con prescala para el TMR0
    OPTION_REGbits.PS = 0b011;
//Prescala 1:16
    TMR0 = 130;
//255-(time/(pre*(4/Fosc)) time=0.001 seg
    INTCONbits.T0IF = 0;
//Limpia bandera
    INTCONbits.T0IE = 1;
//Habilita interrupcion TMR0
    INTCONbits.GIE = 1;  //Habilita interrupciones
}

void __interrupt() isr() //Servicio de interrupcion
{
    if(INTCONbits.T0IF)
//Interrupcion del TMR0
    {
        TMR0 += 130;
//Restablece contador
        INTCONbits.T0IF = 0;
//Limpia la bandera
        tick1ms = 1;
//Activa bandera de tiempo 1ms
        if(tickcnt++ > 999) tickcnt = 0;
//Reinicio 1s
    }
}


void taskled(void) //Destello led
{
    static uint16_t cnt = 0;
    cnt ++;
    if(cnt == 800) LEDpin = 1;
    if(cnt > 999)
    {
        LEDpin = 0;
        cnt = 0;
    }
}

taskled es un procedimiento que se ejecuta en cada milisegundo, haciendo cuenta de las repeticiones la variable local cnt, que se incrementa desde un valor 0 hasta 999, el led se activara cuando cnt sea 800 hasta que supere los 999, en este lapso el destello durara aproximadamente 200 ms (999 - 800).

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 un componente disponible para MPLABX, accediendo a menu->tools->plugins, en esta ventana nos aseguramos de activar la instalación del componentes Simple Serial Port Terminal

Fig8. Instalación de Simple Serial Port Terminal

 Una vez instalado Simple Serial Port Terminal se configurar con el puerto COM asignado al convertidor UART-USB, en windows las asignaciones tiene nombre COMxx, mientras que para linux se cuenta con el acceso al flujo /dev/ttyUSBx.

Finalizada la configuracion del terminal, cada vez que se aproxime una tarjeta MiFARE, veremos un mensaje con el identificador y numero serial como se observa en la Fig9.

Fig9. Mensajes de las tarjetas identificadas

La fig10, 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.
Se 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 MPLABX, se encuentra en formato gzip recordando que soy usuario de linux y es probable que necesites modificar algunas referencias para compilar con windows.
 
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



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 siempre estamos abiertos a cualquier critica constructiva relacionada con esta publicación.

En esta ocasión veremos como medir el consumo de corriente alterna haciendo uso de un modulo muy accesible en cuanto a disponibilidad en el comercio y precio, este modulo se basa en el circuito integrado ACS712.
El propósito que se busca en esta oportunidad es el de 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 de consumo en amperios (A) mediante mensajes de texto enviados al puerto serial UART de una PC. para llevar a cabo las pruebas se recomienda tomar las debidas precauciones de seguridad sobre todo en la interconexión del sensor 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