Manufactura industrial
Internet industrial de las cosas | Materiales industriales | Mantenimiento y reparación de equipos | Programación industrial |
home  MfgRobots >> Manufactura industrial >  >> Manufacturing Technology >> Proceso de manufactura

Kit controlador para display fluorescente al vacío (VFD) basado en Arduino

Componentes y materiales

Componente Cantidad Notas
Arduino UNO 1 o cualquier Arduino de 8 bits
Display VFD 1 nuestro compañero
CD4094 2 Circuito integrado DIP
CD4017 2 Circuito integrado DIP
BC557 17 o equivalente (2N3906, 2SA733, etc.) o PNP de mayor voltaje
BC547 2 o equivalente (2N3904, 2SC945, etc.)
PC817 1 Optoacoplador común en fuentes conmutadas
1N4007 - Diodo alta tensión/corriente 4
Condensadores electrolíticos 4 Ver esquemático para valores y voltajes
Condensador 470nF 1 Cualquier tipo sirve
Placa perforada (perfboard) 1 aka: protoboard, paper board
Resistencias 1/4W 24 Ver esquemático para valores
Jumpers Dupont 1 o tu conexión preferida
Cable 1 Cables finos para circuito y conexión al display

Herramientas necesarias

Sobre este proyecto

¿Para qué sirve?

Los displays VFD ya no son tendencia por razones obvias: son de vidrio ("¡guay!"), tienen un filamento incandescente ("¿¿en serio??"), son básicamente tubos de vacío ("¡interesante!"), producen una luz tan brillante, a veces coloreada, que necesita un plástico oscuro encima ("¡guay otra vez!").

Normalmente necesitas un chip dedicado para controlarlos; la mayoría de módulos/electrodomésticos traen ese chip que se controla independientemente vía I2C o SPI (mucho mejor en facilidad). Si compras o tienes uno de esos displays y careces de ese chip, no es tan fácil "conectar y listo". Lo ideal sería comprar ese chip (suele venir en formato SMD). Este circuito ofrece una interfaz bastante decente para Arduino y puede controlar probablemente cualquier VFD, incluidos los voluminosos "tubos" vintage, pero displays matriciales con muchos segmentos no son buena idea; puedes expandir el circuito pero MILES... mmm, quizá no.

Pros y contras

Pros

Contras

Principio de funcionamiento

Un VFD suele funcionar de forma multiplexada, como una matriz 2D con ejes X e Y. Necesitas calentar el filamento (el cátodo, ves esos hilos finos delante), conectar tierra a ese filamento, un voltaje positivo a un grid (grid de control, un punto del eje X) y otro voltaje positivo en un pin de segmento (el ánodo, un punto del eje Y); en ese punto se enciende un segmento (solo uno). Para encender cualquier segmento y combinación, y teniendo "pocos" cables, el multiplexado selecciona un grid cada vez y al mismo tiempo configura los ánodos para encender los segmentos correspondientes bajo ese grid; un momento después, selecciona otro grid y configura los ánodos para los segmentos bajo ese segundo grid. Acelerando este barrido continuo resulta un movimiento tan rápido que a nuestros ojos no parece que seleccione un grid cada vez, sino que parece controlado de golpe: esto es la llamada POV (Persistencia de la Visión).

Este circuito usa dos tipos de integrados de la misma familia: dos CD4094 y dos CD4017. Los 4094 controlan los ánodos y los 4017 los grids. El 4094 puede almacenar una configuración alto/bajo en sus salidas y es bueno para el lado de los ánodos; los 4017 son los chips clásicos con 10 salidas secuenciales, perfectos para los grids. Una vez cargados los 4094 con la configuración momentánea de ánodos, la señal "ok" (strobe) aplica esta configuración y al mismo tiempo avanza los 4017 un paso, permitiendo una secuenciación automática.

La parte de potencia son básicamente transistores BC557 (o equivalentes) que permiten un rango de voltaje más amplio en los ánodos, porque estos displays requieren voltaje superior a los 5V del Arduino. Los grids son controlados directamente por los 4017; un optoacoplador PC817 permite un voltaje mayor a 5V alrededor de los 4017 y también un nivel de voltaje diferente al de los CD4094, simplificando MUCHO el conjunto.

