【精品博文】FPGA的计算器设计——逐位输入与输出控制模块

之前写了两篇关于计算器的模块,一个是键盘扫描,一个是数码管消零,今天我总结一下第三个模块,也就是标题写的逐位输入与输出控制模块。我们平时使用过计算器都应该了解,我们每按一个键,显示屏上就多一个数,并且新输入的键放在了最低位,以前输入的数依次左移,在输入操作符的时候,显示的数保持不变,输入第二个操作数的时候,第一个操作数被清空,显示屏显示第二个操作数。

相信很多人都会开始觉得这不很简单吗?不就是移位吗?像流水灯一样。没错,但是如果你觉得它和流水灯一样简单,你就大错特错了。这个模块的难点不在于移位操作,而在于它的时序关系。当然这个实验还不涉及到时序约束的问题,只是你怎么保证,你按下一个键,数码管就不多不少,不迟不早的显示你按下的键。这才是问题的关键所在。

我记得,我第一次调试的时候,按下第三个键,才能显示第一个按下的数字,由此可见,我当时的输出是比我的输入慢了2拍的,甚至有人估计会遇到按一个键,满屏都是这个键所代表的数字。这些都是什么原因呢?

首先回顾一下,我在按键扫描中做了一件事,那就是每确认有键按下,就输出一个flag,这个flag的作用就是避免按一次键,出现满屏相同的数字,因为我们按键按下的时间一般是20ms以上,我用来驱动这个控制电路的时钟和按键扫描的时钟都是用的1khz,就是为了保证flag传过来的脉冲宽度,如果没有这个flag,控制电路检测到按键按下的次数就是20+次了。而这个flag,我是检测的按键弹起的瞬间,至于为什么,我在前面键盘扫描的时候已经解释过了,不了解的可以回头看一下。

http://blog.chinaaet.com/yocan/p/5100018107

具体怎么实现,我们还是先来贴代码吧。

这是整个控制部分的代码,代码量不是很多,主要的核心部分是一个两段式的状态机。我定义了两个变量num_reg1和num_reg2用来保存两个操作数,opcode_reg用来保存操作符,在一个每个时钟下只有一个操作数能通过num_out输出到数码管。需要注意的是,我们这里输入的操作数是暂时以BCD码的形式保存,在进行计算时,还需要将BCD转换成二进制或十进制数进行运算。但是数码管是以BCD的形式接收数据和显示的,所以不用考虑BCD转二进制的问题(当然你也可以令数码管以二进制的形式接收数据并显示,我在数字钟的实验中就是以二进制的形式来接收数据和显示的,这个需要和其他模块进行相应的配合,看怎样比较合适就进行怎样的设计)。

在状态机中,S0状态下,接收第一个数据,通过检测接收到的数据是0-9还是a-d,来判断第一个操作数是否输入完毕,在输入操作数的时候,通过循环移位的方式,来把输入的操作数保存在num_reg1寄存器中,至于操作数的输出,我是通过组合逻辑的方式,把num_reg1,传递给了num_out。

至于为什么用组合逻辑呢?如果你用时序逻辑,在num_reg1 <= {num_reg1[19:0],key_value};之后,再num_out <= num_reg1的话,会是一种什么现象?由于这里,我们给了一个按键按下的flag限制,所以在第一个按键按下的时候,num_reg1的低4位会得到当前按下的键值,但是由于是时序逻辑和非阻塞赋值,所以赋给num_out的值此时还是为0。当下一个按键到来的时候,num_out的值才会被赋予第一个按键的值。所以这里就会慢一拍了,加上前面在矩阵键盘扫描里慢下的那一拍,就是为什么我第一次调试的时候慢了两拍的原因。(像这里需要与按键配合调试,不太好写testbench的情况,我推荐大家用signaltap或者chipscope来调试)

在S0状态,如果检测到a-d的键按下,说明输入的是操作符,我们先把操作符保存在opcode_reg中,而不是马上输出,先让状态跳转到S1。因为可能存在误输操作符的情况,在S1状态如果继续输入操作符,那么我们就更新操作符寄存器。如果是输入的0-9,那么代表着第二个操作数开始输入,我们类似对操作数1的处理,把第二个操作数保存起来,直到检测到等号,跳转到S3状态,S3状态直接把计算结果赋给第一个操作数。很多人也许会惊讶,为什么要这样做?我来解释一下这样做有几点好处:

1,输出的处理变得简单,代码中有红色下划线的地方就是决定输出哪个信号,一句话就搞定;

2,可以实现连续运算,如果得到计算结果后,我继续输入的是操作符,那么状态跳回S1,可以继续计算;如果继续输入的是操作数,则表示用户自己放弃连续运算,状态调回S0,重新开始新一轮计算(具体请看S3)。

总结一下,这段代码有几点比较好的地方:

1,状态机状态比较少,各状态之间关系简单明了,我相信很多人写计算器第一反应估计会罗列出4,5种状态,先要输入第一个操作数,然后操作符,然后第二个操作数,然后等号,可能还有一个初始态。这样当然也能实现,只是状态越多,状态之间的跳变就会越复杂。

