[Aporte] Capacímetro Autorango con PIC16F628A

D@rkbytes

Moderador general
En esta ocasión les traigo un capacímetro autorango con una respuesta desde 3pF hasta 2600uF.
El circuito funciona en base a un microcontrolador PIC16F628A, unos pocos componentes y un LCD 16x2
Para su funcionamiento únicamente se necesita realizar un ajuste sobre un potenciómetro multivueltas.

Armado y puesta en marcha del circuito:
El circuito debe ser montado preferentemente sobre una placa de fibra de vidrio, aunque funciona muy bien sobre placas fenólicas, e incluso sobre tarjetas perforadas y protoboards.

Después de colocar y soldar perfectamente todos los componentes, se debe colocar el potenciómetro a la mitad de su recorrido y se verifica que las terminales de prueba no estén en corto circuito.

Al encender el aparato por primera vez, deberá mostrar una capacidad muy lejana a 0.00 pF.
Entonces se debe presionar el botón AUTOCAL para que el microcontrolador comience a realizar una autocalibración del sistema dejándolo en 0.00pF y almacenar el valor de calibración en la memoria interna del microcontrolador.

Una vez realizado este procedimiento se necesitará tener algún capacitor de valor conocido, ó mejor aún, un capacitor con baja tolerancia (1%) de los llamados capacitores patrón.

Se coloca este capacitor sobre los terminales de prueba y se reajusta nuevamente el potenciómetro hasta conseguir una lectura lo más aproximada al valor del capacitor de valor conocido.

Si al retirar el capacitor se muestra en la pantalla una capacidad parásita del algunos pocos pico faradios, se presiona nuevamente el botón AUTOCAL para reajustar la desviación.

Con éstos pasos ya debemos tener calibrado nuestro capacímetro y listo para medir capacitores de valor desconocido ó alterados.


Podrán notar que la precisión del circuito es muy elevada y será una herramienta muy útil en su taller.

Adjunto 4 diagramas y su correspondiente programa ejecutable *.hex, que corresponden a dos tipos de oscilador y a dos tipos de pantallas LCD 16x2, para que armen el circuito que más le convenga.

Notas:
Los archivos LCD Estándar son para pantallas genéricas 16x2 del tipo de controlador HD44780.
Y los archivos LMG-162-STN son para este tipo de pantalla China que es muy económica.
La precisión de las lecturas del circuito con oscilador interno es también muy elevada.
Los LED's de muestreo sirven para mostrar actividad del circuito en capacidades altas y bajas.
No se adjuntan los programas ni tampoco los circuitos impresos, quedando en sus manos su diseño.

Espero que este aporte sea de su completo agrado y utilidad.

Saludos y suerte.
 

Adjuntos

  • CapMeter LCD Stándar Int_Osc.rar
    99.9 KB · Visitas: 528
  • CapMeter LCD Standár Xtal.rar
    106.1 KB · Visitas: 449
  • CapMeter LMG-162-STN Int_Osc.rar
    101.2 KB · Visitas: 357
  • CapMeter LMG-162-STN Xtal.rar
    104.3 KB · Visitas: 346
  • LCD Stándar XTal SCH.jpg
    LCD Stándar XTal SCH.jpg
    122.9 KB · Visitas: 843
  • LCD Stándar Int_Osc SCH.jpg
    LCD Stándar Int_Osc SCH.jpg
    116.2 KB · Visitas: 693
Me han preguntado sobre si este proyecto se puede simular.
La respuesta es; no se pueden simular los programas, ya que el simulador agrega una desviación de 0.5 pF
y al no poder encontrarse el valor de 0.00 pF para la calibración durante la simulación, el programa entrará en un bucle al no poder ajustarse a ese valor.

Para lograr que el programa funcione bajo simulación se tuvo que hacer un cambio al programa.

Si desean ver el funcionamiento del capacímetro autorango en simulación,
aquí adjunto el diseño simulable en ISIS de PROTEUS con el cambio requerido para tal efecto.

