Proyecto Casero: Luz NocturnaVFD. Desarrollado y escrito por Frasier Chew.
Los visualizadores fluorescentes de vacío (VFD) existen desde hace más de 6 décadas. Aunque su apogeo ha pasado en favor de otras tecnologías de visualización más recientes como la LCD, se siguen utilizando hoy en día por su robustez. Los VFD pueden funcionar en una amplia gama de condiciones de temperatura y ofrecen ángulos de visión excepcionales.
Una explicación sencilla de cómo funcionan los VFD es que un filamento catódico suministra los electrones que son atraídos por los ánodos recubiertos de fósforo. Cuando la capa de fósforo recibe el impacto de los electrones, se vuelve fluorescente y emite luz visible.
Este artículo está organizado como sigue. En primer lugar, la sección 1 presenta y muestra el proyecto. En segundo lugar, la sección 2 explica cómo está diseñado y funciona el dispositivo. Por último, el anexo ofrece una galería de imágenes, una lista de materiales y el código del proyecto.
1. Descripción del Proyecto
1.1 VFD IV-25
En este artículo, le mostraré cómo hice una luz de noche muy chula usando un viejo VFD soviético IV-25:
El IV-25 es un tubo de visualización de gráfico de barras de 7 segmentos. Es un tubo muy sencillo porque no tiene rejillas de pantalla y tiene clavijas de salida individuales para cada ánodo, lo que hace innecesaria la multiplexación.
1.2 Luz Nocturna VFD
La luz nocturna del IV-25 es lo suficientemente brillante como para iluminar una habitación oscura con un suave resplandor verde. Usando el microcontrolador Attiny84, he codificado 4 secuencias de funcionamiento diferentes para el VFD que se controlan mediante un interruptor selector giratorio. Todo el circuito está alimentado por una batería de litio 18650 que se puede recargar con un módulo TP4056.
Los cuatro modos de funcionamiento son:
Modo 1 | Ir de segmento en segmento, rebotar. |
Modo 2 | Desvanecimiento de un segmento, se mueve hacia arriba y luego se restablece. |
Modo 3 | Iluminación de segmentos completa, estática. |
Modo 4 | Iluminación de todo el segmento, desvanecimiento. |
1.2.1 Modo 1
1.2.2 Modo 2
1.2.3 Modo 3
1.2.4 Modo 4
2. Construcción y Operación de Luz VFD
Esta sección muestra cómo se diseñó y construyó la luz nocturna VFD. Incluye las siguientes subsecciones:
- Alimentación.
- Esquemático del PCB y explicación de las diferentes etapas electrónicas.
- Software.
2.1 Alimentación
2.1.1 Requisitos
El microcontrolador Attiny84 requiere 5Vdc.
Aparte de eso, para utilizar este VFD, se necesitan 2 tensiones diferentes:
- 25 Vdc para los anodos.
- 2.4 Vac para el filamento del cátodo. El uso de corriente continua con el filamento daría lugar a un gradiente de concentración no deseado a través del tubo VFD que puede causar una iluminación desigual de los segmentos del ánodo. (La sección 2.2.1 explica la generación de este voltaje)
2.1.2 Convertidor Elevador de Tensión
Dos módulos elevadores MT3608 se usaron para generar los 25Vdc de los ánodos y los 5Vdc de alimentación del microcontrolador Attiny84:
Estos módulos elevan la tensión de 3,7 Vdc de la batería 18650 y proporcionan una salida de tensión constante que puede ajustarse mediante el potenciómetro.
Mas información sobre el funcionamiento del módulo MT3608 se puede encontrar en este enlace.
2.2 Esquemáticos
Los esquemas del proyecto se pueden descargar desde este enlace. Alternativamente, pueden obtenerse descargando la siguiente imagen:
2.2.1 Alimentación del filamento del VFD
Para la alimentación del filamento, utilicé el integrado amplificador de audio con referencia LM4871. Este es el equivalente moderno del ahora obsoleto LM9022, un circuito integrado controlador de filamentos VFD, pero es esencialmente el mismo chip. Seguí el circuito de aplicación de auto-oscilación para generar pseudo AC usando una onda cuadrada:
Se utilizó una resistencia de 100 ohmios (R33) para limitar la corriente al filamento de forma que brille lo justo y necesario. Es importante no sobrecargar el filamento, ya que reducirá significativamente la vida útil del tubo, mientras que sólo aumenta marginalmente el brillo.
2.2.2 Interfaz entre el VFD y el Microcontrolador
Utilicé el diseño de circuito de Kevin Rye para interconectar el Attiny84 al VFD. Más información sobre su diseño se puede encontrar en este enlace.
Esta interfaz se basa en transistores NPN y PNP, concretamente las referencias 2N3904 y 2N3906 respectivamente.
2.2.3 Selección de Modo
Debido a restricciones en los puertos de entrada del Attiny84, sólo pude codificar un máximo de 4 secuencias de funcionamiento diferentes para el VFD. Por eso decidí utilizar un interruptor giratorio unipolar de 4 contactos (SP4T).
Notar que si se decide utilizar un interruptor giratorio con más polos, los polos adicionales pueden ignorarse simplemente no conectándolos. Así que no te preocupes si no puedes encontrar el tipo exacto de interruptor. Sólo tienes que tener en cuenta el número de posiciones.
Si se desean más secuencias, se puede utilizar un microcontrolador con más pines de E/S como el Atmega328 junto con otros tipos de interruptores.
2.3 Software
Para encender y apagar los segmentos es necesario utilizar la modulación por ancho de pulsos (PWM). Desafortunadamente, el Attiny84 no tiene suficientes pines PWM para controlar por separado cada uno de los 7 segmentos de ánodo, por lo que se requiere PWM por software.
Łukasz Podkalicki ha escrito un código que utiliza retardos de forma inteligente para atenuar por pulsos un LED. El código se puede encontrar en este enlace. Su código funciona definiendo en primer lugar un valor de retardo Máximo y Mínimo. El valor Mín se decrementa hasta que se cumple una condición. Esto activa «dir = 1» y hace que el valor Mín se incremente hasta que se cumpla otra condición que activa «dir = 0». «dir» alterna entre 1 y 0 creando un efecto de desvanecimiento de pulsos en un LED.
En el Anexo 3 puedes encontrar mi código de Atmel studios incorporando su software PWM. ¡Te animo a que juegues con él y crees tus propias secuencias de operación!
Anexo: Detalles Luz Nocturna VFD
Anexo 1: Galería
Anexo 2: Lista de Materiales
Referencia | Número Unidades |
IV-25 VFD | 1 |
Attiny84 MCU | 1 |
LM4871 | 1 |
2N3904 NPN | 7 |
2N3906 PNP | 7 |
Battery 18650 | 1 |
ON-OFF Switch | 1 |
SP4T Switch Rotatorio | 1 |
MT3608 Modulo | 2 |
TP4056 Modulo Carga | 1 |
Resistencias | |
47K | 14 |
10K | 10 |
4K7 | 7 |
2K2 | 1 |
100 | 1 |
Condensadores | |
10 uF Electrolitico | 1 |
1 uF Electrolitico | 1 |
0.01 uF Ceramico | 1 |
Annex 3: Código
/* * IV-25 VFD Night Light.c * * Created: 15/12/2022 4:33:34 PM * Author : Frasier */ #include <avr/io.h> #include <stdio.h> #define F_CPU 1000000L // 8Mhz internal osc, divided by 8 (fuse) #include <util/delay.h> //VFD 7 outputs mapped to PORTA int seg_1 = 5; int seg_2 = 4; int seg_3 = 3; int seg_4 = 6; int seg_5 = 0; int seg_6 = 1; int seg_7 = 2; int trigger = 0; // @@@@@@@@@@ fade code referenced from <blog.podkalicki.com/attiny13-led-fading-with-delay-function/> //#define DELAY_MAX 512 // value is defined within the for loop itself #define DELAY_MIN 1 /* # "Value of DELAY_MAX and DELAY_MAIN should be from range <1, 2^16>" # "Value of DELAY_MAX should be greater then DELAY_MIN" */ /* Mode 1 - PB0 Move from segment to segment, bounce back. Mode 2 - PB1 Single segment fade on off, moves upwards then resets Mode 3 - PB2 Full segment illumination Mode 4 - PA7 Full segment illumination, pulse fade */ int main(void) { // Defining Outputs // Enable first 7 ports as Output for VFD segments DDRA |= (1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4) | (1 << 5) | (1 << 6); // Enable selector switch Input for mode selection DDRA &= ~(1 << 7); DDRB &= ~(1 << 0) | (1 << 1) | (1 << 2); // Configure pull up resistors PORTA |= (1 << 7); PORTB |= (1 << 0) | (1 << 1) | (1 << 2); // @@@@@@@@@@ fade code uint16_t delay = DELAY_MIN; uint8_t dir = 0; int count = 0; // counter for break, for Mode 2 pulse while (1) { if( !(PINB & (1 << 0)) ) // if PB0 is pressed, Mode 1 { for (int i = 0; i < 7; i++) // Count upwards { if( !(PINB & (1 << 1)) ) {trigger = 1;} // if PB1 is pressed set trigger, break out of loop if (trigger == 1) { clear(); trigger = 0; break; } int a = select(i); int b; PORTA |= (1 << a); // Turn on segment if (i > 0) // turn off the previous segment once "i" is at least 1 { b = select(i-1); PORTA &= ~(1 << b); // Turn off segment } _delay_ms(1000); if (i == 6) {PORTA &= ~(1 << seg_7);} // Turn off final segment } for (int t = 5; t > 0; t--) // Count downwards { if( !(PINB & (1 << 1)) ) {trigger = 1;} // if PB1 is pressed set trigger, break out of loop if (trigger == 1) { clear(); trigger = 0; break; } int c = select(t); int d; PORTA |= (1 << c); // Turn on segment if (t < 6) { d = select(t+1); PORTA &= ~(1 << d); // Turn off segment } _delay_ms(1000); if (t == 1) {PORTA &= ~(1 << seg_2);} // Turn off final segment } } if( !(PINB & (1 << 1)) ) // if PB1 is pressed, Mode 2 { int DELAY_MAX = 800; for (int w = 0; w < 7; w++) // Count upwards { if( !(PINB & (1 << 0)) | !(PINB & (1 << 2)) ) {trigger = 1;} // if PB0 or PB2 is pressed set trigger, break out of loop if (trigger == 1) { clear(); trigger = 0; break; } int a = select(w); //int b; //PORTA |= (1 << a); // Turn on segment for (int m = 0; m < 10000; m++) { if( !(PINB & (1 << 0)) | !(PINB & (1 << 2)) ) {trigger = 1;} // if PB0 or PB2 is pressed set trigger, break out of loop if (trigger == 1) { clear(); trigger = 0; break; } PORTA &= ~(1 << a); // Turn segment off _delay_loop_2(delay); PORTA |= (1 << a); // Turn segment on _delay_loop_2(DELAY_MAX - delay); if (dir) { // fade-in if (++delay >= (DELAY_MAX - 1)) { dir = 0; count++; } } else { // fade-out if (--delay <= DELAY_MIN) { dir = 1; } } if (count == 1) { count = 0; break; } } PORTA &= ~(1 << a); // Turn off segment } } if( !(PINB & (1 << 2)) ) // if PB2 is pressed, Mode 3 { PORTA |= (1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4) | (1 << 5) | (1 << 6); // Turn on all segments trigger = 1; } if( !(PINA & (1 << 7)) ) // if PA7 is pressed, Mode 4 { int DELAY_MAX = 1024; if (trigger == 1) { trigger = 0; clear(); } //PORTA |= (1 << seg_3); // compare the brightness of this led, test case //PORTA |= (1<<seg_4); //@@@@@@@@@@@@@@@ fade code clear(); // LED off _delay_loop_2(delay); PORTA |= (1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4) | (1 << 5) | (1 << 6); // Turn all segments on _delay_loop_2(DELAY_MAX - delay); if (dir) { // fade-in if (++delay >= (DELAY_MAX - 1)) dir = 0; } else { // fade-out if (--delay <= DELAY_MIN) dir = 1;} } } } // Function for mapping the segment outputs in the correct order int select(int a) { if (a == 0){return seg_1;} if (a == 1){return seg_2;} if (a == 2){return seg_3;} if (a == 3){return seg_4;} if (a == 4){return seg_5;} if (a == 5){return seg_6;} if (a == 6){return seg_7;} } void clear() { // Function for clearing all the segments PORTA &= ~(1 << 0); PORTA &= ~(1 << 1); PORTA &= ~(1 << 2); PORTA &= ~(1 << 3); PORTA &= ~(1 << 4); PORTA &= ~(1 << 5); PORTA &= ~(1 << 6); }
Suscripción
Si te ha gustado esta contribución no dudes en suscribirte a nuestro boletín: