Voltimetro con pic CCS compemdio

Multímetro de Banco - Versión 1.0
Después de realizar el multímetro de banco anterior, he decidido mejorar el mismo creando este nuevo proyecto en su versión 1.0, lo cual quiere decir que con el tiempo se irá mejorando y agregando funciones.
En este link se puede leer el principio de funcionamiento (lo que es medición y procesamiento de la señal), ya que funciona igual. http://electgpl.blogspot.com.ar/2014/04/multimetro-de-banco-con-datalogger.html
Se le incorpora la medición de frecuencia lo cual también pueden encontrarlo en el siguiente linkhttp://electgpl.blogspot.com.ar/2014/03/frecuencimetro-hasta-30khz.html
Por último se le agrega la medición de diodos, y continuidad visual (se le puede agregar alerta acústica donde está el led, con un transistor y un buzzer).
El funcionamiento de todo el sistema es en base a un menú, el cual se realiza con la sentencia Switch Case, y se opera mediante un único pulsador.
Al presionar el pulsador se incrementa la variable menú en una unidad, y cambia de Case en la sentencia Switch, dentro de cada Case se procede a realizar la función especifica. Como se pueden imaginar se puede incrementar la cantidad de Cases para incrementar la cantidad de funciones.
Por el momento no he realizado funciones (lo cual quedaría mucho mas prolijo) porque mi idea es que sea de fácil comprensión para aquellos que recién se inician.
Se utiliza un multiplexor/demultiplexor Analógico 4051 que cumple la función de switchear digitalmente la entrada analógica del MCU para cambiar las diferentes funciones, el mismo se comanda por las direcciones binarias.El circuito funciona con 5V por ejemplo provenientes de un puerto USB o de un pack de pilas (Con su regulador de tensión a 5V).

#include <16F883.h>
#device adc=10
#FUSES XT,NOWDT
#use delay(clock=4000000)
#include <LCD.C>
void main(){
   int16 valorADC, frecuencia;
   int menu=1;
   float corriente, tension, diodos, temperatura;
   setup_adc_ports(sAN0|VSS_VDD);
   setup_adc(ADC_CLOCK_INTERNAL);
   lcd_init();
   while(TRUE){ 
      if(input(PIN_C1)==1){
         delay_ms(200);
         menu++;
         if(menu>6)
         menu=1;
      }
      switch(menu){
      case 1:
         lcd_gotoxy(1,1);
         printf(lcd_putc,"VOLTIMETRO    DC");
         output_low(pin_c4);
         output_low(pin_c5);   
         set_adc_channel(0);
         delay_us(20);
         valorADC = read_adc();
         tension = 5.0 * valorADC / 1024.0;   
         lcd_gotoxy(1,2);
         printf(lcd_putc,"VM:10V    %1.3fV",tension*2);
         break;
      case 2:
         lcd_gotoxy(1,1);
         printf(lcd_putc,"AMPERIMETRO   DC");
         output_high(pin_c4);
         output_low(pin_c5);
         set_adc_channel(0);
         delay_us(20);
         valorADC = read_adc();
         corriente = (5.0 * valorADC / 1024.0) * 0.2118;
         lcd_gotoxy(1,2);
         printf(lcd_putc,"IM:1A     %1.3fA",corriente);
         break;
      case 3:
         lcd_gotoxy(1,1);
         printf(lcd_putc,"FRECUENCIMETRO  ");
         set_timer1(0);
         setup_timer_1(T1_EXTERNAL|T1_DIV_BY_1);
         delay_ms(500);
         setup_timer_1(T1_DISABLED);
         frecuencia=get_timer1();
         lcd_gotoxy(1,2);
         printf(lcd_putc,"       %6lu Hz",frecuencia*2);
         break;
      case 4:
         lcd_gotoxy(1,1);
         printf(lcd_putc,"DIODOS Y LEDS   ");
         output_low(pin_c4);
         output_high(pin_c5);
         set_adc_channel(0);
         delay_us(20);
         valorADC = read_adc();
         diodos = 5.0 * valorADC / 1024.0;   
         lcd_gotoxy(1,2);
         printf(lcd_putc,"          %1.3fV",diodos);
         break;
      case 5:
         lcd_gotoxy(1,1);
         printf(lcd_putc,"TEMPERATURA     ");
         output_high(pin_c4);
         output_high(pin_c5);
         set_adc_channel(0);
         delay_us(20);
         valorADC = read_adc();
         temperatura = (5.0 * valorADC / 1024.0) * 100;   
         lcd_gotoxy(1,2);
         printf(lcd_putc,"          %2.1f°C",temperatura);
         break; 
      case 6:
         lcd_gotoxy(1,1);
         printf(lcd_putc,"CONTINUIDAD     ");
         lcd_gotoxy(1,2);
         if(input(PIN_C2)==0){
            printf(lcd_putc,"CIRCUITO CERRADO");
            output_high(pin_c3);
         }
         else{
            printf(lcd_putc,"CIRCUITO ABIERTO");
            output_low(pin_c3);
         }      
         break;   
      default:
         lcd_gotoxy(1,1);
         printf(lcd_putc,"    **ERROR**   ");
         lcd_gotoxy(1,2);
         printf(lcd_putc,"   [REINICIAR]  ");
      }
   }
}