Suerte.
 

Adjuntos

  • Simulación Capacímetro Autorango.rar
    20.9 KB · Visitas: 341
Hola D@rkbytes Esta muy bueno el proyecto. Muchas gracias por compartir. Una pregunta, acaso el principio de funcionamiento es mediante un TAC (time to amplitude converter) conformado por los dos transistores?
 
Hola D@rkbytes Esta muy bueno el proyecto. Muchas gracias por compartir. Una pregunta, acaso el principio de funcionamiento es mediante un TAC (time to amplitude converter) conformado por los dos transistores?
Funciona simplemente cargando y descargando el capacitor y tomando el tiempo con el Timer1 del PIC.
Luego se hace una comparación sobre desbordamiento y cálculos sencillos para obtener el valor.
 
Ah ya entiendo. Es mas simple de lo que pensé :D. Solo me confundió que la salida de voltaje del capacitor esta a un pin que puede ser entrada analógica y al parecer cuando trabajas con x, todo tiene x. :p
 
Hola D@rkbytes me puedes deCir el comando PARA el pic en basic o en c para la comparacion del del tiempo de caraga del capacitor
 
Última edición por un moderador:
Hola D@rkbytes me puedes deCir el comando PARA el pic en basic o en c para la comparacion del del tiempo de caraga del capacitor
No es un comando, es un set de instrucciones las que se realizan.

El programa hace lo siguiente.

Se configura el registro CMCON para trabajar con un comparador independiente (CM<2:0> = 101)

Inicia Bucle.
Se descarga el capacitor.
Se configura el TMR1 con el prescaler 1:1
Se carga el capacitor.
Se verifica si existe un cambio en comparador (CMCON.7 = C2OUT)
Si no hay cambio se toma el tiempo del TMR1, se realiza un cálculo y se muestra el valor.
Si existe cambio, se configura el TMR1 con el prescaler 1:8 (Cambio de rango)
Se toma una nueva lectura y si no existe desborde se realiza otro cálculo y se muestra el valor.
Si existe desborde del TMR1 se notifica como fuera de rango.
Reanudar el bucle.

Esto es resumidamente lo que hace el programa, en realidad es más complejo.
Como mencioné anteriormente, el código está escrito en Basic de Proton IDE, en C no lo tengo y por ahora no tengo pensado subirlo.

Saludos.
 
Última edición por un moderador:
Tal vez algún día me anime a subirlo.

Para aquellos que les interese saber cómo es que funciona este sencillo capacímetro, aquí está el código fuente.

Está escrito en PICBasic con Proton IDE.

Espero sea de utilidad.

Saludos.
 

Adjuntos

  • 16F628A CapMeter AutoCal.rar
    2.3 KB · Visitas: 667
Última edición:
Hola amigo soy nuevo en esto de los microcontroladores ,programando en c con pic c compiler .
Podrias facilitarme el archivo punto c para así entender mejor el programa xfa
De antemano te agradesco la atención gracias
 
Cómo he mencionado en los post anteriores, el código está escrito en PICBasic con Proton IDE.
NO está escrito en C.

El código en basic se encuentra en el post #11

Saludos.
 
Última edición:
Hola chicos,
Muchisimas gracias por compartir este medidor, es una pasada.
Me encanta , yo que estoy empezando con los pics y todo este mundillo, agradezco mucho esta información y como no, esa magnífica simulación para proteus.
Que maravilla
De los componentes necesarios para realizar el proyecto sólo me falta encontrar los transistores, tengo 548 y 557 pero no los que vienen el diagrama... habrá que pasarse por la tienda de eletrónica :)
Saludos
 
De los componentes necesarios para realizar el proyecto sólo me falta encontrar los transistores, tengo 548 y 557 pero no los que vienen el diagrama.
También puedes usar el BC557 o cualquier otro transistor PNP de uso general y pequeña señal.
Puse como referencia esos transistores por ser de fácil adquisición, pero no son críticos.