El Arduino debe proporcionar toda la orquestación: almacenar todas las configuraciones de segmentos y cargar el circuito con la configuración de ánodos en cada cambio de grid. Esto requiere un código inteligente para hacerlo más allá de la acción del usuario. El código que he hecho configura una interrupción basada en timer que recarga los chips 4094 en cada paso, realmente unas 1000 veces por segundo, así para 10 grids da una tasa de refresco de 100Hz, que está bien. Hay un array de datos que almacena la configuración de segmentos y puede modificarse en el código, sin procedimientos particulares ni acciones subsiguientes; la rutina de interrupción subirá los datos por su cuenta.

Fuentes de alimentación

El voltaje de los grids en los chips 4017 puede ser de 5Vdc a 18Vdc y al menos 50mA de corriente; no necesita estar regulado. Normalmente 12V bastan para cualquier situación; aumentarlo no parece incrementar mucho el brillo (si es un tubo de vacío, el grid no requiere voltajes enormes).

El voltaje de los ánodos puede ser desde literalmente 0V hasta lo que aguanten tus transistores (50Vdc para BC557); normalmente si el display es perfecto, 20-30Vdc harán el trabajo perfectamente, no regulado está bien. Para configuración normal, 50mA de alimentación son más que suficientes.

La alimentación digital puede ser 5Vdc o también 3.3Vdc en caso de esos Arduinos o MCUs (no probado aún); requiere unos 100mA (esperemos menos); en caso de que los CD4094 se vuelvan lentos, puedes reducir el reloj SPI en código y/o usar la salida "Q'S" del primer 4094 para una comunicación más consistente.

La alimentación del filamento debe proporcionar al menos 5V 200-300mA; si ya tienes una fuente DC puedes evitar el rectificador y el condensador de 1000uF, pero NO puedes usar la misma alimentación digital para/desde el Arduino. El filamento real en caso de un display de electrodoméstico no muy grande funciona a unos 3V y puede consumir 150mA.

Kit controlador para display fluorescente al vacío (VFD) basado en Arduino
Kit controlador para display fluorescente al vacío (VFD) basado en Arduino
Kit controlador para display fluorescente al vacío (VFD) basado en Arduino
Kit controlador para display fluorescente al vacío (VFD) basado en Arduino
Kit controlador para display fluorescente al vacío (VFD) basado en Arduino

Consejos y notas

Código

Código Arduino con rutina funcional (Arduino)