Frecuencimetro Hasta 30kHz
En este post, les mostrare una forma muy sencilla de realizar un frecuencímetro de uso general, aunque de bajas prestaciones.
Un frecuencímetro es un instrumento de medición que debe realizar una cuenta en un determinado tiempo.
La frecuencia en Hertz es la cantidad de veces que se repite un pulso durante el transcurso de 1s.
Por ejemplo: Si durante 1s contamos 30 pulsos, la frecuencia será de 30Hz. Si durante 1s contamos 1000 pulsos, la frecuencia será de 1kHz, y así sucesivamente para cualquier valor.
En este programa extremadamente sencillo aplicaremos esta misma lógica, utilizaremos el Timer1 para crear un temporizador de 1s (el cual genera el lapso de tiempo para contar pulsos) y durante este lapso de 1s se contaran los pulsos que ingresan en la entrada T1CKI (Timer 1 External Clock Input).
La forma de pensar esta lógica será la siguiente:

1) Encendemos el Timer
2) Demoramos 1s (el lapso de cuenta)
3) Apagamos el Timer
4) Mostramos cuantos pulsos ingresaron por T1CKI durante ese segundo.

Como pueden ver en el programa la demora no es de 1000ms (1s) sino que es de 250ms, esto es porque en la configuración del Timer1 tenemos el divisor (preescaler) por 1, si quieren poner la demora de 1000ms tienen que configurar el preescaler como divisor por 4, esto quedaría: T1_DIV_BY_4, pero el refresco del LCD en mostrar la cuenta seria de 1s por ende es un poco lento y perdemos muestras, entonces al configurar el preescaler por 1 y esperar 250ms obtenemos el mismo resultado pero el LCD y las muestras se actualizan cada 1/4s entonces el funcionamiento será más eficiente.

Claramente no es un instrumento de precisión ni mucho menos, solamente trata de explicar, mediante el uso del timer1 como temporizador, el funcionamiento básico de un frecuencímetro. El mismo está limitado en frecuencia, pero hasta los 30kHz nos mostrara una cuenta estable.
Si quieren que este frecuencímetro acepte mayor frecuencia pueden poner un preescaler externo, que podría ser un circuito con FF (donde cada FF realizara una división por 2). Si utilizamos un 4017, tendremos un divisor programable de 1 a 10, donde la máxima entrada serian 300kHz que al pasar por el divisor /10 nos dará 30kHz y no tendríamos problemas en el MCU, (dentro del MCU en el printf tendremos que compensar esta división con una multiplicación por el mismo valor para que la lectura sea correcta), esto quedaría: printf(lcd_putc,"%lu Hz",pulsos*10); entonces de este modo ingresamos 300kHz al 4017, salimos con 30kHz del 4017 que ingresaran al MCU y la lectura será de 30kHz*10=300kHz.
Descripción: https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjQeciKZO-DMpe_HA9qpd0ECQAQKLYz8qXFUyDB_aRC49hcfG2iU-1GYUTgrH57KHJBOOX6oHAyQcpVfozznFEvNi8-o5RHtjwuE1HMhuEjx-jMaBX9HFNjfS8c3Kjy7vE1ErdjDkCEJcuI/s1600/Frecuencimetro.png


