Контроллер вакуумно-люминесцентного дисплея (VFD) на Arduino — DIY набор
Компоненты и материалы
| Arduino UNO (или любая 8-битная Arduino) | ×1 |
| VFD-дисплей | ×1 |
| CD4094 (DIP, сдвиговый регистр) | ×2 |
| CD4017 (DIP, десятичный счётчик) | ×2 |
| BC557 (PNP-транзистор, или 2N3906, 2SA733 и др.) | ×17 |
| BC547 (NPN-транзистор, или 2N3904, 2SC945 и др.) | ×2 |
| PC817 (оптопара) | ×1 |
| 1N4007 (высоковольтный диод) | ×4 |
| Электролитические конденсаторы (значения по схеме) | ×4 |
| Конденсатор 470 нФ | ×1 |
| Монтажная плата (perfboard) | ×1 |
| Резисторы 1/4 Вт (значения по схеме) | ×24 |
| Перемычки Dupont | ×1 |
| Провода (тонкие, для обратной стороны платы и подключения дисплея) | ×1 |
Инструменты
- Паяльник
- Припой (0.5 мм, качественный)
- Обкусыватели
О проекте
Зачем это нужно?
VFD-дисплеи сегодня не в тренде, но они крутые: стеклянные колбы, накатанные нити накала, по сути — вакуумные лампы. Они дают яркий, иногда цветной свет, требующий тёмного фильтра. Обычно для управления нужен специализированный драйвер (I2C/SPI). Если у вас есть «голый» дисплей без драйвера, подключить его непросто — драйверы обычно в SMD. Эта схема даёт универсальный интерфейс для Arduino, способный управлять практически любым VFD, включая винтажные «ламповые» индикаторы. Матричные дисплеи с тысячами сегментов — не лучшая идея, хотя схему можно расширить.
Плюсы и минусы
Плюсы:
- Почти нулевая стоимость (детали легко найти)
- Работа с высоким напряжением на анодах (до сотен вольт)
- Независимые напряжения сеток и анодов
- Только 3 цифровых линии данных
- Расширяемая архитектура
- Готовый код для любой 8-битной Arduino
Минусы:
- Требует несколько источников питания (типично для VFD)
- Нет функции диммирования (кроме изменения напряжения)
- Занимает SPI и Timer1
- Нельзя «зависнуть» микроконтроллер — сканирование остановится на одной сетке (риск сгорания)
- Требует сборки, это не просто пара резисторов и LED
Принцип работы
VFD работает в мультиплексном режиме (матрица X×Y). Нагревается катод (нить накала), на сетку (X) и анод (Y) подаётся положительное напряжение — загорается один сегмент. Для отображения изображения сканируют сетки последовательно, устанавливая конфигурацию анодов для каждой. Достаточная скорость создаёт эффект одновременного свечения (POV — Persistence Of Vision).
Схема использует два CD4094 (управление анодами, хранят состояние выходов) и два CD4017 (последовательное переключение сеток). После загрузки конфигурации в CD4094 сигнал строба защёлкивает данные и тактирует CD4017 — автоматическая секвенция.
Ключевые транзисторы BC557 поднимают напряжение на анодах выше 5 В Arduino. Сетки управляются CD4017 напрямую. Оптопара PC817 позволяет запитать CD4017 от напряжения выше 5 В и гальванически разделить цепи — это сильно упрощает схему.
Arduino orchestreрует процесс: хранит конфигурацию сегментов и по прерыванию таймера (~1000 раз/сек) загружает CD4094. Для 10 сеток частота обновления ~100 Гц. Данные хранятся в массиве segments[] — можно менять в любом месте кода, прерывание само выведет изменения.
Источники питания
- Сетки (CD4017): 5–18 В DC, ≥50 мА, стабилизация не обязательна. Обычно 12 В достаточно.
- Аноды (BC557): 0–50 В DC (макс. для BC557), обычно 20–30 В DC, ≥50 мА.
- Цифровая логика: 5 В (или 3.3 В для 3.3-вольтовых MCU), ~100 мА. Если CD4094 «тормозят» — снизьте тактирование SPI в коде.
- Нить накала: ≥5 В, 200–300 мА. Нельзя использовать общий источник с Arduino! Обычно 3 В, 150 мА. Добавлен диодный мост и конденсатор на случай AC-трансформатора.
Советы и примечания
- Перед пайкой определите назначение выводов дисплея: нить накала (боковые контакты) — 2×АА батареи; сетки и аноды — 2×Крона (18 В). Найдите «анод 0» — обычно первый сегмент первой цифры. Порядок сеток часто совпадает с порядком выводов.
- Ток накала повышайте плавно, в темноте. Когда нить слегка закраснеет — чуть уменьшите. Идеально — мощностной потенциометр (иногда встречаются в старых ТВ).
- Напряжение на сетках/анодах поднимайте осторожно — люминофоры сгорают безвозвратно. При зависании кода питание будет постоянно на одной сетке.
- Подбирайте компромисс сетки/аноды: сетки потребляют ток, лучше не завышать, фокус на анодах.
- Идеально — один трансформатор на всё. Импульсные БП, особенно заземлённые, могут дать сбой — для экспериментов лучше классические трансформаторные.
- Схему можно расширять доп. CD4094/CD4017. Если нужно ≤8 анодов или ≤10 сеток — второй чип можно опустить, но для универсальности лучше собрать полностью.
- Нет резисторов на базах BC557 — максимальная скорость, но CD4094 отдают ток (до ~4 мА/ножка при 5 В). Чипы не сгорят, но проверьте потребление.
- Старые тусклые дисплеи иногда «оживляют» импульсами тока на нить (доведение до видимого свечения 5 раз по 2 сек). Рискованно — нить может обрушиться.
Код
Arduino-скетч с рабочим прерыванием
/* Versatile VFD Display Hardware Interface Arduino Program
Copyright (C) 2019 Genny A. Carogna
GNU GPL v3 */
// Используются Timer1 и SPI «под капотом» — они заняты.
// Дисплей сканируется непрерывно (100 Гц), нагрузка на CPU ~3%.
// Работает на любой 8-битной Arduino, 3.3 В — возможно, снизьте SCK.
#define ledLed 13
#define strobePin 4
#define strobeHold 10 // мкс, удержание строба для оптопары
// Пример конфигураций для разных дисплеев (оставьте нужную)
#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
// Массив сегментов: segments[grid] — биты сегментов (LSB = сегмент 0)
// Автоматически выбирает тип: uint8_t / uint16_t / uint32_t
#if anodeAmount > 16
volatile uint32_t segments[gridAmount] = {0};
#elif anodeAmount > 8
volatile uint16_t segments[gridAmount] = {0};
#else
volatile uint8_t segments[gridAmount] = {0};
#endif
void setup() {
// Быстрая настройка SPI-пинов и строба
*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);
*portModeRegister(digitalPinToPort(ledLed)) |= digitalPinToBitMask(ledLed);
*portOutputRegister(digitalPinToPort(ledLed)) &= ~digitalPinToBitMask(ledLed);
delay(800); // ждём сброс CD4017 при включении питания
cli(); // запрет прерываний для настройки
// Timer1: прерывание grids×100 раз в сек = 100 Гц обновление
TCCR1A = 0; TCCR1B = 0; TCNT1 = 0;
OCR1A = 160000 / gridAmount;
TCCR1B |= (1 << WGM12) | (1 << CS10);
TIMSK1 |= (1 << OCIE1A);
// SPI: мастер, 1 МГц (SPR0). Для 0.5 МГц раскомментируйте SPSR строку.
SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR0);
// SPSR = (1 << SPI2X); // двойная скорость (если раскомментировать и убрать SPR0)
sei(); // прерывания разрешены
// Дополнительный setup() код — сюда
}
void loop() {
show(); // демо-режим, можно удалить
}
// Прерывание Timer1 — каждая смена сетки
ISR(TIMER1_COMPA_vect) {
static uint8_t turn = 1; // текущая сетка (1-based в оригинале)
// Передача битов анодов (младшие байты первыми), инвертированных (из-за PNP)
#if anodeAmount > 24
SPDR = ~uint8_t(segments[turn] >> 24); while(!(SPSR & (1< 16
SPDR = ~uint8_t(segments[turn] >> 16); while(!(SPSR & (1< 8
SPDR = ~uint8_t(segments[turn] >> 8); while(!(SPSR & (1<2) pos++;
uint16_t mask = 0xFF80;
uint8_t nums[] = {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] |= nums[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; break;
}
}
void marantzPrintNum(uint8_t val, uint8_t pos) {
if(pos>5) return; pos+=2;
uint16_t mask = 0xFF80;
uint8_t nums[] = {B00111111,B00000110,B01011011,B01001111,B01100110,B01101101,B01111101,B00100111,B01111111,B01101111,B00000000};
segments[pos] &= mask; segments[pos] |= nums[val];
}
Схема
На схеме не нарисованы все 17 транзисторов BC557 — они одинаково подключены к выходам CD4094. Перемычка на CD4017 (красная линия) сбрасывает счётчики после последней сетки: соедините её с выводом после последней используемой сетки (для 10 сеток — 11-й вывод).
Подключения Arduino выделены красным. USB питание для Arduino, но для остальных источников настоятельно рекомендуется классический трансформатор (не импульсный, заземлённый). Все источники — DC, кроме возможно филамента. Диодный мост и 1000 мкФ на случай отдельного трансформатора филамента (обычно ~3 В, 150 мА, подойдёт 5 В AC). «Балласт» — мощностной потенциометр ~100 Ом или резистор/диоды для снижения напряжения.
BC557 подтягивают аноды к анодному напряжению, 100 кОм опускают при выключении. CD4017 запитаны от напряжения сеток, доп. транзисторы не нужны. «Гетто»-сброс CD4017 (~0.1 с) — ждите перед запуском кода. Каскад CD4017 без логических элементов: NPN-транзистор + оптопара эмулируют AND — достаточно быстро.
Обратите внимание на разные земли — изучите схему внимательно.
Производственный процесс
- Интерактивная кукла «Игра в кальмара» на Arduino UNO: DIY-проект
- Профессиональное руководство по анимации битмапов на TFT-экране ILI9341 2.4" с Visuino
- Веб-управляемая DMX-система освещения: Arduino Mega как мастер-контроллер
- Создание классической игры Pong на Arduino UNO с OLED-дисплеем: пошаговый урок
- DIY USB-геймпад на Arduino: собственный высокопроизводительный контроллер
- Unopad: Бесшовный Arduino MIDI-контроллер для Ableton Live
- Монитор температуры и реальные часы на Arduino Due с TFT-дисплеем 3.2"
- Интерактивный HMI-проект на Nextion с Arduino Mega и датчиками
- Сборка вольтметра на Arduino с дисплеем Nokia 5110 — Пошаговое руководство
- Вывод данных BME280 (температура, влажность, давление) на сенсорный экран Nextion