/* Versatile VFD Display Hardware Interface Arduino Program Copyright (C) 2019 Genny A. Carogna This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>. */ /* este código usa recursos del Arduino de forma "entre bastidores", el timer1 y el módulo SPI son ambos usados y ocupados *, así que puedes tener grandes problemas usando SPI, pines SPI, y algunas funcionalidades basadas en timer1... el circuito propuesto * no tiene memoria a bordo, así que la configuración de segmentos debe ser "barrida" continuamente, cada grid, 100 veces por segundo *, desde el array de segmentos del Arduino, esto se traduce también en el llamado "overhead" de trabajo de CPU, que, para que lo sepas, * no es más que uso regular de un micro al final, puede rondar el 3% de trabajo de CPU en términos de tiempo ocupado, también puedes * intentar usar las herramientas SPI regulares de Arduino pero necesita un análisis en profundidad de la salida y procedimiento * * este código funciona con cualquier Arduino de 8 bits, también 3.3V debería ir bien, quizá reduzca la frecuencia SCK, considerando que los CD4094 están * alimentados junto a él y pueden "subvoltaje" (sí, exactamente los principios de overclock para freír tu querido PC) */ #define ledLed 13 // es el pin del led que enciende un led para ledte saber que un led encendido significa algo relacionado con leds (mumbojumbo de científico por supuesto) #define strobePin 4 // pin Arduino para dedicar a la línea "strobe" #define strobeHold 10 // microsegundos // tiempo de retención para conmutar el optoacoplador... no megahercios-rápido pero aceptable // datos para mis displays (un videocasete, un lector CD audiófilo y un estéreo compacto)... no importa, bórralo, y solo define "gridAmount" y "anodeAmount" #define JVC #define mitsubishiGrids 10 #define mitsubishiAnodes 9 #define marantzGrids 9 #define marantzAnodes 14 #define JVCGrids 11 #define JVCAnodes 19 #if defined mitsubishi #define gridAmount mitsubishiGrids #define anodeAmount mitsubishiAnodes #elif defined marantz #define gridAmount marantzGrids #define anodeAmount marantzAnodes #elif defined JVC #define gridAmount JVCGrids #define anodeAmount JVCAnodes #endif // este array, segments[x], almacena los bits de segmento // segments[0] significa grid cero, y el bit menos significativo es segmento cero en ese grid // puedes acceder y modificar este array como quieras, desde donde sea, sin hacer nada más, el efecto es inmediatamente visible en // el display, y permanece mientras no cambies los bits; para displays con más de 8 segmentos por grid, necesitas un // contenedor de 16 o 32 bits por grid, esto se gestiona automáticamente desde los #define(s) anteriores #if anodeAmount > 16 volatile uint32_t segments[gridAmount] = {0}; // más de 16 segmentos por grid (32 bit necesarios) #elif anodeAmount > 8 volatile uint16_t segments[gridAmount] = {0}; // más de 8 segmentos por grid (16 bit, transferencia doble) #else volatile uint8_t segments[gridAmount] = {0}; // 8 o menos segmentos por grid (8 bit) #endif void setup(){ // pone pines SPI y algunos funcionales como salida de forma rápida/directa *portModeRegister(digitalPinToPort(PIN_SPI_SS)) |= digitalPinToBitMask(PIN_SPI_SS); *portModeRegister(digitalPinToPort(PIN_SPI_MOSI)) |= digitalPinToBitMask(PIN_SPI_MOSI); *portModeRegister(digitalPinToPort(PIN_SPI_SCK)) |= digitalPinToBitMask(PIN_SPI_SCK); *portModeRegister(digitalPinToPort(strobePin)) |= digitalPinToBitMask(strobePin); *portOutputRegister(digitalPinToPort(strobePin)) &= ~digitalPinToBitMask(strobePin); // ponerlo LOW *portModeRegister(digitalPinToPort(ledLed)) |= digitalPinToBitMask(ledLed); *portOutputRegister(digitalPinToPort(ledLed)) &= ~digitalPinToBitMask(ledLed); // ponerlo LOW delay(800); // delay para esperar reset CD4017 (necesitas ejecutar código DESPUÉS de alimentar los 4017, esto lo hace automático si alimentas todo a la vez) cli(); // deshabilita interrupciones para dejar ajustar cosas sin que gatos y perros escapen por todos lados // configuración timer1, hace una interrupción "grids veces 100" por segundo... da 100Hz refresco total que está bien TCCR1A = 0; TCCR1B = 0; TCNT1 = 0; OCR1A = 160000 / gridAmount; TCCR1B |= (1 << WGM12); TCCR1B |= (1 << CS10); TIMSK1 |= (1 << OCIE1A); // configuración SPI, no podemos usar herramientas SPI Arduino porque dependen de interrupciones Y * necesitamos que la comunicación ocurra DENTRO de una interrupción.. // cambia SPR0 por SPR1 y descomenta última línea para tener mitad velocidad reloj SPI SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR0); // 1MHz velocidad SCK stock // SPSR = (1 << SPI2X); // descomenta esto y modifica arriba para mitad velocidad reloj sei(); // interrupciones activadas de nuevo // mejor poner tu código setup() adicional desde aquí } // puedes hacer lo que quieras en loop(), delays, polling, pero deshabilitar interrupciones o parar el micro completamente * congelará el display en un grid, y si el voltaje está a tope ¡puedes quemar segmentos (!!) void loop() { show(); // especie de salvapantallas, puedes borrar } // rutina de servicio de interrupción, ocurre en cada cambio de grid y 100 veces por segundo ISR(TIMER1_COMPA_vect){ /* ATENCIÓN ATENCIÓN: no sé por qué necesito empezar "turn" desde 1 para funcionalidad correcta (alimento Arduino después y puede voltear un grid), en caso siga fallando grid correcto al inicio, varía esto ATENCIÓN */ static uint8_t turn = 1; // variable indestructible para recordar en qué grid estábamos la próxima interrupción #if anodeAmount > 24 SPDR = ~uint8_t(segments[turn] >> 24); // necesitamos bits negados en CD4094 (por disposición transistores) while (!(SPSR & (1 << SPIF))) ; // esperamos complete transferencia #endif #if anodeAmount > 16 SPDR = ~uint8_t(segments[turn] >> 16); // necesitamos bits negados en CD4094 (por disposición transistores) while (!(SPSR & (1 << SPIF))) ; // esperamos complete transferencia #endif #if anodeAmount > 8 SPDR = ~uint8_t(segments[turn] >> 8); // necesitamos bits negados en CD4094 (por disposición transistores) while (!(SPSR & (1 << SPIF))) ; // esperamos complete transferencia #endif SPDR = ~uint8_t(segments[turn]); // necesitamos bits negados en CD4094 (por disposición transistores) while (!(SPSR & (1 << SPIF))) ; // esperamos complete transferencia... yyyYYYAAAAWWWWNNNnnn........... // strobe (por fin!!) esto también conmuta el grid en los CD4017s *portOutputRegister(digitalPinToPort(strobePin)) |= digitalPinToBitMask(strobePin); // conducción pin rápida ON delayMicroseconds(strobeHold); *portOutputRegister(digitalPinToPort(strobePin)) &= ~digitalPinToBitMask(strobePin); // conducción pin rápida OFF // recordatorio giro grid turn ++; if (turn == gridAmount) turn = 0; } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////DESDE AQUÍ EL SKETCH SE REFIERE A MIS DISPLAYS Y JUEGOS VISUALES, PUEDES BORRAR DESDE AQUÍ///////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // esto es solo una demo, bórralo como quieras void show() { // volteo números #ifdef mitsubishi for (uint8_t i = 0; i < 9; i ++) for (uint8_t j = 0; j < 11; j ++) { delay(200); mitsubishiPrintNum(j, i); } for (uint8_t i = 0; i < 9; i ++) for (uint8_t j = 0; j < 11; j ++) { delay(20); mitsubishiPrintNum(j, i); } #elif defined marantz for (uint8_t i = 0; i < 6; i ++) for (uint8_t j = 0; j < 11; j ++) { delay(200); marantzPrintNum(j, i); } for (uint8_t i = 0; i < 6; i ++) for (uint8_t j = 0; j < 11; j ++) { delay(20); marantzPrintNum(j, i); } #elif defined JVC /* for (uint8_t i = 0; i < 9; i ++) for (uint8_t j = 0; j < 11; j ++) { delay(200); JVCPrintNum(j, i); } for (uint8_t i = 0; i < 9; i ++) for (uint8_t j = 0; j < 11; j ++) { delay(20); JVCPrintNum(j, i); }*/ #endif delay(500); // volteo segmentos for (uint8_t i = 0; i < gridAmount; i ++) for (uint8_t j = 0; j < anodeAmount + 1; j ++) { delay(100); segments[i] = (uint32_t(1) << j); } delay(500); // todo el display parpadeando for (uint8_t i = 0; i < 5; i ++) { delay(200); for (uint8_t j = 0; j < gridAmount; j ++) { segments[j] = 0xFFFFFFFF; } delay(200); for (uint8_t j = 0; j < gridAmount; j ++) { segments[j] = 0; } } delay(500); } // visualización fácil de número 7 segmentos void mitsubishiPrintNum(uint8_t val, uint8_t pos) { if (pos > 2) pos ++; uint16_t mask = 0xFF80; uint8_t numbers[] = {B00111111, B00000110, B01011011, B01001111, B01100110, B01101101, B01111101, B00100111, B01111111, B01101111, B00000000}; switch (pos) { case 0: case 1: case 4: case 5: case 6: case 7: case 8: segments[pos] &= mask; segments[pos] |= numbers[val]; break; case 2: if (val == 1) segments[1] |= (1 << 8); else segments[1] &= ~(uint16_t(1) << 8); break; case 9: segments[9] &= 0xFFF0; if (val == 1) segments[9] |= 3; else if (val == 2) segments[9] |= B1101; } } // visualización fácil de número 7 segmentos void marantzPrintNum(uint8_t val, uint8_t pos) { if (pos > 5) return; pos ++; pos ++; uint16_t mask = 0xFF80; // máscara para borrar dígito uint8_t numbers[] = {B00111111, B00000110, B01011011, B01001111, B01100110, B01101101, B01111101, B00100111, B01111111, B01101111, B00000000}; segments[pos] &= mask; // borrar dígito segments[pos] |= numbers[val]; // poner dígito } // visualización fácil de número 7 segmentos void JVCPrintNum(uint8_t val, uint8_t pos) { // por venir (realmente no te importa) } // 

Esquemáticos

Evité dibujar TODOS los transistores BC557 porque simplemente están ahí conectados en todas las salidas del CD4094, todos iguales.

Hay un selector de jumper (corriendo en la línea roja) que debes configurar en los chips 4017; resetea los dos 4017 al completar el barrido de grids; debes conectar (o soldar) el jumper volante en el pin de salida DESPUÉS del último grid; así si tu display tiene 10 grids el jumper va en la 11ª salida.

Las conexiones del Arduino están marcadas en rojo; puedes usar la alimentación USB para él pero se aconseja encarecidamente usar un transformador clásico para el resto de alimentaciones si ya tienes una fuente con toma de tierra como tu PC. Estas alimentaciones deben ser todas DC excepto quizá la del filamento; añadí diodos porque es probable que necesites un transformador separado con secundario de bajo voltaje. La alimentación del filamento suele rondar 3V 150mA; un transformador 5V AC bastará. La "balasto" posiblemente sea un potenciómetro de potencia bobinado de unos 100 ohmios, o una resistencia fija, o también unos diodos 1N4007 para reducir el voltaje.

Los transistores BC557 elevan los ánodos al voltaje anódico y las resistencias de 100kohm dejarán caer el voltaje de conducción cuando el segmento está apagado, mientras los CD4094 permanecen a 5V normalmente.