Suerte.
 
Como a muchas personas les gusta programar en C, me decidí por trasladar el programa a este lenguaje.
Cuando decidí escribir el programa una de las mejores opciones de entorno que pensé usar fue Proton.
Motivos:
Uso directo de los registros sin hacer referencias.
Manejo de variables del tipo Float y Double Word (32 Bits) en PIC16
Posibilidad de controlar la pantalla sin usar el pin RW (Ahorro de un pin)
Funciones nativas como el uso de Button y otras más que en permiten mejoras en el código.
Y algo muy notorio e importante; buena optimización de código :), algo que en C es difícil conseguir. :rolleyes:

Al usar C el resultado final fue el mismo, pero con la desventaja de que me quedé sin memoria ROM.
El programa final ocupó el 98.8% de memoria ROM y el 19.2% de memoria RAM.
Tamaño total del archivo hex: 11.1Kb.

En Proton el programa final ocupó el 71.78% de memoria ROM y el 26.34% de memoria RAM.
Un poco más de memoria RAM, pero sin memoria ROM ya no hay programa. :cry:
Tamaño total del archivo hex: 8.10Kb.

Resultados de compilación en C. (PICC PCWHD Compiler)
C Compilation Results.jpg

Resultados de compilación en PICBasic (Proton)
PICBasic Compilation Results.jpg


Este mismo programa en ensamblador, (MPLAB v8.92 con MPASM v5.51) ofrece estos resultados.
Assembler Compilation Results.jpg
Tamaño total del archivo hex: 2.81Kb.

Como podrán ver, la diferencia es notoria entre un lenguaje y otro.
Mientras más alto nivel se maneje, más consumo de recursos tendrá.

Adjunto el programa en PICC de CCS compilado con PCWHD Compiler v5.021 y el nuevo archivo de simulación.

Saludos.
 

Adjuntos

  • 16F628A CapMeter AutoCal PICC.rar
    62.9 KB · Visitas: 351
Última edición:
ManBarCob

Pues cambiales el nombre usando "Guardar como ...", así elijes donde guardarlos y que nombre ponerles.


Saludos, JuanKa.-
 
Esta es otra versión del código escrito en C, dirigida a reducir el tamaño del código final.
Código:
/******************************************************************************
 * ; Programa: CapMeter JHD 162A.c
 * ; Versión: 1.0
 * ; Autor: D@rkbytes
 * ; Compañia: Digitek
 * ; Fecha: 01/06/2014
 * ; Hora: 20:56:36 p.m.
 * ; Notas: Capacímetro Autorango 3pF a 2600uF. Con autocalibración
 * ;******************************************************************************/
#include <16f628a.h>
#fuses NOBROWNOUT, PROTECT
#use delay(internal = 4MHz)
#opt 11					// Según esto, optimiza el código pero no noté cambios :/

// Configuración de pines para la pantalla
#define LCD_ENABLE_PIN	PIN_A6
#define LCD_RS_PIN	PIN_A7
#define LCD_RW_PIN	PIN_A0
#include <lcd.c>

#byte PIR1 = getenv("SFR:PIR1")		// Referencia hacia el registro PIR1
#bit  TMR1IF = PIR1.0			// Referencia hacia el bit TMR1IF

// Constantes - Configuración
int1  Flag_Simular = 1;			// Bandera para simulación

// Declaración de variables globales
int16 Valor_Cap;
int8  Valor_Calib;
int16 Tiempo_Descarga;

// Declaración de funciones.
void Descargar_Cap (void);
void Muestreo_Bajo (void);


