Arduino 驱动的真空荧光显示器(VFD)控制器套件
组件与材料
| 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 |
| 470nF 电容 | ×1 |
| 万用实验板 | ×1 |
| 1/4W 电阻 (见原理图参数) | ×24 |
| 杜邦线 | ×1 |
| 细导线 (用于电路背面连接及屏幕引脚焊接) | ×1 |
所需工具
- 电烙铁 (通用)
- 焊锡丝 (建议 0.5mm,买优质产品)
- 剪线钳
项目背景:为什么要做这个?
VFD 显示器虽不再流行,但极具魅力:玻璃封装、白炽灯丝、本质是真空管、发光极亮且常带色彩(需深色面板遮盖)。
通常驱动 VFD 需专用芯片(多为 SMD 封装),若手头只有裸屏无驱动芯片,直接驱动并不容易。本电路提供了一套低成本、易获取元件的 Arduino 驱动方案,可驱动大多数 VFD(含复古“大管”型),但不适合段数极多的矩阵显示(扩展虽可行但需大量 CPU 资源)。
优缺点分析
优点
- 成本极低
- 元件易购
- 阳极耐高压(可达百伏级)
- 栅极与阳极电压独立可调
- 仅需 3 根数字数据线
- 可扩展 (需更多 CPU 工作量)
- 代码兼容所有 8 位 Arduino
缺点
- 需要多路电源供电 (VFD 典型特征)
- 无调光功能 (除非调节驱动电压)
- 占用 Arduino SPI 与 Timer1 资源
- 若 MCU 死机,扫描冻结可能烧毁单个栅极段
- 非简单的电阻+LED,需一定焊接调试工作量
工作原理
VFD 采用多路复用驱动,类似二维矩阵(X/Y 轴)。需加热灯丝(阴极),给栅极(控制栅,X 轴)和段针(阳极,Y 轴)施加正压,对应交点发光。为减少引线,采用逐行扫描:每次选通一个栅极,同时配置该栅极下所有阳极状态,高速循环利用视觉暂留效应 (POV) 形成完整画面。
本电路使用两片 CD4094 驱动阳极(可锁存输出状态),两片 CD4017 驱动栅极(10 位顺序输出)。CD4094 加载完阳极数据后,选通信号同时触发 CD4017 步进,实现自动扫描序列。
功率部分:BC557 将阳极电压摆幅扩展至高压;栅极由 CD4017 直接驱动,PC817 光耦隔离并允许栅极电压高于 5V 且与 CD4094 电压域分离,大幅简化设计。
Arduino 负责完整编排:存储所有段配置,定时中断每秒约 1000 次重载 CD4094,10 栅极下刷新率 100Hz。段配置数组可随时修改,中断自动上传,无需额外流程。
电源供电方案
- 栅极电压 (CD4017):5~18V DC,≥50mA,通常 12V 即可,无需稳压。
- 阳极电压:0V 至三极管耐压上限 (BC557 为 50V),通常 20~30V 效果佳,无需稳压,50mA 充足。
- 数字电源:5V 或 3.3V (兼容 3.3V MCU),~100mA。若 CD4094 响应慢,可降低 SPI 时钟或用首级 4094 的 Q'S 输出改善通信。
- 灯丝电源:≥5V 200~300mA。若有现成直流源可省去整流桥和 1000uF 电容,**严禁与 Arduino 共用电源**。实际灯丝常为 3V/150mA。





