Categorías
Proyectos de Electrónica

Luz Nocturna VFD con Attiny84

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:

Samples of VFD 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 1Ir de segmento en segmento, rebotar.
Modo 2Desvanecimiento de un segmento, se mueve hacia arriba y luego se restablece.
Modo 3Iluminación de segmentos completa, estática.
Modo 4Iluminació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:

MT3608 to supply VFDs for a cool night light.

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:

Schematics of VFD Night Light with Attiny84

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:

Self oscillating AC Square Wave
Copiado desde el datasheet del LM9022.

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.

MCU to VFD Interface

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

VFD Night Light 1 of 3
VFD Night Light 2 of 3
VFD Night Light 3 of 3

Anexo 2: Lista de Materiales

ReferenciaNúmero Unidades
IV-25 VFD1
Attiny84 MCU1
LM48711
2N3904 NPN7
2N3906 PNP7
Battery 186501
ON-OFF Switch1
SP4T Switch Rotatorio1
MT3608 Modulo2
TP4056 Modulo Carga1
Resistencias
47K14
10K10
4K77
2K21
1001
Condensadores
10 uF Electrolitico1
1 uF Electrolitico1
0.01 uF Ceramico1

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: