1. 项目背景与需求从“吃灰”芯片到编码器鉴相手头有一堆从旧设备上拆下来的电机需要读取它们的编码器信号来判断电机的转向和速度。这个需求在机器人、数控机床、甚至一些简单的自动化设备里很常见。编码器通常会输出两路相位差90度的方波信号我们常说的A相和B相通过判断这两路信号的相位关系就能知道电机是正转还是反转。最直接的做法是用几片74系列的逻辑门芯片搭一个鉴相电路网上现成的逻辑图一抓一大把。但当时实验室的抽屉里静静地躺着几十片GAL16V8是以前项目剩下的“遗产”。老板一句话“手头有什么就用什么”让这些几乎被遗忘的芯片重新进入了我的视野。GALGeneric Array Logic通用阵列逻辑芯片对于很多年轻工程师来说可能只是个教科书上的名词。它是一种可编程的逻辑器件在FPGA和CPLD大行其道的今天确实显得古老。但它有个无可比拟的优势成本极低。对于只需要实现几十个逻辑门功能的小型、固定应用用一片几块钱的GAL来实现远比动用一颗FPGA或单片机要经济得多电路也更简单可靠。我的需求恰好就是这样一个简单的固定逻辑——编码器四倍频鉴相用GAL16V8来实现无论是从物料成本还是电路复杂度上看都是非常合适的选择。然而当我真正开始动手时才发现教程难觅。网上的资料要么过于古老要么直接跳到了VHDL/Verilog的“现代”方法对于只想快速实现一个简单功能的“实用主义者”很不友好。经过一番摸索我找到了一条几乎零代码、基于原理图、快速生成烧录文件的捷径。这个方法的核心是借助一个古老的工具——Protel 99SE现在叫Altium Designer的爷爷辈里自带的一个功能。整个过程你甚至不需要理解CUPL语言一种用于PLD的硬件描述语言就像画普通的数字电路图一样就能把功能实现。2. 工具链选择为什么是Protel 99SE PLD-CUPL面对一个“古老”的芯片选择开发工具的第一原则是匹配与可用性。GAL16V8流行的年代正是Protel 99SE如日中天的时候。这款软件内置了对多种PLD可编程逻辑器件的图形化设计支持其中就包括CUPL编译器。CUPLCompiler for Universal Programmable Logic是当时很多PLD厂商支持的通用描述语言和工具。为什么不用更新的软件比如Vivado、Quartus原因很简单不支持。主流FPGA/CPLD工具链早已放弃了对这些简单PLD的直接支持。虽然有一些第三方或开源工具如WinCUPL但它们的安装、配置、学习曲线对于只想快速解决一个问题的人来说又是一道门槛。Protel 99SE中的PLD-CUPL向导提供了一个从画图到生成JEDEC文件标准烧录格式的一站式图形化环境极大地降低了入门难度。注意我知道现在找到一台能顺畅运行Protel 99SE的Windows XP电脑可能比找到GAL芯片还难。但实际测试发现在Windows 10/11上以兼容模式运行Protel 99SE其PLD设计部分基本功能是稳定的。当然你也可以寻找更新的Altium Designer版本它们通常保留了向后兼容性。本文的方法论是通用的核心是“图形化设计-CUPL编译-JED文件”这个流程。这套工具链的另一个巨大优势是设计直观。我的鉴相逻辑是用基本的与门、或门、非门、D触发器搭建的。在原理图环境下我可以像在纸上画电路图一样直接连接这些符号所见即所得。编译器会自动将原理图翻译成CUPL语言再编译成适用于GAL16V8结构的熔丝图Fuse Map最终生成.jed文件。这比直接写CUPL或任何HDL语言都要友好得多尤其适合从数字电路基础直接过渡过来的工程师。3. 核心逻辑设计编码器鉴相电路详解在动手画图之前必须先把要实现的逻辑搞清楚。我需要的编码器鉴相四倍频电路是一个经典的数字电路应用。它有两个核心功能方向鉴别根据A、B两相输入的相位差判断电机正转还是反转。四倍频脉冲输出在A、B相的每个上升沿和下降沿都产生一个计数脉冲从而提高位置分辨率。假设我们定义A,B为编码器两路输入信号。CLK为系统时钟用于同步防止亚稳态频率需远高于编码器信号频率。DIR为方向输出例如1表示正转0表示反转。PULSE为四倍频后的脉冲输出。其真值表或状态机描述在很多教材里都有。但用基本门电路和触发器来实现一个常见的方案是用D触发器对A、B信号进行同步锁存得到A_sync和B_sync以及它们上一个时钟周期的值A_prev,B_prev。方向判断DIR (A_sync ^ B_prev) ~(A_prev ^ B_sync)这里‘^’表示异或。这个逻辑可以简化为当A领先B变化时正转特征输出1当B领先A变化时反转特征输出0。脉冲生成PULSE (A_sync ^ A_prev) | (B_sync ^ B_prev)。即A或B信号任意一路发生跳变上升沿或下降沿就产生一个脉冲。在GAL16V8中实现我们需要将这些布尔表达式转化为与或阵列。幸运的是我们不需要手工做这个转化。我们只需要在Protel的原理图环境中用库里的D触发器DFF、与门AND、或门OR、非门NOT、异或门XOR等符号按照上述逻辑连接起来。3.1 原理图绘制实操要点打开Protel 99SE按照正文的步骤启动PLD-CUPL向导后你会进入一个特殊的原理图文档。左侧的库浏览器中有一个专门的“PLD Symbols”库里面包含了所有可综合的逻辑单元。第一步是清理画布。向导生成的原理图包含了一个虚拟器件和一堆默认引脚把它们全部删除。我们从一个干净的页面开始。第二步是放置输入输出引脚。从“PLD Symbols”库中找到IPAD输入引脚、OPAD输出引脚。对于双向引脚则用IOPAD。我这次的需求很简单输入A,B,CLK。共3个IPAD。输出DIR,PULSE。共2个OPAD。注意GAL16V8有8个输出逻辑单元OLMC每个都可以配置为组合输出或寄存器输出。我们的DIR和PULSE希望是同步于CLK的寄存器输出以保持信号稳定。因此在后续配置和逻辑中需要确保它们来自D触发器的输出。第三步是搭建逻辑电路。这是最核心的一步。放置两个D触发器DFF用于锁存A和B输入。将它们的时钟端CLK都连接到CLK输入引脚。数据端D分别接A和B。输出端Q即为同步后的A_sync和B_sync。为了得到上一拍的值需要再引入两个D触发器它们的D端分别接A_sync和B_sync时钟同样是CLK。它们的输出Q就是A_prev和B_prev。现在我们有了A_sync,B_sync,A_prev,B_prev这四个信号。接下来用逻辑门搭建表达式。对于DIR用两个异或门XOR分别计算A_sync ^ B_prev和A_prev ^ B_sync。再用一个非门NOT对后者取反。最后用一个与门AND将两者相与。这个与门的输出就是方向逻辑但它目前是组合逻辑。我们需要将它连接到一个新的D触发器的D端该触发器的时钟接CLK其Q端输出才是稳定的DIR信号。最后将这个Q端连接到一个OPAD上命名为DIR。对于PULSE用两个异或门分别计算A_sync ^ A_prev和B_sync ^ B_prev。再用一个或门OR将两者相或。同样这个或门的输出是组合逻辑的脉冲我们将其连接到另一个D触发器的D端时钟接CLK其Q端输出连接到名为PULSE的OPAD。实操心得信号命名与网络标号在连接复杂电路时大量导线交叉会使得原理图难以阅读和检查。强烈建议使用“网络标号”Net Label。例如将第一个D触发器输出Q命名为A_sync然后在需要用到A_sync的地方放置一个同样名为A_sync的网络标号它们就在电气上连接起来了。这能让你的图纸清晰百倍也便于后续检查。绘制完成的原理图应该是一个清晰的、由触发器、门电路和连线构成的数字系统框图。这比看一堆代码要直观得多。4. 器件配置与引脚映射让设计落地到GAL16V8画好原理图只是设计了一半。我们必须告诉编译器这个设计最终要实现在哪个具体的芯片上以及芯片的每个引脚对应我们原理图中的哪个信号。这就是配置和映射。4.1 选择目标器件点击菜单栏的PLD - Configure...会弹出配置对话框。在Target Device区域是关键所在。你需要从下拉列表中选择具体的器件型号。找到GAL16V8并选中。这里有几个细节需要注意GAL16V8有不同的工作模式通过编译选项可以配置输出逻辑宏单元OLMC。对于我们的设计DIR和PULSE是寄存器输出CLK需要连接到所有触发器的时钟端。在GAL16V8中引脚1通常被固定配置为全局时钟CLK输入。因此我们必须将原理图中的CLK信号映射到引脚1编译器才会正确地将它连接到内部的时钟网络。器件型号务必选对GAL16V8有普通型和高速型等如果选错编译器可能无法通过或生成错误的熔丝图。如果不确定就选最通用的GAL16V8。4.2 引脚映射实战双击原理图中的任何一个IPAD或OPAD符号打开其属性对话框。我们需要关注Part Fields标签页。这里有一个Params字段就是用来指定引脚映射的。 映射的格式是LOC PINx其中x是引脚号。 例如将CLK输入引脚映射到引脚1LOC PIN1将A输入引脚映射到引脚2LOC PIN2将B输入引脚映射到引脚3LOC PIN3将DIR输出引脚映射到引脚12LOC PIN12将PULSE输出引脚映射到引脚19LOC PIN19重要注意事项GAL16V8引脚功能限制GAL16V8的引脚不是完全自由的。引脚1是专用时钟输入。引脚11是输出使能OE通常需要接低电平GND才能使能输出如果你不需要三态功能简单地将它接地即可。引脚12-19是输出引脚但其中一些在特定模式下也可以作为输入。在分配引脚时最好先查阅一下GAL16V8的数据手册中的引脚功能图避免将输入信号分配到纯输出引脚上。一个安全的分配策略是输入用2-9脚输出用12-19脚1脚接时钟11脚接地10脚接地GND20脚接电源VCC通常是5V。完成所有引脚的映射后建议列一个表格进行核对防止错漏。这是硬件设计中最容易出错也最致命的一环。5. 编译、烧录与验证从文件到芯片当原理图和引脚映射都确认无误后就可以进行编译了。点击PLD - Compile。编译器会做以下几件事检查原理图的电气连接和逻辑完整性。将原理图网表转换为CUPL语言描述。根据选择的GAL16V8架构进行逻辑综合与适配将你的逻辑函数拟合到芯片的与或阵列和OLMC中。生成熔丝图文件即JEDEC格式.jed的文件。如果编译成功在状态窗口会看到“Design Compilation Successful”之类的提示。如果失败会给出错误信息通常是语法错误、逻辑太复杂无法实现超出了GAL16V8的资源、或引脚分配冲突。需要根据提示返回修改。编译成功后在当前工程目录下或你在向导中指定的输出目录找到生成的.jed文件。这个文件就是我们要烧录到物理芯片中的“编程文件”。5.1 烧录器选择与操作你需要一个支持GAL16V8的编程器烧录器。市面上一些通用的EPROM/单片机编程器比如TL866系列通常都支持GAL系列芯片。操作步骤大致如下将GAL16V8芯片正确插入编程器插座注意方向芯片上的凹槽或圆点对准插座的标记。打开编程器软件选择器件型号为“GAL16V8”。点击“擦除”Erase或“检查空白”Blank Check确保芯片是空的。点击“加载文件”Load File选择刚才生成的.jed文件。点击“编程”Program或“烧写”Write。编程器会将熔丝图写入芯片。最后可以进行一次“校验”Verify确保写入的数据与文件一致。烧录完成后芯片就包含了你的编码器鉴相逻辑。将它焊接到你的目标电路板上连接好编码器的A、B相到对应输入引脚接上电源和时钟就可以在输出引脚用示波器或逻辑分析仪观察DIR和PULSE信号了。6. 调试技巧与常见问题排查第一次尝试很难一次成功。以下是我在调试过程中遇到的一些典型问题及解决方法整理成排查清单现象可能原因排查步骤与解决方法编译失败1. 逻辑过于复杂超出GAL16V8容量。2. 引脚分配冲突如输入分配到输出专用脚。3. 原理图存在环路或未连接端口。1. 简化逻辑。GAL16V8输出最多8个乘积项检查编译器报告看哪个输出逻辑的乘积项超限。可以通过逻辑代数化简如卡诺图来简化表达式。2. 仔细核对GAL16V8数据手册的引脚图重新分配引脚。3. 在原理图中运行电气规则检查ERC。烧录失败1. 芯片已损坏或不是空片。2. 编程器型号不支持或接触不良。3..jed文件损坏或格式不对。1. 尝试擦除芯片。如果擦除失败换一片芯片试试。2. 确保编程器软件中器件型号选择正确。重新插拔芯片确保引脚接触良好。3. 重新编译生成.jed文件或换一个简单的测试逻辑如一个反相器来测试编程器链路是否正常。上电后输出无变化或全高/全低1. 电源或地线未接好。2. 输出使能OE引脚11未正确接地。3. 时钟信号CLK引脚1未连接或频率不对。4. 逻辑设计根本性错误。1. 用万用表测量芯片VCC引脚20和GND引脚10电压是否为稳定的5V。2. 确认引脚11已可靠接地。3. 用示波器检查引脚1是否有时钟信号。时钟频率必须高于编码器信号最高变化频率的若干倍建议10倍以上否则无法可靠采样。4. 回到仿真或重新审查逻辑图。可以用逻辑分析仪同时抓取输入A, B和所有中间节点如果可能以及输出信号对照时序图分析。方向判断错误1. A、B两相输入接反。2. 同步触发器亚稳态导致误判。3. 逻辑表达式有误。1. 交换A、B输入再测试。2. 提高系统时钟CLK频率远高于编码器信号频率。确保编码器信号边沿干净无毛刺可考虑在输入端加入施密特触发器整形如74HC14或软件上做滤波。3. 这是最常见的问题。用仿真工具如Proteus先对原理图进行数字仿真输入A、B相位差90度的方波观察DIR输出是否正确。在Protel中编译后可以查看生成的报告文件里面有化简后的逻辑方程核对是否正确。脉冲输出有毛刺或丢失1. 组合逻辑的竞争-冒险现象。2. 输入信号抖动。3. 时钟频率不够高漏掉了快速跳变。1. 我们的PULSE逻辑(A^A_prev)6.1 一个关键的实操心得利用编译器报告编译成功后不要急着关掉报告窗口。编译器会生成一个.lst或.rpt文件里面包含了经过化简后的每个输出的逻辑方程。仔细阅读这个方程它是你的设计在芯片内部实现的真实逻辑。你可以把它和你最初设计的布尔表达式进行对比这是验证编译器是否正确理解你意图的最直接方法。有时编译器会进行优化结果可能和你预想的略有不同但功能必须等价。如果发现不对就要回去检查原理图连接。7. 方法优劣分析与适用场景这种基于Protel 99SE原理图开发GAL的方法优缺点都非常明显。优点学习曲线极低如果你熟悉数字电路原理图几乎不需要学习任何新的语言如VHDL/Verilog或CUPL上手速度极快。直观可视整个设计过程就是画电路图对于小型、以门级和触发器级为主的逻辑设计非常直观便于理解和调试。工具集成从设计、编译到生成烧录文件在一个相对熟悉的环境对于老工程师中完成流程顺畅。缺点与局限工具古老Protel 99SE已是二十多年前的软件在新系统上运行可能有兼容性问题。其PLD功能后续版本虽有保留但不再是开发重点。不适合复杂逻辑对于状态机、计数器等稍复杂的逻辑用门电路和触发器搭接原理图会变得非常庞大和杂乱难以维护。这时硬件描述语言HDL的优势就体现出来了。可移植性差设计绑定在特定的图形化工具和芯片上。如果想换成其他型号的PLD或CPLD可能无法直接迁移。调试能力弱缺乏现代EDA工具的仿真、时序分析等高级调试功能。调试主要靠硬件实测和阅读编译报告。那么它适合谁电子爱好者或学生手头有一些GAL芯片想实现一个简单的逻辑电路如自定义译码器、简单时序控制、接口逻辑转换作为入门PLD/FPGA的跳板。维护工程师需要修复或仿制一个使用了GAL芯片的老设备但找不到原厂JED文件需要根据电路功能反向生成。快速原型验证在FPGA或CPLD开发板不在手边时用GAL快速验证一个核心逻辑功能的正确性。成本极度敏感的超简单应用产品功能极其固定且简单一片几元钱的GAL就能搞定没有必要上MCU或CPLD。对于更复杂或未来的项目我强烈建议学习VHDL或Verilog并使用现代的FPGA/CPLD开发工具如Quartus, Vivado等。那是一个更强大、更主流的世界。但这次用GAL16V8的经历让我重新体会到“用最简单工具解决实际问题”的乐趣也让我对硬件底层逻辑的实现有了更感性的认识。有时候回头看看这些“古老”的技术反而能加深对基础原理的理解。毕竟再复杂的FPGA其底层基础也是由与门、或门、触发器这些基本单元构成的。