2,输入输出关系简单明了,我曾经也纠结过怎样建立num_out和各个操作数以及运算结果之间的联系,目前这种方式,是我能想到的最简单有效的方式了,希望能给需要的人一点帮助。

计算器模块还剩最后一个模块了,就是计算以及BCD和二进制之间的转码了,这个控制模块只是实现了最基础的功能,就是正整数的输入,如果要实现负数和小数的运算,这个模块还需要做很大的改动,有兴趣的可以自己思考一下,我会在写下一个模块的时候上传整个工程的代码。小数部分我也只是实现了定点小数而已,浮点小数好像真的挺难的,最近培训,每天安排都很满,继续优化计算器了。这周在做一个IIC控制EEPROM的读写,等把计算器写完了就开始写IIC。

(0)

相关推荐

  • 二进制转BCD码

    应用: 用fpga实现对数码管显示,以前通常的方法是进行整除和取余进行运算,但是fpga并不擅长乘法除法运算,所以可以用BCD码来转换. BCD码:通俗的可以理解为用四位二进制数表示一位十进制数字.例 ...

  • 基于有限状态机的PLC程序设计方法

    云南民族大学电气信息工程学院的研究人员范雄涛.沈勇.和淑芬,在2018年第2期<电气技术>杂志上撰文指出,在PLC程序设计中,通常需要考虑系统可靠性和实用性,同时需要满足其工艺要求,以及对 ...

  • 【蓝桥杯】【入门题】【算法提高VIP】1480:模拟计算器

    题目 1480:模拟计算器 蓝桥杯刷题群已成立,微信后台回复[蓝桥杯],即可进入. 如果加入了之前的社群不需要重复加入. 时间限制: 1Sec 内存限制: 128MB 1. 题目描述 使用Switch ...

  • Java语言程序设计与数据结构(基础篇)第3章 选择笔记

    文章目录 Java语言程序设计与数据结构(基础篇)第3章 选择笔记 1.常见错误1:忘记必要的括号 2.常见错误2:错误地在if行出现分号 3.常见错误3:对布尔值的冗余测试 4.常见错误4:悬空el ...

  • 【精品博文】基于FPGA的计算器设计——(数码管消“0”)

    我在上一周做了一个数字钟的实验,当时也用到了数码管,我的开发板上有6个数码管,正好2个给小时,2个给分钟,2个给秒.每一个数码管都有自己的任务,所以就不用考虑消"0"的问题了.但这 ...

  • 【精品博文】基于FPGA的计算器设计一(矩阵键盘模块)

    这周做了一个计算器的实验,目前可以正负实现数的加减乘除,以及定点小数的加减乘除,精度不高还在进一步完善,今天先把矩阵键盘扫描的模块总结一下,明天继续优化. 这是一个大概的模块划分和数据流向图,我们首先 ...

  • 【精品博文】ARRIA10开发设计要领

    估计大概明年很多人就会用arria10做网络平台加速了,还有安防的视频加速算法,无线小基站,或者arria10做机器视觉平台.这些都是明年2018的可能要做的事情. arria10虽然吹了这么几年,但 ...

  • 【精品博文】spartan6 硬件设计笔记

    用spartan6主要是想利用它的差分收发器做一些应用,那么这里就需要注意lvds引脚,任何io bank都可以用作lvds 输入,但是lvds 输出引脚只能从bank0 和bank2 中选择. 可选 ...

  • 【精品博文】做算法设计的FPGAer应该多用VHDL

    VHDL似乎快被FPGA/ASIC界遗忘了.不说ASIC那几个工具本来就不待见VHDL,越来越多的高校也采用与C形似的verilog进行教学,各个论坛讨论群里常见的问题或者求助绝大多数也是以Veril ...

  • 【精品博文】高级FPGA设计——第五章:复位电路

    复位极端重要,但是却常常容易被忽略.在这一章,我们就来聊聊复位的事. 1,同步复位和异步复位 众所周知,复位操作包括同步复位和异步复位.我们先来了解下两者存在的问题. 1.1 完全异步复位的问题 完全 ...

  • 【精品博文】高级FPGA设计——第四章:跨时钟域问题

    在FPGA设计中,不太可能只用到一个时钟.因此跨时钟域的信号处理问题是我们需要经常面对的. 跨时钟域信号如果不处理的话会导致2个问题: (1) 若高频率时钟区域输出一个脉冲信号给低频率时钟区域,则该脉 ...

  • 【精品博文】高级FPGA设计——第三章:功耗结构设计

    除了速度和面积外,数字设计中还有另外一个主要特性:功耗. 在CMOS技术中,动态功耗与门和金属引线的寄生电容充放电有关.在电容中消耗电流的一般方程为:I=V*C*f (其中I是总电流,V是电压,C是电 ...

  • 【精品博文】高级FPGA设计——第二章:面积结构设计

    在上一章中,我们提到速度是FPGA设计中的重要特性,现在要说说另一重要特性:面积. 面积过大意味着成本的提升,对FPGA以及ASIC都是如此.因此,我们需要竭力控制面积,可采用以下方法: 1,折叠流水 ...