实用技巧与注意事项
- 接线前先测屏:不知引脚定义时,用两节 5 号电池串联测灯丝(通常为侧面触点),两节 9V 电池串联给栅极/阳极供正压。栅极/阳极常成组分布,建议先找到“阳极 0”(通常为数字/字母区第一段),避免接反导致软件逻辑繁琐。
- 灯丝电流循序渐进:在暗处观察,灯丝微红即可,略微降低电流。功率电位器最佳,旧电视常有,现难觅。
- 栅极/阳极电压适度:荧光粉过压会永久烧毁;系统扫描驱动,若程序死机会持续通电单栅极,需注意。
- 寻找栅极/阳极电压平衡点:栅极也消耗电流,不宜过高,重点调节阳极。
- 建议用传统变压器供电:全项目最好用单一变压器多绕组;开关电源尤其是带地的易干扰,实验阶段首选传统变压器方案。
- 可扩展性:可级联更多 CD4094/CD4017;若 ≤8 阳极或 ≤10 栅极可减少芯片,但建议一次性做满配以备不时之需。
- 阳极三极管基极无电阻:换速极快、省元件,但 CD4094 输出电流略大(~4mA/脚@5V),芯片不发热、不超额定功耗,但个别批次输出过强需留意。
- 老化屏幕可能修复:整屏变暗(非个别段烧毁)可尝试灯丝电流冲击:将灯丝烧至可见黄热,每次几秒,重复 5 次。可能需 2 倍额定电压,有风险(细丝易断),主要适用于极老古董管。
核心代码
/* Versatile VFD Display Hardware Interface Arduino Program
Copyright (C) 2019 Genny A. Carogna - GPL v3 */
// 占用 Timer1 和 SPI,不可同时使用 SPI 库或依赖 Timer1 的功能
// 无板载存储,段配置需从数组持续扫描(100Hz刷新),CPU占用约3%
#define ledLed 13
#define strobePin 4
#define strobeHold 10 // 微秒,选通脉冲宽度
// 示例显示器参数(请根据实际屏幕修改 gridAmount/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
// 段数据数组,自动根据 anodeAmount 选择位宽
#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(); // 关中断配置定时器和 SPI
// Timer1: grids × 100 次/秒中断 → 100Hz 总刷新率
TCCR1A = 0; TCCR1B = 0; TCNT1 = 0;
OCR1A = 160000 / gridAmount;
TCCR1B |= (1 << WGM12) | (1 << CS10);
TIMSK1 |= (1 << OCIE1A);
// SPI 配置:主模式、1MHz(可改半速)
SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR0);
// SPSR = (1 << SPI2X); // 取消注释为半速
sei(); // 开中断
}
void loop() {
show(); // 演示效果,可删除
}
// Timer1 中断服务程序:每栅极扫描一次
ISR(TIMER1_COMPA_vect) {
static uint8_t turn = 1; // 当前栅极索引
// 分字节发送段数据(高位在前),取反(因 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<
原理图说明
原理图未画出所有 BC557(均同方式接在 CD4094 输出)。
关键点:
- CD4017 级联需跳线选择复位点:将飞线接在“最后一个栅极的下一个输出脚”(如 10 栅极接第 11 脚)。
- Arduino 连接标红:USB 供电可行,但其余电源强烈建议用传统变压器(避免接地冲突)。
- 灯丝供电通常 3V/150mA,5V 交流变压器配“镇流器”(绕线电位器/定值电阻/串联二极管)降压。
- BC557 拉高阳极至阳极电压,100kΩ 下拉使关断时电压回落,CD4094 维持 5V 逻辑。
- CD4017 直接用栅极电压供电,无需额外三极管。简易复位电路约 0.1s,上电后须等待稳定再运行代码。
- 原级联方案需额外逻辑门,本设计用 NPN 三极管+光耦模拟 AND 门,关断较慢但无妨(4017 时钟输入为施密特触发器,速度要求不高)。
- 多处地线分离,请仔细核对原理图。

制造工艺
- 自制《鱿鱼游戏》主题互动娃娃——Arduino UNO DIY项目
- ILI9341 2.4 英寸 TFT 触摸屏扩展板位图动画专业指南
- 基于 Web 控制的 DMX 灯光系统 – Arduino 主控制器
- 用 Arduino UNO 和 OLED 显示屏制作经典 Pong 游戏:分步教程
- DIY Arduino USB 游戏手柄 — 自制高性能游戏手柄
- Unopad:基于 Arduino 的无缝 Ableton Live MIDI 控制器
- Arduino Due 驱动 3.2″ TFT 实现温度监测与实时时钟
- 基于 Arduino Mega 与 Nextion 显示屏的交互式气象站
- Arduino DIY 电压表:Nokia 5110 屏幕显示,手把手教学
- BME280 环境数据实时显示于 Nextion 触摸屏——Visuino 图形化开发
- Arduino 声纳实时测距与 Processing 可视化
- DIY Arduino Nano 示波器:10 Hz–50 kHz / 128×64 LCD