void main (void) {
    setup_comparator(NC_NC_A1_A2);	// Activar un comparador independiente
    port_b_pullups(true);		// Activar resistencias pull-up en puerto B
    output_high(pin_b0);		// Q1 y Q2 en corte
    output_high(pin_b1);

    lcd_init();				// Inicializar la pantalla
    lcd_putc("\f<CAPCHECK>  v3.0");

    if (!Flag_Simular) {		// Si voy a simular, omito el mensaje y el retardo
	lcd_gotoxy(3,2);
	lcd_putc("DIGITEK 2013");
	delay_ms(2000);
    }

    Tiempo_Descarga = 250;		// Iniciar el muestreo de Cx en períodos de 250 ms
    Descargar_Cap();			// Descargar Cx
    Valor_Calib = read_eeprom(1);	// Leer el valor de calibración

    while (true) {
	if (!input(pin_b3)) {		// Si RB3 es 0...
	    if (Valor_Cap != 0) {		// Si Valor_Cap no es 0.0...

		Tiempo_Descarga = 1;			// Disminuir el tiempo de descarga

		while (true) {
		    Valor_Calib += 1;				// Incrementar el valor de calibración.
		    Muestreo_Bajo();

		    // Mostrar el valor de calibración en hexadecimal
		    lcd_gotoxy(1,1);
		    printf(lcd_putc,"CALIBRANDO: 0x%02X", Valor_Calib);

		    if (Valor_Cap == 0) {			// Cuando Valor_Cap sea 0...
			write_eeprom(1,Valor_Calib);		// Guardar el valor de calibración
			delay_ms(1000);
			break;
		    }
		}
	    }

	    // Calibrado:
	    lcd_putc("\f<CAPCHECK>  v3.0");	// Mostrar que se ha calibrado el equipo
	    lcd_gotoxy(1,2);
	    lcd_putc("*CALIBRACION OK*");
	    delay_ms(1000);
	    Tiempo_Descarga = 250;		// Reestablecer el tiempo de descarga a 250 ms
	}
	Muestreo_Bajo();
    }
}


void Muestreo_Bajo (void) {
    Descargar_Cap();				// Descargar Cx
    clear_interrupt(INT_TIMER1);		// Limpiar la bandera de interrupción del TMR1 (TMR1IF)
    set_timer1(0x00);				// Limpiar valores de TMR1H y TMR1L
    setup_timer_1(T1_DISABLED);			// Prescaler 1:1, TMR1 = OFF
    output_low(pin_b1);				// RB1 en 0 para cargar Cx. (Q2 en saturación)
    setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);	// Habilitar el Timer1 para medir el tiempo de carga de Cx

    // Esperar_Carga:
    while (!TMR1IF) {				// Mientras TMR1 no desborde
	if (C2OUT) {					// Si C2OUT no es cero
	    // Calculo_Bajo:
	    setup_timer_1(T1_DISABLED);			// Deshabilitar el Timer1 para medir el tiempo de carga de Cx
	    output_high(pin_b1);			// Detener la carga de Cx. (Q2 en corte)

	    Valor_Cap  = get_timer1();
	    Valor_Cap *= 100;				// Para hacer todas las operaciones enteras, hasta el printf
	    Valor_Cap /= 2;				// Corrección para la calibración
	    Valor_Cap -= Valor_Calib * 100;

	    if (Flag_Simular) {				// Si voy a simular entonces resto 0.5
		Valor_Cap -= 50;
	    }

	    lcd_gotoxy(1,2);				// Mostrar el valor del capacitor en pF
	    printf(lcd_putc,"Cx = %0.2f %cF    ", Valor_Cap / 100.0, 0xE6);	// p
	    return;
	}
    }

    // Tiempo_OK:
    clear_interrupt(INT_TIMER1);		// Limpiar la bandera de interrupción del TMR1
    output_high(pin_b1);			// Detener la carga de Cx

    // Muestreo_Alto:
    Descargar_Cap();				// Descargar Cx

    setup_timer_1(T1_DISABLED);			// Deshabilitar TMR1
    set_timer1(0x00);				// Limpiar valores de TMR1
    clear_interrupt(INT_TIMER1);		// Limpiar la bandera de interrupción del TMR1
    output_low(pin_b0);				// RB0 en 0 para cargar Cx
    setup_timer_1(T1_INTERNAL|T1_DIV_BY_8);	// Habilitar el Timer1 para medir el tiempo de carga de Cx

    // Esperar_Carga2:
    while (!TMR1IF) {				// Mientras TMR1 no desborde
	if (C2OUT) {					// Checar si VCx es > 0.632V
	    // Calculo_Alto:
	    setup_timer_1(T1_DISABLED);			// Detener TMR1 para obtener el tiempo leído
	    output_high(pin_b0);			// Detener la carga de Cx

	    Valor_Cap = get_timer1();
	    Valor_Cap *= 100;				// Para hacer todas las operaciones enteras, hasta el printf
	    Valor_Cap /= 25;				// Dividir el tiempo medido por 25 (8 us/200 Omhs = 1/25)

	    lcd_gotoxy(1,2);				// Mostrar el valor del capacitor en uF
	    printf(lcd_putc,"Cx = %0.2f %cF    ", Valor_Cap / 100.0, 0xE4);	// u
	    return;
	}
    }

    // Tiempo2_OK:
    clear_interrupt(INT_TIMER1);		// Si, limpiar la bandera de interrupción del TMR1
    output_high(pin_b0);			// Detener la carga de Cx
    lcd_gotoxy(1,2);				// Mostrar el mensaje de error en la pantalla por método de tabla
    lcd_putc("!FUERA DE RANGO!");
    delay_ms(1000);				// Esperar 1 segundo
    return;
}


