1. 项目概述:为经典计算器注入复古灵魂
手头有一台老旧的TI-83+图形计算器,功能完好,但那个单色液晶屏看久了总觉得少了点味道。我一直对真空荧光管那种独特的蓝绿色辉光和复古的数码管造型情有独钟,于是萌生了一个想法:能不能让计算器的计算结果,同时显示在一块更酷、更有“赛博朋克”感的VFD屏幕上?这个想法驱动我完成了这个项目——一个基于PIC微控制器的TI83+计算器显示扩展模块。
这个项目的核心,是构建一个独立的显示系统。它不修改计算器本身的任何硬件或固件,而是通过计算器自带的I/O端口“窃听”数据。当你在计算器上完成计算并将结果存入特定变量后,只需按下我们自制面板上的一个按钮,这个扩展模块就能读取该数值,并将其驱动到一排共11位的IV-6型VFD管上显示出来,同时也会在一块辅助的LCD屏上给出提示信息。整个系统涉及微控制器编程、串行通信协议解析、高压驱动电路设计以及电源管理,是一次典型的嵌入式系统综合实践。
2. 核心思路与系统架构设计
2.1 为什么选择PIC与VFD这个组合?
首先从微控制器选型说起。PIC系列单片机,特别是像PIC16F88这样的型号,在多年前是嵌入式爱好者的热门选择。它资源适中(7KB Flash, 368B RAM, 16个I/O口),功耗低,并且有庞大的社区和成熟的开发工具链(如Great Cow Basic, MPLAB X)。对于这个项目,我们需要一个MCU来负责与计算器通信并处理数据,PIC16F88完全够用。更重要的是,项目灵感来源于Thomas Henry在《Nuts & Volts》杂志上发表的一篇经典文章,他恰好为PIC和TI计算器开发了通信库,这大大降低了软件层面的难度。
至于显示方案,LED数码管太普通,OLED又太现代。VFD(真空荧光显示屏)则完美契合“复古未来”的主题。IV-6管是常见的俄罗斯产小型VFD,它需要相对较高的阳极/栅极电压(约20-34V)和较低的灯丝电压(约1.2V AC或DC)。驱动它需要专门的芯片,我手头有一些A6812SA,这是一款集成了移位寄存器和高压驱动器的芯片,虽然已停产但市面上仍有库存,其替代品MAX6921引脚兼容。选择它,是因为它能用简单的串行信号控制多路高压输出,非常适合驱动多位数码管。
2.2 整体系统工作流程解析
整个系统可以看作一个“数据中继站”。其工作流程如下:
- 数据源:用户在TI-83+计算器上进行运算,并通过
STO>键将结果存储到一个预定义的变量(例如变量S)中。这是整个交互的起点。 - 触发采样:用户按下扩展模块面板上的“New”按钮。这个动作向PIC16F88产生一个中断或电平信号,告知其可以开始读取数据。
- 数据获取:PIC16F88通过连接在计算器I/O端口的几根线(通常是时钟、数据线),利用Thomas Henry编写的TI通信库,向计算器发送读取变量
S的指令。计算器则通过相同的协议将变量值传回。 - 数据处理:PIC16F88接收到的是一个浮点数或整数的二进制表示。代码将其转换为字符串格式。这里有一个关键检查:字符串长度是否超过11位(我们为11个VFD管预留了10位数字和1个小数点位)。如果超长,则在LCD屏上提示用户重新输入。
- 显示驱动:
- LCD显示:将处理好的字符串直接显示在2x16字符的LCD上,作为辅助确认。
- VFD显示:这是核心。代码需要将字符串中的每个字符(‘0’-‘9’, ‘.’, ‘-’)转换为对应的段码(
numeral),并为每个字符分配一个位码(digit)来指定它由哪一根VFD管显示。然后,将digit和numeral数据组合,通过串行方式(时钟、数据、锁存三个信号)送入A6812SA移位寄存器。
- 动态扫描:A6812SA的20个输出端口对应VFD管的栅极(控制哪一位亮)和阳极段(控制显示什么数字)。PIC以极快的速度循环发送11组数据,每次只点亮一位管子,利用人眼的视觉暂留效应,实现所有位“同时”点亮的效果,即动态扫描( multiplexing)。
- 电源供给:VFD需要两组电源。灯丝(Filament)电压约1.2V DC,直接从系统5V通过可调电阻分压获得。阳极/栅极的高压(约30V)则由另一个PIC单片机(12F683)构成的Boost升压电路产生,其输出电压可通过电位器调整,从而控制VFD的亮度。
注意:整个设计的关键在于“非侵入式”。我们不需要对计算器做任何焊接或刷机,仅仅是通过其外部连接端口进行通信。这保证了计算器的完整性和原始功能,也使得项目可逆、风险极低。
3. 硬件设计与核心电路详解
3.1 主控与接口电路:PIC16F88
PIC16F88是这个系统的大脑。其电路设计相对标准:
- 电源:
VDD和VSS引脚连接5V和GND,并就近放置一个0.1uF的陶瓷去耦电容。 - 复位电路:虽然芯片有内部复位,但为了调试方便,我仍然在
MCLR引脚上拉了一个10k电阻到VDD,并连接了一个轻触开关到地,实现手动复位。 - 晶振:为了确保与计算器通信时序的稳定,我使用了一个4MHz的外部晶振,并配上两个22pF的负载电容。
- 与TI-83+的连接:这是最需要小心处理的部分。TI-83+使用一个2.5mm的I/O端口,其引脚定义需要查阅官方文档。通常我们需要连接其中的
SCLK(串行时钟)、SIO(串行数据)和GND。务必注意电平匹配:TI-83+的I/O口电压可能是3.3V,而PIC16F88是5V系统。虽然在某些情况下可以直接连接(PIC的输入能容忍5V,而TI的输出可能接近5V),但最稳妥的做法是使用电平转换电路(如74LVC4245)或至少串联一个330欧姆的电阻以限流,避免损坏计算器珍贵的端口。
3.2 显示驱动核心:A6812SA与VFD管阵列
A6812SA是一个20通道的串行输入、并行输出高压驱动器。其接口非常简单:
DATA IN:串行数据输入,连接PIC的一个I/O口。CLOCK:时钟输入,连接PIC的另一个I/O口。数据在时钟上升沿或下降沿(根据数据手册)被移入。LATCH:锁存信号,连接PIC的第三个I/O口。当一帧数据(20位)移位完成后,一个LATCH脉冲将移位寄存器中的数据锁存到输出锁存器,从而更新VFD显示。BLANK:消隐控制,可快速关闭所有输出。本项目可接高电平或通过电阻上拉使其无效。VDD/VSS:接5V逻辑电源。VP:接高压电源(本项目中为Boost电路产生的~30V)。OUT0-OUT19:20个高压开漏输出。其中19个被使用:11个用于连接11个VFD管的栅极(Grid),另外8个用于连接所有VFD管的阳极段(Segment a-g及dp)。因为所有VFD管的相同段是并联的,所以8个段信号足以控制所有管子显示的内容,而11个栅极信号则用于选择当前要点亮哪一位管子。
IV-6 VFD管的引脚排列需要特别注意。通常它有两个灯丝引脚(Filament),多个栅极(Grid)和多个阳极段(Anode Segment)。接线前必须找到对应的数据手册。一个常见的接线方法是:将所有VFD管的相同段(如a段)引脚并联,接到A6812SA的一个段输出上;将每个VFD管独立的栅极引脚,分别接到A6812SA的一个栅极输出上。
3.3 高压生成:基于PIC12F683的Boost升压电路
VFD的阳极和栅极需要约30V的电压才能激发荧光粉发光。我们利用一个简单的Boost(升压)电路来从5V生成这个高压。PIC12F683在这里并非用作逻辑控制,而是利用其PWM(脉冲宽度调制)模块来驱动一个MOSFET开关。
电路基本构成:
- 储能电感:选择合适感值的功率电感(例如100uH),这是能量转换的核心。
- 开关管:一个N沟道MOSFET(如IRF740),其栅极由PIC12F683的PWM输出引脚通过一个限流电阻驱动。
- 续流二极管:一个快速恢复二极管(如FR107),阴极接输出,阳极接电感和MOSFET的连接点。
- 输出滤波电容:一个高压电解电容(如100uF/50V)用于平滑输出电压。
- 反馈与调节:这是一个开环电路,没有电压反馈。输出电压由输入电压、占空比和负载决定。我们通过一个电位器连接到PIC的ADC引脚,读取电位器的位置,然后动态调整PWM的占空比,从而间接控制输出电压。电位器旋钮就做成了面板上的“亮度调节”。
实操心得:开环Boost的风险与控制:使用开环Boost电路必须极其小心。空载或轻载时,输出电压可能会飙升到远高于设计值,击穿后级元件(如A6812SA)。因此,务必在每次上电前将亮度电位器逆时针旋到底(最小占空比)。同时,在输出端并联一个稳压管(如36V)或压敏电阻作为过压保护,是很有必要的安全措施。
3.4 灯丝供电与辅助电路
IV-6的灯丝额定电压约为1.2V AC。使用交流电可以避免因灯丝电位差导致的显示亮度不均。但为11个管子提供交流驱动需要额外的变压器和电路,比较复杂。本项目采用了简化的DC驱动方案。
- DC驱动方案:从5V电源,通过一个精密多圈电位器(100欧姆)分压,为每个VFD管的灯丝提供约1.2V DC。每个管子独立一个电位器,以便微调。
- 亮度不均问题:DC驱动下,灯丝一端接正,一端接负,会导致靠近正极的段比靠近负极的段更亮。对于单个数码管,这种不均匀性在可接受范围内。为了进一步改善,可以将所有VFD管的灯丝串联起来,用一个恒流源驱动,但这要求灯丝电压累加,设计更复杂。本项目的折中方案被证明是有效的。
- LED氛围灯:为了增强视觉效果,在每个VFD管下方安装了一个蓝色LED,通过一个限流电阻(如470欧姆)连接到5V电源。它们常亮,为VFD管提供背光,营造出更深的层次感。
4. 软件设计与代码实现剖析
4.1 开发环境与基础库
代码使用Great Cow Basic(GCB)编写。GCB是一种基于BASIC语法的PIC编译器,语法简单直观,适合快速开发。项目的软件基石是Thomas Henry编写的TI-Library.gcb。这个库封装了与TI-83+计算器通信的底层细节,提供了像TI_Read、TI_Write这样的高级函数,使得从PIC读取计算器变量变得像读取本地变量一样简单。没有这个库,项目难度将呈指数级上升。
4.2 主控程序(PIC16F88)流程解析
主程序运行在一个无限循环中,核心是状态机管理。
// 伪代码示意,非完整GCB代码 Include "TI-Library.gcb" // 引入TI通信库 // 定义引脚 Symbol BUTTON = PORTA.0 Symbol DATA_PIN = PORTA.1 Symbol CLOCK_PIN = PORTA.2 Symbol LATCH_PIN = PORTA.3 Symbol NEG_LED = PORTA.4 // 定义段码表 (共阴极,1表示点亮) Dim SEGMENT_CODE(11) As Byte = {0x3F, 0x06, 0x5B, ...} // 0-9及小数点的段码 Sub Main Initialize() // 初始化I/O、LCD、定时器 LCD_Print “Ready. STO> S” Do Forever If BUTTON = 0 Then // 按钮被按下 DebounceDelay(50) // 消抖 Get_Data_From_TI83() // 核心函数 End If Run_Multiplex() // 持续运行动态扫描 Loop End Sub Sub Get_Data_From_TI83 TI_Connect // 建立与计算器的连接 TI_Read(“S”, value$) // 读取变量S的值到字符串value$ TI_Disconnect length = Len(value$) If length > 11 Then LCD_Clear LCD_Print “Too Long! <=10 digits” WaitMs 2000 LCD_Print “Ready. STO> S” Return End If // 处理负号 If Left$(value$, 1) = “-” Then High NEG_LED value$ = Mid$(value$, 2) // 移除负号,因为VFD管不显示“-”,由LED指示 Else Low NEG_LED End If LCD_Clear LCD_Print value$ LCD_SetCursor 2,1 LCD_Print “Len:”; length // 将字符串转换为显示缓冲区 Convert_String_To_Buffer(value$) End Sub Sub Run_Multiplex For digit = 1 To 11 // 1. 准备数据:1位栅极选择位 + 8位段码位 data_word = (1 << (digit-1)) // 栅极位,例如第1位管子是0x0001 data_word = data_word | (SEGMENT_CODE(buffer(digit)) << 8) // 合并段码 // 2. 串行发送19位数据到A6812SA Low LATCH_PIN For bit = 18 To 0 Step -1 // 先发送高位 If (data_word >> bit) And 1 Then High DATA_PIN Else Low DATA_PIN End If Pulse CLOCK_PIN // 产生一个时钟脉冲 Next bit High LATCH_PIN // 锁存数据,更新显示 // 3. 点亮当前位一段时间 WaitUs 2000 // 扫描间隔,控制亮度 Next digit End Sub关键点解析:
- 通信与错误处理:
TI_Read函数是黑盒,我们信任库的正确性。重点在于对读取结果的后续处理:长度检查和负号处理。 - 显示缓冲区:
buffer数组存储了当前要显示的11位数字(或小数点)的段码索引。Convert_String_To_Buffer函数需要处理对齐问题,例如数字“123.4”可能需要转换为缓冲区:[空, 空, 空, 1, 2, 3, ., 4, 空, 空, 空],实现右对齐显示。 - 动态扫描时序:
Run_Multiplex子程序是显示驱动的核心。它必须足够快,通常扫描整个11位的时间要小于20ms(即频率>50Hz),才能避免闪烁。WaitUs 2000意味着每位显示约2ms,11位就是22ms,略高于临界值,但实际观看效果尚可。可以通过减少延时或优化代码来提速。
4.3 升压控制器程序(PIC12F683)
这个PIC的程序非常简单,就是一个ADC读取加PWM输出。
// PIC12F683 用于Boost PWM控制 Include “ADConverter.h” Symbol POT = GPIO.0 // 连接电位器,设为模拟输入 Symbol PWM_OUT = GPIO.2 // 连接MOSFET栅极 Sub Main ANSEL = %00000001 // 设置AN0为模拟输入 CMCON0 = 7 // 关闭比较器 TRISIO = %00000001 // GP0输入,GP2输出 ADC_Init() // 初始化ADC模块 PWM_Init(5000) // 初始化PWM,频率约5kHz PWM_Start() Dim adc_value As Word Dim duty_cycle As Byte Do Forever adc_value = ADC_Read(0) // 读取电位器电压 (0-1023) duty_cycle = adc_value / 4 // 映射到0-255的占空比 PWM_Set_Duty(duty_cycle) WaitMs 100 // 每100ms更新一次占空比,响应速度足够 Loop End Sub参数选择:
- PWM频率:选择5kHz是一个折中。频率太低,电感噪音可能被人耳听到,且输出纹波大;频率太高,MOSFET的开关损耗会增加。5-50kHz是此类低功率Boost的常见范围。
- ADC采样更新率:100ms的更新间隔对于手动调节亮度来说非常平滑,避免了因ADC采样过快导致的亮度抖动。
5. 组装、调试与安全操作指南
5.1 机械结构组装要点
项目的外壳和面板可以通过3D打印或使用现成的塑料盒改造。对于VFD管的固定,我采用了一个巧妙的方法:
- 找一些内径与VFD管直径匹配的塑料管(如吸管或笔芯外套),切成等长的小段。
- 将这些塑料管段粘在PCB或底板上,排列成一行。它们既是VFD管的支撑座,又能确保所有管子高度对齐。
- 将LED和限流电阻塞入这些塑料管段内部,这样LED的光就从管子底部向上照射,形成均匀的背光。
- 使用ZIF(零插拔力)插座来安装PIC16F88。这在调试和烧录程序时提供了巨大的便利,无需反复焊接。
5.2 上电前至关重要的校准步骤
这是避免“烟花”的关键环节,必须严格执行:
- 高压调节归零:确保面板上的亮度旋钮(控制Boost电路PWM占空比)逆时针旋到底(电阻最大,占空比最小,输出电压最低)。
- 灯丝电流限制:将所有11个用于灯丝限流的100欧姆电位器,逆时针旋到底(电阻最大,灯丝电压接近0V)。
- 首次上电与测量:连接5V电源。先不要接计算器。
- 用万用表测量Boost电路输出端电压,应为一个很低的值(可能只有几伏)。缓慢顺时针旋转亮度旋钮,观察电压平稳上升,最高不要超过A6812SA的
VP引脚最大额定电压(例如35V)。我将其设定在30V。 - 逐一校准灯丝电压:用万用表表笔测量每个VFD管的两个灯丝引脚。非常缓慢地顺时针旋转对应的电位器,观察电压上升至1.2V。此时灯丝可能会发出微弱的橙红色光。这是正常的,但为了延长灯丝寿命,我建议将电压调至刚好低于发光阈值的点,例如1.1V。这样既能保证电子发射,又能最大程度延长管子寿命。
- 用万用表测量Boost电路输出端电压,应为一个很低的值(可能只有几伏)。缓慢顺时针旋转亮度旋钮,观察电压平稳上升,最高不要超过A6812SA的
- 连接计算器与功能测试:关闭扩展模块电源。将连接线稳妥地插入TI-83+的I/O口。打开计算器电源,再打开扩展模块电源。在计算器上输入
123.456,然后按STO>SENTER。按下扩展模块的“New”按钮。此时,LCD应显示该数字,同时11位VFD管应从右向左显示“123.456”(前面几位为空)。缓慢调节亮度旋钮,直到VFD显示清晰且亮度舒适。
5.3 完整操作流程与安全规范
- 开机顺序:
亮度旋钮调至最低->打开扩展模块电源->打开计算器电源。 - 日常操作:
- 在TI-83+上进行计算。
- 按
STO>SENTER存储结果。 - 按扩展模块的“New”按钮,更新VFD显示。
- 可随时调节亮度旋钮至满意程度。
- 关机顺序:
亮度旋钮调至最低->关闭扩展模块电源->关闭计算器电源。
核心安全禁令:绝对禁止在亮度旋钮未调至最低时开机或关机。突然施加或切断高占空比PWM信号,可能导致电感产生瞬间高压尖峰,对MOSFET和驱动芯片造成致命打击。养成“调低亮度再动电源”的肌肉记忆。
6. 常见问题排查与进阶优化
6.1 问题速查表
| 现象 | 可能原因 | 排查步骤 |
|---|---|---|
| VFD完全无显示 | 1. 高压电源故障。 2. A6812SA未工作。 3. 动态扫描程序未运行。 | 1. 测Boost输出是否有~30V?检查PIC12F683 PWM输出、MOSFET、电感、二极管。 2. 测A6812SA的 VP引脚是否有高压?VDD是否有5V?用示波器查DATA,CLOCK,LATCH信号是否正常。3. 检查主程序是否卡在 TI_Read等通信环节。可先注释掉通信代码,让扫描循环单独运行。 |
| VFD显示暗淡 | 1. 高压不足。 2. 灯丝电压过低。 3. 扫描速度过快,每位点亮时间太短。 | 1. 调高亮度旋钮,监测高压是否随之上升至30V左右。 2. 测量并微调灯丝电压至1.1-1.2V。 3. 增加 Run_Multiplex子程序中WaitUs的延时值。 |
| VFD显示闪烁 | 动态扫描频率过低(低于50Hz)。 | 优化Run_Multiplex代码,减少不必要的延时,确保11位扫描总时间小于20ms。 |
| 某些段常亮或常灭 | 1. A6812SA对应输出通道损坏。 2. VFD管内部断线或短路。 3. 焊接虚焊或连线错误。 | 1. 用万用表测试A6812SA对应输出引脚在扫描时是否有电压变化。 2. 交换VFD管测试,判断是管子问题还是驱动问题。 3. 仔细检查PCB走线和焊点。 |
| LCD显示正常,但VFD显示乱码 | 段码表SEGMENT_CODE数据错误,或字符串到缓冲区的转换逻辑有误。 | 1. 确认段码表是针对共阴极VFD管定义的。 2. 调试 Convert_String_To_Buffer函数,确保小数点等特殊字符被正确映射和处理。 |
| 无法从计算器读取数据 | 1. 连接线接触不良或接错。 2. TI通信库初始化或连接失败。 3. 计算器未开机或变量 S不存在。 | 1. 重新插拔连接线,确认SCLK,SIO,GND对应无误。2. 在代码中加入更多调试信息输出到LCD,查看 TI_Connect的返回状态。3. 确保计算器已开机,并已在计算器上创建了实数变量 S。 |
| 负号LED不亮 | 1. LED极性接反或损坏。 2. 负号检测逻辑错误。 | 1. 检查LED及限流电阻回路。 2. 调试代码,确认当读取的字符串以“-”开头时,控制LED的I/O口是否被置高。 |
6.2 进阶优化思路
- 增加通信可靠性:目前的通信是“一问一答”的查询式。可以增加超时重试机制和校验和,防止因计算器忙或干扰导致的数据错误。
- 实现自动同步:可以尝试监听计算器I/O端口的特定信号,当检测到有新的
STO>操作时自动触发读取,无需手动按“New”按钮。但这需要对TI协议有更深的理解。 - 改进电源效率:为Boost电路增加简单的电压反馈(如用电阻分压采样输出电压,通过PIC的ADC读取并闭环调节占空比),实现稳压输出,避免负载变化引起的亮度波动。
- 支持更多显示模式:扩展代码,使其不仅能显示数字,还能显示简单的字母(如“Error”, “Full”),充分利用VFD管的段码。
- 外壳与美学优化:设计一个更精致的3D打印外壳,将LCD、VFD管阵列、旋钮和按钮集成在一起,做成一个独立的桌面摆件。
这个项目最大的乐趣在于,它像一座桥梁,连接了上世纪七八十年代的显示技术与九十年代的计算设备,并通过现代的嵌入式开发工具将其融合。当你按下按钮,古老的荧光管亮起,显示出图形计算器里的数字时,那种跨越时间的对话感,正是电子制作最迷人的地方。