似乎好久没有写新的博文了。由于今年的春节较往年要早,近一个月来,各门考试接踵而至让我忙得不可开交。虽然非常赶,终于还是考完了。当初想都不敢想的13天考10门的考试周也就这样熬过去了。事实证明,即便是很大的困难,逼一下自己还是能挺过来的。不过最后还是和往年的冬天一样发了个一年一度的高烧,真的难受,以后还得更加注重自己的身体。
废话不多说,这几天就打算先把这学期期末阶段一些有意义、有价值的的知识与经历整理记录一下。首先是一个运动码表的大作业,本文主要是使用Logisim对运动码表进行实现的方法与过程。
需求分析
该项目要求我们设计一个简单的运动码表,包括四个按键组成的输入模块和四个7段数码管组成的输出模块。四个按键分别是:Start,按下时计时器归零并重新开始计时;Stop,按下时停止计时并显示计时数据;Store,按下时尝试更新系统记录,要求记录当前码表值,若已有记录,则和当前待记录的值作对比,如果计时数据比记录数据要小即用时要短,则更新系统记录并显示;Reset,按下时进行复位,将计时数据置为00.00,系统记录置为99.99。
Logisim使用
在具体说明实现的方法之前,我想先把之前整理的一些Logisim的基本使用做一个简短的总结。Logisim的使用其实不难,可以参考网上整理的Logisim文档翻译就可以快速入门。实际上,在具备一定数字电路知识的情况下,到处点点也能够学会Logisim的基本使用方法。
Logisim为数字电路的设计提供了很大的帮助,我们可以通过填写真值表或者输入逻辑函数快速生成原本手动连线根本无法完成的复杂电路。
如果想要获得Logisim最新的优化版本,可以加入华科谭志虎教授创建的计算机硬件系统设计交流群(群号:957283876),此群汇集了多个高校的学生,是一个比较活跃的技术交流群,谭教授秒回且超赞的解答真的忍不住让人点赞!下面是一些我当初刚使用时记录在note上的一些Logisim的使用与常见处理,分享在此。
引脚
在Logisim中,引脚即Pin,可以使用键盘上、下、左、右光标键来改变引脚的朝向。
注意:这里该表朝向不是按照旋转方向来的,而是按哪个方向就是指向哪个方向。
此外,根据形状的不同,引脚分为输入引脚(较方)和输出(较圆)引脚,可以使用UI左上角最左侧的手型的戳工具点击对应的引脚来修改引脚的值(高电平、低电平、未知x态)。
当我们选中引脚时,按下alt+数字组合,就可以改变到对应的位宽。与门
选中与门,按下数字键,就修改输入引脚个数。线颜色的含义
- 亮绿色:高电平。
- 深绿色:低电平。
- 蓝色:未知状态。
- 灰色:飞线。
- 红色:信号冲突。
- 黑色:多位总线。
- 橙色:位宽不匹配。
时钟
- ctrl+K:驱动与关闭时钟连续运行。
- ctrl+T:驱动时钟单步运行。
其它快捷键
上面列出的都是一些并比较典型的特例,别的地方使用基本类似,可以多多尝试。下面再列出两个比较常用的快捷键:- ctrl+D:创建副本。
- ctrl+Z:撤销。
整体设计
为了实现运动码表的功能,我们将整个项目拆分成如下几个模块:
- 计时模块(包括计时使能模块)。
- 码表驱动与显示模块。
- 系统记录数据寄存模块。
- 码表状态功能控制模块。
- 数值比较模块。
- 数值选择模块。
此外,根据需求分析,我们设计了如下6个状态,并构建状态机如下:
- 000 中间态:每次按键弹起后,回到该状态。
- 101 复位:计时变成00.00,记录变成99.99,显示计时数值,时钟不计时。
- 001 计时:计时变成00.00,记录不变,显示计时数值,时钟计时。
- 010 停止:计时不变,记录不变,显示计时数值,时钟不计时。
- 011 更新(小于系统记录NewRecord=1):计时不变,记录变成计时,显示记录数值,时钟不计时。
- 100 不更新(大于等于系统记录NewRecord=0):计时不变,记录不变,显示记录数值,时钟不计时。
可得状态转换关系的真值表如下所示:
为了实现上述状态转换与控制信号输出,我们设计了如下码表控制电路。
其中SD-EN控制寄存器使能,DP-SEL控制码表显示数值的选择,TM-Reset控制是否复位。
设计实现
这是设计完成后最终circ文件中所包含的内容,下面我简述一下各个模块中的内容及思路。
数码管驱动:即将4位2进制数转化成7个二进制信号,驱动7段数码管的亮灭。
4位BCD计数器:基于下面的BCD计数器状态转换(即在0-9之间递增循环)和BCD计数器输出函数(即在达到9时输出进位信号)。
码表计数器:由四个4位BCD计数器组成。
码表显示驱动:即将四个4位二进制组成的数字通过四个7段数码管显示出来,内部基于上面的显示驱动转换电路即数码管驱动的封装。
码表控制器:上文的设计中已经提及,基于码表控制器状态转换(输入信号+现态->次态)和码表控制器输出函数(现态->控制信号)。
计时使能:这里我比较巧妙地运用了D触发器的置位清零两个端,将在后文提及。
最后就是运动码表的总电路图:
遇到的问题
复位后自动开始计时
这是最让我头疼的一个问题,由于上述状态机的设计方法和Logisim中按键在鼠标松开后自动弹起的功能,导致在我按下Reset清零后系统会自动重新开始计时(因为这时的现态已经不是复位状态),这显然是不符合需求的。为了使计时使能在下一次按键到来之前能保持现态,我将复位控制信号从状态转换电路中单独取出,并使用一个D触发器的置位清零两个端子实现了这个保持功能,效果不错。计时器遇到9时跳跃进位
当最初的电路实现完成后,我兴奋地开始计时,结果计时器的花式进位方式顿时让我傻了眼。仔细研究后我发现,我起初设计的电路在进位时只考虑了低一位计数器传来的进位信号,而事实上,高位的进位条件往往是由后几位共同决定的,为此,修改电路如下: 问题解决。码表在更新数据的前一个时钟内会显示较大的记录数值
这个问题其实不是非常重要,但同班的一位同学还是注意到了这点。也就是说,当计时数据比系统记录要小的时候,系统应该更新记录并显示最好的成绩,然而当按下Store进行存储更新时,在前一个时钟周期内,码表会短暂地先显示原本较大即较差地系统记录,这是不希望出现的。
解决的办法可以在寄存器和显示选择器之间添加一个三态门,具体可以看上文中的总电路图。
实现
看到评论区有许多同学似乎有一些困难无法解决,因此我在此提供了我最后实现的百度网盘链接,提取码为e8i1。
注意:文件中包含logisim和运动码表的电路文件。我在当初实现时,一些模块是直接使用了库中已有的器件,并没有全部从最基础的器件开始实现。此外我的思路和华科谭志虎教授的慕课在细节上也有稍许不同,一些要点都已写在本篇文章中了。本人的实现仅供参考,如是学校作业,还需根据具体要求进行调整或者修改。