ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

数电实训万年历项目:从74LS芯片到FPGA的完整设计与调试实录

数电实训万年历项目:从74LS芯片到FPGA的完整设计与调试实录 你们实训周应该也做过类似的东西吧数电这门课理论知识听的时候觉得不过尔尔真正上手做项目才会发现全是坑。我这次数电实训选的是万年历一个看似简单实际上把组合逻辑、时序逻辑、译码显示、异步清零、同步置数全串起来的经典题目。从拿到题目到仿真通过再到面包板跑起来前后折腾了两周中间烧过芯片、炸过电容、对着示波器怀疑人生。这篇就把整个项目的设计思路、电路细节、调试记录和踩坑实录完整写出来给后面做这个题目的同学一个参考也欢迎已经做完的朋友一起来讨论。先说清楚这个项目是干什么的。万年历本质上就是一个“带日历功能的数字钟”要求用数字电路实现年、月、日、时、分、秒的计数与显示并且日期要能根据大小月自动调整2月还要区分平年闰年。这个项目最合适的人群就是正在学数电的学生以及想通过一个完整项目巩固时序逻辑知识的硬件爱好者。它不像单片机方案那样写几行代码就完事而是逼着你去理解每一个进位信号、每一个清零条件做完之后你对计数器的理解会彻底不一样。1. 项目整体设计与思路拆解1.1 万年历实训到底考什么需求拆解先把需求一条条列清楚这决定了后面的电路结构。我给自己定的功能指标是这样的显示内容年后两位、月、日、时、分、秒共14位数字秒信号由555定时器产生1Hz基准脉冲这是整个系统的心脏时制24小时制23:59:59后回到00:00:00日期切换1、3、5、7、8、10、12月为31天4、6、9、11月为30天2月平年28天、闰年29天闰年判断年份后两位能被4整除即为闰年手动校准通过按键分别对时、分、日、月、年进行快速调整。这个需求里秒、分、时是常规计数器难度不大真正的分水岭在日期部分——日计数器必须根据月份和闰年结果决定是30天、31天还是28/29天。也就是说日期部分不光是计数器还得有一块“月底判断”的组合逻辑。这部分做明白了整个项目的核心就拿下了一大半。1.2 方案选型为什么坚持用74系列芯片而不是单片机不少同学看到这个题目第一反应是“用STM32啊RTC模块一开就完事了”但数电实训的意义恰恰在于不让你用处理器。如果走单片机路线就完全绕开了数电的核心知识——计数器、译码器、触发器、门电路。所以我的方案用的是74LS系列的TTL小规模集成电路总共大概用了这些芯片74LS160×8十进制同步计数器秒/分/日/月/年的主体74LS08、74LS32、74LS04若干与门、或门、非门用于清零/置数逻辑和月底判断74LS151×1数据选择器用于校时脉冲切换74LS48×14BCD七段译码器驱动共阴数码管555定时器×1产生1Hz秒脉冲。当然用FPGA也是可以的而且现在很多学校的数电实验课已经开始引入FPGA用Verilog写一个万年历模块更接近工程实践。但从课程考核角度讲用分立芯片搭电路能把每个信号都看得清清楚楚这是FPGA综合之后看不到的东西。我的建议是如果你时间充裕先用74芯片搭一遍硬件再用FPGA写一遍Verilog两头都通了数电基本上就过关了。1.3 顶层模块划分从整体到局部的拆解思路我习惯在动手前先把整个系统画成功能模块图不是仿真图是手绘框图这样接线时脑子不会乱。整个万年历我划分成五个模块第一个是时钟源模块给整个系统提供稳定的1Hz脉冲第二个是时分秒模块从秒计数器到分计数器到时计数器逐级进位第三个是日历模块这个最复杂包括日计数器、月计数器、年计数器外加一个“月底判断”组合逻辑块用于控制日计数器何时归1第四个是译码显示模块把所有计数器的BCD码送进74LS48驱动14位数码管第五个是校时模块用按键产生快调脉冲通过数据选择器切换正常秒脉冲和手动脉冲。模块划分清楚之后就能一条一条地搭建每搭完一块先单独测试再逐级联调。我见过很多人上来就一股脑把所有芯片插到面包板上结果出问题的时候根本不知道从哪查起。这个项目必须循序渐进。2. 核心电路设计与参数计算2.1 1Hz秒脉冲源555定时器振荡电路的设计与校准整个系统的时间基准是1Hz这个信号如果飘了后面的计数全部不准。我用的是经典的555无稳态多谐振荡器电路结构是一个555定时器加两个电阻一个电容。这里把参数计算说透一些。555输出方波的周期公式是T 0.7 × (R1 2R2) × C其中R1是接在VCC和放电引脚之间的电阻R2接在放电引脚和触发/阈值引脚之间C是定时电容。高电平持续时间为0.7×(R1R2)×C低电平持续时间为0.7×R2×C。要让周期等于1秒就得选择合适的R和C组合。我实际用的参数是R1取10kΩR2取68kΩC取10μF。代入公式算一下T 0.7 × (10k 2×68k) × 10μ 0.7 × 146k × 10μ ≈ 1.022秒这个误差在百分之一左右用示波器看会稍微偏慢一点点。所以我在R2的位置串联了一个10kΩ的多圈电位器实际调试时一边用示波器看波形一边微调电位器把周期调到1.000秒左右。这里要注意555的输出波形占空比不是50%因为充放电回路不对称但数字电路只关心脉冲的上升沿占空比无所谓只要能稳定输出1Hz就行。注意如果你手头没有示波器可以用万用表频率档测量或者用LED灯观察闪动频率。但只用LED不太精确建议有条件还是借一台示波器。2.2 模60计数器秒和分电路的两种实现方式秒计数器和分计数器本质相同都是模60。模60的意思是从0计数到59然后回到0并输出一个进位脉冲给下一级。我用两片74LS160实现一片做个位0~9一片做十位0~5。74LS160是同步十进制计数器高电平使能上升沿计数有异步清零(CLR)和同步置数(LOAD)功能。模60的接法有两种我分别说清楚。第一种是个位RCO接十位时钟的方式。74LS160的RCO进位输出在计数到9且使能有效时输出高电平到下一个时钟上升沿变为低电平。这个下降沿刚好可以作为十位74LS160的时钟。但是74LS160是上升沿触发直接用RCO接CLK不行需要反相一下。这种级联方式叫异步级联接线简单但时序不干净。第二种更推荐是同步级联方式把个位的RCO接到十位的ENT使能端两片74LS160的CLK接同一个秒脉冲。个位计数到9的瞬间RCO变高十位使能打开下一个时钟上升沿到达时个位从9回到0十位同时加1。这种方式没有额外的边沿问题级联更可靠。我当时用的是同步级联后面分到时的进位也是这样处理的全部统一。关键问题来了秒计数到59后十位是50101下一个脉冲来的时候个位变0同时十位应该从5变成0。光靠使能级联只能实现60进位的“加1”不能实现“到5就清零”。所以十位计数器需要反馈逻辑。我用的是同步置数法把十位的QA和QC对应二进制0101的bit0和bit2接入一个与非门输出接到十位的LOAD端数据输入端D0~D3全部接GND。这样当十位计数到5时LOAD被拉低下一个时钟上升沿到来时十位被置为0不会出现状态6。这个方案比清零法好在不会产生毛刺因为同步置数是在时钟边沿才动作。2.3 模24计数器时电路的清零与置数设计时计数器同样是两片74LS160但计数范围是0~23到23后下一脉冲回到00。这部分的反馈条件需要组合个位和十位。23这个状态对应十位为20010个位为30011。我在设计中使用了反馈清零法把十位的QB2的权位和个位的QA与QB3的权位bit0和bit1相与产生清零信号送到两片计数器的CLR端。当计数器到达23后如果下一脉冲本来应该到24但清零信号会在24状态出现前把计数器复位——这里要小心74LS160是异步清零一瞬间会出现毛刺。所以我把清零信号同时送到两片芯片的CLR端并且每个芯片的电源脚并行接一个0.1μF去耦电容把这个毛刺的影响压到最低。如果你对毛刺特别敏感也可以改用置数法当计数器进入24状态十位2、个位4时LOAD拉低在下一个时钟将计数器置为0。这两种方法我都在仿真里试过实际硬件上用清零法更常见因为反馈逻辑简单但要说信号干净置数法更优。实训项目里两种都能通过关键是你要能解释清楚为什么这么接。2.4 日历模块日/月/年计数器与闰年判断的组合逻辑这是整个项目最值得详细讲的部分也是最容易写崩的地方。日、月、年计数器各自都是模M计数器但“日”的模数是动态的取决于月份和闰年。先说月计数器和年计数器。月计数器从1计数到12用两片74LS160当计数到13时置1注意不是清零置0因为月份从1开始。我的做法是用反馈置数法当十位为1、个位为3时产生LOAD信号将十位置0、个位置1。年计数器从00计数到99也是两片74LS160比较简单但要把年的十位和个位送到一个“闰年判断”电路中去。闰年判断是组合逻辑它根据当前年份产生一个信号供月底判断使用。闰年判断的实现思路是这样的只判断年份后两位能否被4整除。为什么可以只看后两位因为100是4的倍数所以一个四位年份能否被4整除只取决于后两位。设年份十位为Y1个位为Y0那么年份N的末两位是10×Y1Y0又因为10 mod 42所以N mod 4等价于(2×Y1Y0) mod 4。能被4整除的条件是当Y0为0、4、8时Y1必须是偶数当Y0为2、6时Y1必须是奇数。用逻辑门实现这个条件需要把Y1的奇偶判断和Y0的取值判断结合起来。Y1是偶数说明Y1的bit0为0Y0为0/4/8表示Y0的bit1为0且bit0为00、4、8的二进制分别是0000、0100、1000共同点是bit1和bit0都为0Y0为2/6表示Y0的bit1为1且bit0为0。把这些条件写成布尔表达式LEAP (Y1.bit0 0) AND (Y0.bit0 0) AND (Y0.bit1 0) OR (Y1.bit0 1) AND (Y0.bit0 0) AND (Y0.bit1 1)化简后会发现判断的核心是Y0的bit1与Y1的bit0是否相等。这个用异或门就能做但我在实际电路中直接用了几片与非门搭出来的没有刻意化简因为芯片管脚够用。要提醒的是这个方法到2099年都是有效的因为2100年按公历规则不算闰年但咱们这个万年历只做到两位年份所以不用担心100年例外。日计数器是日历模块的核心。日计数器从1开始计数到月底时下一个脉冲回到1也就是说它不是一个从0到M的计数器而是从1到M的计数器。所以不能用简单的清零法必须用置数法把日计数器置成1。月底条件的判断是整个项目核心中的核心逻辑如下大月1、3、5、7、8、10、12当日期计数到31时翻月小月4、6、9、11当日期计数到30时翻月2月平年日期计数到28时翻月2月闰年日期计数到29时翻月。我用组合逻辑实现这个判断。月份要产生三个信号大月信号MONTH_BIG、小月信号MONTH_SMALL、二月信号MONTH_FEB。日计数器要产生两种判断日期是否等于30/31以及日期是否等于28/29。然后把它们组合起来月底信号 (MONTH_BIG AND DAY_EQ_31) OR (MONTH_SMALL AND DAY_EQ_30) OR (MONTH_FEB AND NOT LEAP AND DAY_EQ_28) OR (MONTH_FEB AND LEAP AND DAY_EQ_29)这个月底信号有两个用途一是作为月计数器的时钟或使能信号让月加1二是让日计数器在下一个脉冲到来时置为1。要知道这里为什么要用“置1”而不是“清零”因为日计数器的起始值是1不是0这是新手最容易犯的错误。我在实现日计数器时用了一个小技巧不需要真的去判断“等于30还是31”可以简化成“日期大于等于当月月底的天数”这个条件。但74LS160的输出是BCD码组合比较逻辑用门电路做也不复杂所以我直接按照上面的逻辑搭的。如果你觉得门电路太多也可以用74LS85四位比较器来做数值比较电路会清爽很多。2.5 译码显示74LS48驱动共阴数码管的接法计数器内部都是BCD码需要经过译码器变成数码管的段选信号。我用74LS48作为七段译码驱动器它输出高电平有效所以只能驱动共阴数码管。如果你用的是共阳数码管就要换74LS47或者加反相器这个千万不能搞错我见过有人把共阳的插到74LS48上结果数码管永远不亮。接线方面74LS48的A、B、C、D分别接计数器输出的BCD码D是最高位a~g输出接到数码管的对应段引脚。74LS48自带内部上拉电阻同时还有灯测试LT和灭零RBI/RBO功能实训中我直接把LT接高电平不需要灭零功能时把RBI接高电平即可。显示部分我采用的是静态显示方案14位数字每一位都单独用一片74LS48驱动也就是说14个数码管对应14片译码器。这样做芯片用量大但是电路简单可靠不用处理动态扫描的刷新时序问题。如果你想省芯片可以用动态扫描加位选信号的方式但那样要在扫描频率和显示亮度之间找平衡难度反而上去了。实训项目追求的是稳定可靠静态显示是最优选。3. 实操过程与调试记录3.1 仿真先行Multisim与Proteus的选型对比我之前一直用Proteus但这次做万年历我换成了Multisim。原因很简单Multisim的74系列芯片模型更贴近真实器件的时序特性特别是RCO、LOAD这些引脚的时序关系仿真结果基本就是实际芯片的行为。Proteus画原理图更舒服但有时候仿真通过的东西到实际面包板上跑不起来模型过于理想化是一个重要原因。仿真时一定要按模块搭不要一上来就把整个系统画完。我的顺序是先搭555秒脉冲用虚拟示波器看波形调整电位器让周期稳定在1Hz接着搭秒的模60计数用逻辑探针或者数码管看0到59的变化再搭分的模60、时的模24逐级确认进位关系最后才是日历模块和闰年判断。日历模块在仿真时有一个特别好的调试方法把555的秒脉冲暂时换成手动时钟源用一个按钮开关每次手动触发一个脉冲这样就能一步一步观察日计数器从1到月底、再翻月到1的过程。手动触发时一定要加消抖电路否则一次按键可能产生多个脉冲你会看到数字跳好几下然后误以为是逻辑错误。3.2 面包板搭建的接线原则电源、地线、去耦与防烧从仿真到实物是最容易翻车的一步。我先把所有芯片分布在面包板上规划好位置再开始接线。这里有几个原则供参考第一电源和地线要先铺好。面包板上下两排一般用作VCC和GND我用红色跳线走VCC黑色跳线走GND中间芯片的电源脚就近连接。74LS160、74LS48这些芯片都是引脚14接VCC、引脚7接GND接之前最好对着数据手册确认一遍不同型号管脚定义有细微差异。第二每个芯片的电源引脚都要并接一个0.1μF的陶瓷去耦电容电容要尽量靠近芯片。这个不是可选项是必须项。没有去耦电容的时候芯片翻转瞬间的电流冲击会造成电源电压波动严重时会让计数器产生误触发表现出来就是乱计数、乱进位查半天查不到原因。第三接线顺序上我先把时钟源接好然后用LED观察秒脉冲再依次接秒、分、时、日、月、年最后接译码显示。每接好一级就通电测试一级不要等全部接完再上电否则出问题你真的会疯掉的。3.3 分级上电调试从秒脉冲到日历翻月的完整顺序上电调试一定要有章法。我把自己当时的调试顺序整理如下供参考第一步测试1Hz秒脉冲。用示波器看555输出脚确认周期接近1秒高电平约2.8V以上TTL高电平标准是2V以上。没有示波器的话用LED观察正常应该一秒闪一次闪烁间隔稳定。如果LED不闪或者常亮先检查555的接法和电容是否接反电解电容是有极性的。第二步测试秒的模60计数。把秒脉冲接入个位CLK观察两位数码管从00到59循环。常见问题是个位正常、十位不走或者走两步就跳。这个问题十有八九出在同步级联的使能信号上重点检查RCO到ENT的连线。第三步测试分的模60和时的模24。为了让测试加快我把分和时的测试脉冲从秒脉冲临时换成手动脉冲几秒钟就能观察一个完整的进位周期。测试完毕再换回正常秒脉冲。第四步测试日历模块。这个阶段要特别关注月底翻月。我当时的做法是先用置数法把日期强行拨到月底前一天比如31号前一天然后手动加脉冲观察日期是否正确翻到下月1号同时月份是否加1。要分别测大月、小月、2月平年和2月闰年四种情况这样才能验证月底判断逻辑是完备的。第五步联调整个系统。上电后先手动校准到当前时间日期然后让它运行几分钟看时分秒运行是否正常日期翻月是否正常。我当时让它连续跑了一整个晚上第二天早上起来看日期已经自动翻了一天说明整个系统是稳定可靠的。4. 常见问题与排查技巧实录4.1 典型故障速查表做这个项目的过程中我遇到的问题基本可以整理成下面这个速查表建议收藏遇到类似问题先对照这个表排查。故障现象可能原因排查方法解决措施数码管完全不亮译码器型号与数码管不匹配查共阳/共阴极性共阴用74LS48共阳用74LS47秒脉冲有但秒计数器不走使能端ENT/ENP没接高万用表测使能脚电平将ENT、ENP接VCC59后变0但十位进位一次跳两个反馈清零信号毛刺严重示波器看清零脚波形改用同步置数或加去耦电容日期翻月后日变成0不是1日计数用了清零法检查置数端接线日计数必须置数到12月28号就直接跳到3月1号闰年判断逻辑错误逐个验证Y0、Y1条件重查闰年组合逻辑按键一下跳好几个数按键没有消抖示波器看按键输出加RC低通或使用RS触发器消抖芯片发烫电源接反或输出短路断电后万用表测电阻检查VCC/GND和输出负载运行几分钟后时间越走越慢555定时电容老化或温度漂移示波器长期监测频率换CBB电容或改用晶振分频4.2 毛刺与竞争冒险清零信号的隐形杀手在用反馈清零法实现模60和模24的时候毛刺问题是绕不开的。什么是毛刺简单说就是组合逻辑输出的一瞬间出现的不期望的窄脉冲。比如十位计数到5时与非门输出清零信号但这个信号在极短的时间内可能有抖动。74LS160是异步清零只要CLR脚出现低电平不管维持多久计数器都会立刻被清零。这就带来一个非常隐蔽的问题如果清零信号在5状态刚建立时先出现了一个极窄的毛刺计数器会提前被清零导致你看到的计数序列是0、1、2、3、0、1、2、3……而不是0到5循环。这种故障用LED观察时很难捕捉但用示波器或者逻辑分析仪看非常明显。解决毛刺的三个常用手段我都试过。第一个是增加去耦电容效果有限第二个是在清零线上并联一个小电容几十pF到几百pF可以滤掉高频毛刺但电容太大会拖慢清零速度第三个最稳妥改用同步置数法让LOAD信号在时钟边沿才起作用不给毛刺发作的机会。如果你在仿真里没问题、一上实物就乱优先考虑换同步置数。4.3 按键消抖的RC方案与RS触发器方案校时和校历功能必须用按键而按键抖动是必现问题。机械按键在按下和释放的瞬间触点会反复通断几毫秒到十几毫秒如果不做消抖一次按压会变成好几个脉冲日历直接快进到不知道哪一年去了。最简单的消抖方法是RC低通滤波加施密特触发器。按键一端接VCC另一端通过一个10kΩ电阻接GND同时并联一个10μF电容这样按键未按下时输出低电平按下后电容充电电压缓慢上升再经过施密特触发器整形输出干净的上升沿。这个方案的缺点是RC时间常数不能太大否则按键响应太慢。我在项目里用的是更经典的RS触发器消抖用两个与非门交叉耦合构成一个RS锁存器。按键接到R和S端按下和释放时RS锁存器会锁住第一个有效的电平变化完全消除抖动。这个方案在数电课本里就有正好和课程知识对应上而且不依赖电容值响应速度快。4.4 电源供电面包板上的“隐形地雷”我最后单独提一下电源问题。面包板供电我一开始用的是一根USB线转5V结果系统一动起来数码管亮度就开始不稳计数器也频繁出问题。后来用万用表一量5V在芯片翻转时波动能到几百毫伏这就是典型的供电能力不足。后面我换成了实验室的直流稳压电源限流1A稳定得很。如果你手上只有USB供电至少要做到两点一是尽量缩短电源线用粗一点的杜邦线二是在面包板电源轨的两端各加一个100μF的电解电容和0.1μF的陶瓷电容起到储能和滤波作用。数码管点亮时电流比较大14位数码管全亮起来峰值电流可能接近几百毫安供电一定要留足余量。5. 项目扩展用FPGA与Verilog重新实现万年历做完74芯片版本之后我其实还做了一版FPGA实现因为很多学校数电实验课开始在往FPGA方向转。这一节算是一个扩展思路给有兴趣的同学参考。用Verilog写万年历模块比搭面包板快得多而且逻辑清晰核心模块就是一个计数器加一个状态判断。顶层思路是先用分频器把开发板上的50MHz时钟分频得到1Hz脉冲。然后秒、分、时、日、月、年各定义成独立的计数变量时钟到达时递进。日计数器的递进条件同样要看月份和闰年用case语句判断当前月份的天数这个比搭门电路直观多了。一个简洁的日期递进伪代码逻辑大致是这样当日计数小于当月天数时日加1否则日回1月加1当月到12且日到月底时月回1年加1当年到99时回0。时分秒的进位逻辑同理。整个工程用状态机做统一控制比一堆计数器散着写要清晰得多。FPGA方案的典型优势是时序可控、逻辑修改方便、仿真速度快劣势是需要开发板和仿真工具对纯数电原理的体现不如74芯片直观。我的建议是课程要求用芯片搭电路的就老老实实搭时间充裕的情况下再用Verilog实现一版作为扩展练习对你理解数字系统的层次化设计非常有帮助。最后再分享一个小技巧这次实训最大的体会是做硬件项目最忌“一气呵成”。我亲眼见过同学花一个下午把所有线接完通电之后屏幕全乱然后拆掉重来来回折腾三四天。正确做法是每完成一个小模块就测试一个小模块测试完的性能和现象记录下来再接下一块。做万年历尤其如此因为模块多、信号多、相互依赖多分模块推进看起来慢实际上是最快的路径。另外一个很实用的小技巧调试日历部分时不要真的从1月1日开始一秒一秒等下去。我的做法是把秒脉冲换成手动脉冲手动把日期拨到月底前一天然后快速验证翻月逻辑。把日期拨到2月27日测平年28天再拨到闰年的2月28日测闰年29天。这样十分钟就能把所有边界情况测完而不是等上几个月。这个思路我没有在任何教程里看到过但实测非常高效分享给大家。
返回列表