Los CD4017 se alimentarán con voltaje de grid y no requieren transistores adicionales. Hay un circuito de reset "ghetto" para los 4017 que dura como una décima de segundo; tienes que esperar a que se asiente antes de ejecutar el código. El esquemático "original" para cascada de CD4017 requería otros chips de compuertas lógicas; usé en su lugar un transistor NPN y el propio optoacoplador para replicar una compuerta AND; es lo suficientemente rápido al cerrar así que es perfecto para la tarea; al abrir es un poco más lento pero no nos importa, especialmente porque las entradas de clock en los 4017 son Schmitt triggered y la velocidad requerida no es "aterradora" ahí.

Hay varias tierras para los chips y componentes como ves; échale un buen vistazo.

Kit controlador para display fluorescente al vacío (VFD) basado en Arduino

Proceso de manufactura

  1. Muñeca interactiva "El Juego del Calamar" con Arduino UNO: Proyecto DIY
  2. Guía Profesional de Animación Bitmap en Pantalla Táctil ILI9341 2.4″ con Shield para Arduino
  3. Sistema de Iluminación DMX Controlado por Web – Controlador Maestro Arduino
  4. Construya el clásico juego Pong en Arduino UNO con pantalla OLED: Tutorial paso a paso
  5. Mando USB para juegos DIY con Arduino – Construye tu propio gamepad de alto rendimiento
  6. Unopad: Controlador MIDI Arduino para Ableton Live sin complicaciones
  7. Monitor de Temperatura y Reloj en Tiempo Real con Arduino Due y Pantalla TFT 3.2"
  8. Proyecto HMI Interactivo con Nextion, Arduino Mega y Múltiples Sensores
  9. Construye un voltímetro DIY con Arduino y pantalla Nokia 5110 – Guía paso a paso
  10. Visualiza Temperatura, Humedad y Presión BME280 en Pantalla Táctil Nextion
  11. Medición de Distancia en Tiempo Real con Sonar Arduino y Visualización en Processing