Ultimamente he tenido que trabajar con inductores, y bueno, como he mencionado, son de los elementos que si podemos construir solo con algo de alambre.
Así que, he tenido la necesidad de construir algunos inductores para mis circuitos. En muchos otros sitios hay muchos artículos y muy buenos de circuitos medidores de LC con PICs (los más antiguos ) y AVR/Arduino (los más recientes). Y prácticamente todos tienen como base el mismo circuito hecho a base del LM311. En la mayoría de los artículos que encontré tienen una buena explicación acerca de cómo funciona el circuito de oscilación, así que no voy a hacer mucho comentario al respecto. Ya que el circuito base es muy estable y no presenta mucha complejidad, si quieren la explicación acerca del circuito base, pueden leer estos artículos.
Entonces, ¿aquí que voy a tratar? Bueno, suponiendo que logramos tener funcionando el circuito oscilador. Lo que sigue es interpretar lo mejor posible la frecuencia de salida para obtener las mediciones de los capacitores e inductores.
Cuando se hacen cálculos con punto flotante (y con mas razón en los procesadores/compiladores donde es emulado) hay que evitar lo mas posible las restas, las divisiones y las raíces cuadradas, ya que estas operaciones arrastran mas errores de precisión que las demás.
Y las ecuaciones base con las que trabajaremos serán:
Como se ve en el circuito, podríamos, a primera impresión, solo despejar de las ecuaciones base los valores que buscamos con respecto a los que conocemos. Pero presenta problemas de precisión debido a los errores que se acarrean con las operaciones que se hacen, además que dependemos mucho de saber lo mejor posible (y con anticipación) los valores de L, C y Ccal y eso es malo si pensamos hacer mas de uno, además de que tendríamos el problema del huevo y la gallina, por que necesitamos un medidor LC para construir el medidor LC.
Para no depender de los valores de L y C, conseguiremos un Capacitor de precisión para la calibración. Se que es un poco caro y solo lo he conseguido en mouser, pero bueno, vale la pena, ya que solo con ese valor podemos medir a L y C.
Ahora bien, como habíamos dicho, necesitamos deshacernos de las raíces. Para esto será necesario establecer con las frecuencias, que es lo que podemos medir directamente con el microcontrolador (timers), relaciones con las que dejemos de depender lo mas posible de valores desconocidos.
Y las relaciones que se pueden encontrar son las siguientes:
Sacando relaciones entre las frecuencias, podemos deshacernos de las raíces y de constantes. Pero la relación todavía depende del valor de L, así que usando las relaciones recién desarrolladas…
Así pues, vemos que, para la relación tenemos que multiplicarla por la relación
para deshacerse de L y este resultado por
para simplificar C, y esto por
y así solamente tener L.
Entonces, Cx y Lx, que son los valores que vamos a medir, estan en función de las frecuencias y el valor del Capacitor de calibración, que como habíamos mencionado es el único por el cual valdría la pena invertir en que fuera de la mayor precisión posible. También se puede observar que los valores de C y de L ya son prácticamente despreciables, excepto por el valor de la frecuencia que esta por los 600kHz-700kHz. Pero, ¿por qué ésta frecuencia base? Bueno eso lo veremos a continuación…
Pero antes, aqui dejo la hoja completa del cálculo
Implementación
Para los microcontroladores como los AVR, los timers/contadores generalmente son de 8 y 16 bits, para los PSoC1 pueden ser de hasta 32 bits. Dependiendo el procesador será la forma y la frecuencia máxima que debemos cuidar en el circuito de oscilación. Por ejemplo, para los AVR/PICs es importante que la frecuencia no supere los 600kHz-700kHz y la razón es muy sencilla: como el timer es de 16 bits, el valor máximo que podemos contar es 65535, que es aproximadamente una décima parte de la frecuencia que proponemos como limite. Esto significa que debemos hacer el cálculo dejando correr el contador solo 0.1 segundos (o menos). Bueno, uno podría pensar en bajar la frecuencia base con unos L y C mas grandes, y así dejar correr el timer/contador mas tiempo, pero eso trae el detalle de que no podríamos medir valores muy pequeños de capacitancia o inductancia. Lo ideal seria poder llevar el oscilador al máximo permitido por el LM311 que es de aprox 2.5MHz, o bien a la frecuencia máxima que nos permita la entrada del timer/contador en el AVR, pero eso implica que el tiempo en el cual medimos la frecuencia, debe ser mas pequeño, induciendo errores por muestreos mas pequeños.
En fin, para la implementacion, el procesador que se usará, es el ATmega8 a 12MHz con un cristal externo, lo que hace mas estable y mas preciso para el tiempo de muestreo de la frecuencia del oscilador LC.
Aqui el circuito:
Para establecer el tiempo de muestreo, explore con configuraciones que fueran facilmente convertibles a «frecuencia real», es decir, que pueda multiplicarlas por las muestras que puedo hacer por un segundo y obtener asi la «frecuencia real» que sale de oscilador LC. El valor que mejor pude ajustar para medir fue 20ms. Con el reloj principal del procesador a 12MHz la configuracion queda mas o menos asi:
Con el timer1 (16 bits) como contador y dejando que corra libre. Por lo que el codigo de esa parte queda asi:
// Timer/Counter 0 initialization // Clock source: System Clock // Clock value: 20ms TCCR0=(1<<CS02) | (0<<CS01) | (1<<CS00); TCNT0=0x16; // Timer/Counter 1 initialization // Clock source: T1 pin Falling Edge // Mode: Normal top=0xFFFF // OC1A output: Disconnected // OC1B output: Disconnected // Noise Canceler: Off // Input Capture on Falling Edge // Timer1 Overflow Interrupt: Off // Input Capture Interrupt: Off // Compare A Match Interrupt: Off // Compare B Match Interrupt: Off TCCR1A=(0<<COM1A1) | (0<<COM1A0) | (0<<COM1B1) | (0<<COM1B0) | (0<<WGM11) | (0<<WGM10); TCCR1B=(0<<ICNC1) | (0<<ICES1) | (0<<WGM13) | (0<<WGM12) | (1<<CS12) | (1<<CS11) | (0<<CS10); TCNT1H=0x00; TCNT1L=0x00; ICR1H=0x00; ICR1L=0x00; OCR1AH=0x00; OCR1AL=0x00; OCR1BH=0x00; OCR1BL=0x00; // Timer(s)/Counter(s) Interrupt(s) initialization TIMSK=(0<<OCIE2) | (0<<TOIE2) | (0<<TICIE1) | (0<<OCIE1A) | (0<<OCIE1B) | (0<<TOIE1) | (1<<TOIE0);
Para medir la frecuencia, el procedimiento es el siguiente, reiniciar los timers (timer0 y timer1), habilitar la interrupcion, esperar a que se ejecute y leer el timer1, multiplicarlo por un factor, que en este caso es 50( ) y asi obtener la frecuencia del oscilador.
#define TIMER0_STOP (TCCR0 = 0) #define TIMER0_START (TCCR0=(1<<CS02) | (0<<CS01) | (1<<CS00)) #define TIMER0_VAL_START (TCNT0=0x16) #define BIT17_CLEAR ( TIFR &= !(1 << TOV1)) #define BIT17_TEST ( TIFR & (1 << TOV1) ) #define TIMER1_CLEAR ( TCNT1 = 0 ) #define TIMER1_START ( TCCR1A=(0<<COM1A1) | (0<<COM1A0) | (0<<COM1B1) | (0<<COM1B0) | (0<<WGM11) | (0<<WGM10), TCCR1B=(0<<ICNC1) | (0<<ICES1) | (0<<WGM13) | (0<<WGM12) | (1<<CS12) | (1<<CS11) | (0<<CS10) ) #define TIMER1_STOP ( TCCR1A=TCCR1B=0 ) long int contador; // Timer 0 overflow interrupt service routine interrupt [TIM0_OVF] void timer0_ovf_isr(void) { TIMER1_STOP; TIMER0_STOP; contador = TCNT1; if( BIT17_TEST ) contador |= (long int ) 0x10000; busy_flag = 0; } float get_frec(void) { BIT17_CLEAR; TIMER1_CLEAR; TIMER0_VAL_START; TIMER1_START; TIMER0_START; busy_flag = 1; while(busy_flag); return 50.0 * (float) contador; }
Como se ve, la funcion de get_frec() activa los timers, interrupciones y hace la conversion necesaria, con lo que, cuando necesitemos leer la frecuencia solo llamamos a esa función.
Por cierto, habilite la bandera de «overflow» del tiemer1, para que trabaje el timer como si fuera de 17 bits, esto por si queremos un oscilador LC de mas frecuencia, digo, por si queremos experimetar y llevar al maximo nuestro medidor.
Las otras funciones, que vale la pena mencionar son la de medir Cx y Lx que dejo a continuacion:
char prefijos[] = {' ','m','u','n','p','f'}; void medir_Cx(void) { char cad_lcd[20]; unsigned char i; float Cx; RELE1 = OFF; RELE2 = OFF; f_cx=get_frec(); lcd_clear(); lcd_putsf("Capacitancia"); if( f_cx < 100.0 ) // valor muy grande { lcd_gotoxy(0,1); lcd_putsf("...."); return; } Cx = ( ( pow(f_0/f_cx,2.0)-1.0 )/( pow(f_0/f_cal ,2.0)-1.0 ) ) * CCAL; for(i=0; i<5; i++) // "autorango" { if(Cx > 1.0) break; else Cx = Cx * 1000.0; } if( i==5 ) // valor muy pequeño, mas pequeño que picos { lcd_gotoxy(0,1); lcd_putsf("...."); return; } lcd_gotoxy(0,1); sprintf(cad_lcd,"%6.2f%cF", Cx, prefijos[i]); lcd_puts(cad_lcd); } void medir_Lx(void) { char cad_lcd[20]; unsigned char i; float Lx; RELE1 = OFF; RELE2 = ON; f_lx=get_frec(); lcd_clear(); lcd_putsf("Inductancia"); if( f_lx < 100.0 ) // valor muy grande { lcd_gotoxy(0,1); lcd_putsf("...."); return; } Lx = ( pow(f_0/f_lx,2.0)-1.0 ) * ( pow( 1/(2*PI*f_0) ,2.0) ) * ( pow(f_0/f_cal,2.0)-1.0 ) * ( 1/CCAL ); for(i=0; i<5; i++) // "autorango" { if(Lx > 1.0) break; else Lx = Lx * 1000.0; } if( i==5 ) // valor muy pequeño { lcd_gotoxy(0,1); lcd_putsf("...."); return; } lcd_gotoxy(0,1); sprintf(cad_lcd,"%6.2f%cH", Lx, prefijos[i]); lcd_puts(cad_lcd); }
Pruebas
Cuando armé el circuito en protoboard, pude hacer un par de pruebas, el capacitor de calibracion que usé es de 1000pF +/- 0.5%. De hecho con las prubas se puede ver que incluso solo con las formulas base (usando raices cuadradas) pude determinar el valor de la bobina con bastante precision, ya que esta marcada como de 82uH:
Pero ya con la rutina de calibracion, unos capacitores y sus medidas:
Algunos inductores:
Para variar, el codigo esta en codevision (si no tienen el compilador, esta el archivo HEX para pasarlo directo al procesador, solo hay que configurarlo para cristal externo) y el diagrama con PCB esta en Diptrace, y lo pueden tener aqui. Si quieren tener una pcb, tengo el proyecto en oshpark.
Y aqui unas fotos de como queda en pcb..
****Actualizacion****
Encontre un «bug en la pcb, no es grave, se puede reparar casi instantaneamente, pero bueno, un error al final del dia. sucede que para algunos chips MAX756 no se puede dejar flotada la señal de SHT (apagado), asi que hay que «puentearla» al la entrada de voltaje de la bateria (del pin 1 al pin 5 del DIP8), les dejo la foto de la «reparacion».
***** Actualizacion 22/05/2015 ******
Los archivos con el «bug» han sido corregidos, junto con los links del proyecto con los archivos buenos y el diseño en oshpark 🙂
Tambien les dejo un video del circuito funcionando…
Espero que les sea de utilidad. Sin mas por el momento…
Argos.
Vaya! esto sin duda ayuda mucho cuando se diseñan circuitos con inductancias, hace tiempo tuve un proyecto para el cual tenia que diseñar un filtro LC y esto me hubiera venido de lujo. ¿Que software usaste para realizar el esquematico final?
Me gustaMe gusta
Para los diagramas uso http://www.diptrace.com/ ya que no pesa mucho y usarlo es muy muy fácil, además deja imprimir en negativo y eso me ayuda con el modo fotográfico para hacer los pcb
Me gustaMe gusta
Disculpa., Como se llama el programa has compilado al codigo…?
Me gustaMe gusta
Para los AVR’s me he encariñado mucho con el codevision, pero uso tambien gcc por compatibilidad, de hecho no hay mucha diferencia entre ellos, si acaso el wizard 😛
Saludos.
Me gustaMe gusta
buenas noches estoy haciendo el mismo trabajo pero implementado con un PIC,lo que deseaba saber es donde has obtenido la respuesta en frecuencia del lm311.Comentas que la frecuencia maxima es de 2.5MHZ.necesito saber esta informacion.Agradeceria su respuesta.Muchas gracias y buen trabajo.
Me gustaMe gusta
Hola. La hoja de especificaciones ( http://physics.gac.edu/~huber/classes/phy270/SpecSheets/LM311_National.pdf ) tiene el dato de «tiempo de respuesta» de 200ns (página 4), para una oscilación completa será de 400ns, entonces la frecuencia máxima será de 2.5MHz. Y bueno, también en la misma hoja de especificaciones vienen unas gráficas (página 7) donde muestra que puede tener tiempos de respuesta de hasta 400ns y bajar la frecuencia de operación a 1.25MHz.
Saludos.
Me gustaMe gusta