void Descargar_Cap (void) {
    output_low(pin_a2);				// RA2 en 0 para descargar Cx
    delay_us(10);				// 10 us de retardo para tiempo de reestablecimiento
    delay_ms(Tiempo_Descarga);			// Retardo para descargar Cx completamente (250 ms)
    output_float(pin_a2);			// RA2 como entrada
    delay_us(10);				// 10 us de retardo para tiempo de reestablecimiento
}
Se han eliminado los goto y una variable. Además, retrasar el uso de punto flotante hasta el final.

Lo malo es que no puedo probarlo a ver si funciona...
 
Esta es otra versión del código escrito en C, dirigida a reducir el tamaño del código final.
Se han eliminado los goto y una variable. Además, retrasar el uso de punto flotante hasta el final.

Lo malo es que no puedo probarlo a ver si funciona...
Saludos Joaquín, siento decirte que el código que expones, no funciona.
Muestra valores que no tienen nada que ver con el programa en Protón, ni con el que fue migrado a C.

Sé que el código en C se puede optimizar, sin embargo esa no fue la intención al haberlo pasado a C.
La verdadera intención fue que sea entendido por las personas que usan este lenguaje, y en PICC de CCS.
También entiendo que el uso de GoTo en C no es bien visto, sin embargo no es una instrucción prohibida.

Traté de hacer una transcripción lo más directa del código en PICBasic y por ese motivo omití los GoTo.

Lo que traté también de demostrar, es como los compiladores afectan a un programa en cuanto al tamaño final cuando se usan variables del tipo Float. (Mis respetos para Proton IDE)

Gracias Joaquín por tomarte el tiempo para reducir el tamaño del código, sé que a muchos les será de ayuda para una mejor comprensión del programa.
 
Era obvio que no funcionaría a la primera, ya que voy a ciegas.

Mi objetivo no era tanto eliminar los goto, sino intentar reducir el tamaño del programa una vez compilado, ya que según lo que mostrabas antes, estaba a punto de llenarse la memoria para programas.

Naturalmente, el trabajo con punto flotante es muy oneroso en cuestión de instrucciones a ejecutar. Y por eso, cuando tenemos la memoria limitada, es interesante conocer técnicas para reducir el costo.

Aunque no funcione, sí que tengo curiosidad en saber si el tamaño del programa se ha reducido o no. En el programa lo dejé con dos llamadas para conversión y división a punto flotante. Según lo bueno que fuera el compilador debería haber ahorrado algunos bytes.

Saludos.
 
Atrás
Arriba