#include <16F628A.h>
#FUSES NOWDT
#FUSES HS
#FUSES NOPUT
#FUSES NOPROTECT
#FUSES NOBROWNOUT
#FUSES NOMCLR
#FUSES NOLVP
#FUSES NOCPD
#use delay(clock=4000000)
#define LCD_ENABLE_PIN  PIN_B7
#define LCD_RS_PIN      PIN_B4
#define LCD_RW_PIN      PIN_B5
#define LCD_DATA4       PIN_B0
#define LCD_DATA5       PIN_B1
#define LCD_DATA6       PIN_B2
#define LCD_DATA7       PIN_B3
#include <LCD.C>
void main(){
   lcd_init();
   int16 pulsos;
   while(true){
      set_timer1(0);                          //HAB Timer1
      setup_timer_1(T1_EXTERNAL|T1_DIV_BY_1); //ON Timer1 2kHz
      delay_ms(250);                          //Demora 1/4s
      setup_timer_1(T1_DISABLED);             //INHAB Timer1
      pulsos=get_timer1();                    //CONT Pulsos
      lcd_gotoxy(1,1);                        //Renglon (1,1)
      printf(lcd_putc,"%lu Hz",pulsos);       //Muestra f
   }
}


NOTA: la redefinición de pines del display LCD se ha realizado porque se necesitaba el pin T1CKI que se encontraba dentro de los pines del LCD por defecto.
En este nuevo post les traeré un proyecto útil para el laboratorio, con el tiempo pretendo agregarle más funciones, como Medición de Resistencias, Capacitores, Inductores, Frecuencia y Diodos (por el momento solo les presento el proyecto simple como para que puedan ir observando la evolución del mismo y comprendiendo cada bloque.
En este caso las mediciones son de Tensión, Corriente, Potencia y Temperatura, como se puede ver en él la imagen animada los cuatro datos se ven en simultaneo.
El circuito que se propone es extremadamente sencillo, solo es el microcontrolador, el LCD, un LM35 y un Shunt.
El microcontrolador puede que sea algo grande para dicha tarea pero es económico y cuando le comencemos a incorporar funciones extra nos servirá su poder de procesamiento.
El LCD es un simple LCD de 2x16 caracteres.
El Shunt en este caso es una resistencia de 4.7Ohms de 10W (Las cerámicas).
El LM35 es nuestro sensor de temperatura que nos entregara 10mV por cada 1°C (es decir si lee una temperatura de 25°C nos entregara en su salida 250mV).
Descripción: https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhudtmocGl0sOkZd86_pxNKVn7b9uDQgCXhuWk0tiiBQhuS63Ycq4L28CfbIbHVX4arcmBq2ic86nSktORPjBgN9NccAgcSKKPshsBLzdX_zixmCwqRXKmVrT_mC-g7N9DAfe-JPxAbor3Z/s1600/multimetro.gif
El principio de funcionamiento:
La medición de Tensión se realiza de forma directa ya que este multimetro tiene un fondo de escala de 5V, sé que es poco pero una de las actualizaciones será incrementar dicho fondo de escala, por ahora nos sirve para medi el consumo en circuitos de 5V (ya sean Leds, USB, etc...).
La medición de Corriente se realiza mediante el shunt, la idea del shunt es de un componente pasivo de baja resistencia conocida, es decir, si alguna vez desarmaron un multimetro pueden encontrar un alambre de más o menos 1mm con forma de U, este es el shunt, no es solo un alambre sino que es un alambre calibrado, por ejemplo de 0,1Ohms, esto se utiliza porque mediante la ley de Ohm conociendo la Resistencia y midiendo la caída de tensión podemos obtener la corriente que lo atraviesa.
Si tenemos nuestra resistencia de 4.7Ohms, y le aplicamos una tensión de 3V, por ley de ohm, tendremos que I=V/R, I=3V/4.7R=638mA, esta es la corriente que atraviesa dicha resistencia.
Entonces si nosotros tenemos por ejemplo un circuito con 10 leds que se alimenta con 4V y estos 10 Leds tienen un consumo de 200mA, la forma de corroborar este consumo es poniendo nuestro Shunt en serie a esta Carga y así podemos saber la corriente que lo atraviesa. Claramente se estarán imaginando que 4.7Ohms es una resistencia considerable, es decir si tengo un circuito que representa una resistencia de carga de 20Ohms, poner en serie 4.7Ohms nos dará 24.7Ohms lo cual es un 20% de la carga aproximadamente, por ende esta es la razón por la cual se utilizan shunts con valores bajos de resistencia por ejemplo 0.1R, 0.01R.., etc... El inconveniente es que si tenemos un Shunt de por ejemplo 0.1R y aplicamos el mismo ejemplo anterior de 3V, tendremos que I=V/R, I=3V/0.1R=30mA, y si queremos medir los 200mA de los leds la ley de ohm nos dirá que la caída de tensión en el shunt de 0.1R es de V=I*R, V=200mA*0.1R=20mV, entonces al ADC del MCU le llegaran solo 20mV. En esta configuración utilizando la tensión de referencia del ADC del MCU igual a Vdd ósea 5V, si nos llegan 20mV será una medida muy baja teniendo en cuenta el fondo de escala que son 5V. Si usamos la resistencia de 4.7R la tensión en el ADC para una carga de 200mA será V=200mA*4.7R=940mV, lo cual ya estamos casi en 1V y la representación será mejor. Si queremos usar un Shunt de 0.1Ohms el problema es que hay otro parámetro a tener en cuenta, La Potencia de Disipación de la Resistencia, si queremos un fondo de escala de 5V (para completar todo el rango del ADC) con una resistencia de 4.7Ohms la corriente que atraviesa a esta será I=V/R, I=5V/4.7R=1.063A, si medimos la potencia, será P=I^2*R=1.063^2*4.7R=8.14W lo que nos dice que requerimos una Resistencia de al menos 10W, si en cambio utilizamos la resistencia de 0,1Ohm la corriente que atraviesa a esta será I=V/R, I=5V/0,1R=50A, si medimos la potencia, será P=I^2*R=50A^2*0.1R=250W lo que nos dice que requerimos una Resistencia de al menos 250W. Por esa razón no podemos usar un fondo de escala de 5V sino que hay que bajarlo. Y esto se puede bajar o bien bajando la tensión de referencia del ADC o bien acondicionando la entrada con otro circuito. Si queremos modificar la referencia del ADC tenemos que poner una fuente estable en la referencia positiva, por ejemplo un diodo Zener de 1V, ahí ya el valor baja mucho por ejemplo para 0.1Ohms, será I=V/R, I=1V/0.1R=10A, P=I^2*R=10A^2*0.1R=10W el valor es mucho mas cómodo y mas económico.
Para calcular el valor de conversión de la tensión que llega al ADC desde la medición de caída de tensión en la resistencia de 4.7R (nuestro Shunt) se ha utilizado una regresión lineal a partir de una tabla de valores.
Descripción: https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgTcgY05WeHhDcaCyQcrx2TQlw8NcUYdPQhmhdGOMDafHzLqEZ_6z6s1RT58EofpKWi98M1EcwdMY-W7_K86T2rs75HDkaVOAelnn87U98hcH7-FJQMj7tXvL91qssMxH1teZ0G8AO6kawu/s1600/tabla.png
Descripción: https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgzE0jwlgXcV7OBSRSV_raZHM78W1Jl-f63Z-pkgRL0oSgmY9lVL3SjvrZ1r84eYhId_-VvnhXekml0U6G8qeXmRZ2gZo8Kf_6Zgp9l7upS-ZCudIKUDozZI9X8Cg87a0yVhm41DG5HR7zy/s1600/grafico.png
Pueden ver la forma de calcular la regresión en el siguiente link:
http://electgpl.blogspot.com.ar/2014/03/algoritmo-para-regresion-estadistica-en.html
Esto nos ha dicho que multiplicando el valor de caída de tensión del Shunt por 0.2118 nos dará un proporcional en Ampere para mostrar en el LCD, tomando el ejemplo anterior si medimos una caída de tensión V=200mA*4.7R=940mV al ADC ingresaran esos 940mV pero en el LCD debemos mostrar los 200mA para ello multiplicamos 0.940*0.2118=0.1992 que es aproximadamente 200mA.
La medición de Potencia será claramente el producto entre la tensión y la corriente medidas anteriormente, P=V*I y se mostrara el valor en el LCD.
La medición de Temperatura también requiere una conversión ya que el sensor LM35 nos entregara 10mV por cada 1°C, entonces si el ADC nos lee 300mV entonces el cálculo será 300mV * 100= 30°C.
La salida de Data Logger es mediante el puerto USART serie a 9600bps (se puede modificar claramente) este como se puede ver en el programa nos da un string con los 4 valores leídos lo cual se irá actualizando con la finalidad de podes exportar esta tabla de 4 columnas a algún programa y procesar dichos cambios.



#include <16F883.h>
#device adc=8
#FUSES NOWDT
#FUSES INTRC_IO
#FUSES NOPUT
#FUSES MCLR
#FUSES NOPROTECT
#FUSES NOCPD
#FUSES NOBROWNOUT
#FUSES IESO
#FUSES FCMEN
#FUSES NOLVP
#FUSES NODEBUG
#FUSES NOWRT
#FUSES BORV40
#use delay(int=4000000)
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=5)
#include <LCD.C>
void main(){
   setup_adc_ports(sAN0|sAN1|sAN2|VSS_VDD);
   setup_adc(ADC_CLOCK_DIV_2);
   setup_spi(SPI_SS_DISABLED);
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
   setup_timer_1(T1_DISABLED);
   setup_timer_2(T2_DISABLED,0,1);
   setup_ccp1(CCP_OFF);
   setup_comparator(NC_NC_NC_NC);
   lcd_init();
   int8 currentADC, voltajeADC, tempADC;
   float currentA, voltajeV, tempC, powerW;
   while(TRUE){
      set_adc_channel(0);
      delay_us(10);
      currentADC = read_adc();
      currentA = (5.0 * currentADC / 256) * 0.2118;
      set_adc_channel(1);
      delay_us(10);
      voltajeADC = read_adc();
      voltajeV = 5.0 * voltajeADC / 256;
      set_adc_channel(2);
      delay_us(10);
      tempADC = read_adc();
      tempC = (5.0 * tempADC / 256) * 100;
      powerW = voltajeV * currentA;
      lcd_gotoxy(1,1);
      printf(lcd_putc,"[V]:%02.2f[A]:%1.2f",voltajeV,currentA);
      lcd_gotoxy(1,2);
      printf(lcd_putc,"[W]:%1.2f[C]:%02.1f",powerW,tempC);
      printf("[v]:%02.1f [A]:%1.3f [W]:%1.3f [C]:%02.1f\r",voltajeV,currentA,powerW,tempC);
   }
}


Comentarios

Entradas populares de este blog

FUENTE LABORATORIO PIC 18F2550 (CÓDIGO) PROTON IDE COMPILER

VOLTIMETRO CON PIC CCS PROTEUS