如何设计一个电子计算器

  版权申明:本文为博主窗户(Colin Cai)原创,欢迎转帖。如要转贴,必须注明原文网址

  http://www.cnblogs.com/Colin-Cai/p/8185972.html 

  作者:窗户

  QQ:6679072

  E-mail:6679072@qq.com

  首先,不要误解,我这里的计算器是指硬件的计算器,至于纯软件的计算程序,乃至有高级功能的,比如可以求解方程甚至可编程之类,我以后找个时间来说说。这两天看到有人在博问里问类似的问题,原问是想设计一个有着数码管、有着4x4键盘的硬件里的程序,不知道他具体想做什么,只是给了一些建议。联想到还有计算器这个东西,这应该很容易作为电子工程或者微电子专业的一个作业的形式出现。以前我招实习生的时候,似乎也曾经叫其实现过计算器。这里给出一点方案,以供参考。

  硬件

       

  框图如上,主要有4大模块,电源、控制、按键矩阵、数码管。

  电源有多种方案,简单点可以用电池或者usb,这里不作详细讨论。

  数码管采用共阴或共阳,每一位一个片选,选个6位的,一共14个引脚,都接在控制模块IO引脚上,注意控制信号电平,必要的时候阳级接上拉电阻。

  键盘矩阵则是以下电路这样的东西,由一堆按键组成,键盘矩阵对外8个信号都接在控制模块的引脚上。另外,如果控制模块的引脚无法配置上拉或下拉电阻,那么PD0/PD1/PD2/PD3或者PD4/PD4/PD6/PD7/PD8就要接上拉电阻,这涉及到键盘矩阵的检测原理。

  

  控制模块,就看想用什么编程了,如果想用单片机,可以选择经典的51单片机、AVR单片机、PIC单片机都可以,STM32当然可以,只是ARM可以做远比这个复杂的事情,没必要杀鸡用牛刀。当然,想学学ARM特别是STM32的编程,可以用STM32。PIC单片机和51单片机我只玩过汇编,不过现在单片机支持C语言都支持的蛮不错,建议还是C语言编程。

  当然,也有想玩玩数字设计的,那么cpld对于这个需求是合适的,没必要上FPGA,可以用很早以前的,价格也便宜。对于资源多少没有把握的话,你也可以先做数字设计,再来选器件。

  固件

  硬件设计好了之后,需要设计固件。

  如果控制模块选用的是单片机,那么我们一般是在裸机下编程,对于这几款单片机我似乎只玩过汇编,但现在都21世纪了,我想至少也应该用C语言来玩玩。

  我们首先要明白数码管和键盘矩阵的原理:

  数码管相对简单一些,一般来说,数码管每一位显示的数字都不一样。如我图中的共阴6位数码管,当要显示某位的时候,片选信号选择是拉低,其他片选拉高,然后再把要显示的数字所要点亮的管的引脚拉高,这样,要显示的这一位就显示出了数字,而其他的几位没有任何显示。然后快速切换,每一位都显示该显示的数字,那么根据视觉暂留,我们就看到了完整的显示。

  键盘矩阵可能要复杂那么一些。首先,我们假设我们这里PD5、PD6、PD7、PD8都被我们接了上拉电阻,并且IO都为高阻接收状态,而不输出。我们这里只考虑一个键的识别,其实键盘矩阵也可以识别多个键。我们想一想,如果某个键按下去,比如左上角的S3按下之后,会发生什么。在按下去之前,PD1、PD2、PD3、PD4和PD5、PD6、PD7、PD8之间并不联通。但当S3按下去,PD1和PD4连在了一起。如果控制模块把PD4的输出射为高阻状态,那么如果PD0输入低电平,那么PD4读取出来的应该为低电平,否则为高电平。于是我们把PD1、PD2、PD3、PD4这4个引脚每次只其中一个输出低电平,其他三个输出高阻状态,每次都去读取PD5、PD6、PD7、PD8,那么就可以根据数值来判断到底是哪个按键被按下。注意,此处PD1、PD2、PD3、PD4这4个引脚每次只其中一个输出低电平的时候,其他三个不能输出高电平,而应该是高阻,否则,如果有两个按键被按下,则为短路状态!

  另外要考虑按键的抖动问题,有多种解决方法,比如可以在判断到一次按键按下之后0.3秒内不重复判断按键被按下。

  既然数码管的显示需要定时去切换显示位,而键盘矩阵也需要定时去切换输入,那么我们就可以设置一个定时器,把这两个硬件的处理都挂在同一个定时中断例程上作为驱动层,其逻辑使用上述的原理来实现,可以每次中断给一个循环计数作为状态,做一个moore机简单明了,至于0.3秒内不重复在交互里体现即可。程序中实现驱动层和应用层的层次分离,无论从调试硬件还是设计固件来说都是必要的,当然你也可以分的更细,比如HAL层。当然,非要在这里把所有的一切糅合在一起也是能够最终搞定的,但层次感差很多,并且一个初学者真的设计不好一个大的状态机。

  设计一些全局变量用来应用层和驱动层交互显示数据和所按按键。

  unsigned char num[6] ;//应用层写,驱动层读,用于6位数据的显示

  unsigned char flag;//flag=0的时候,驱动层可以设置key,并把flag设为1;flag=1的时候,应用层可以读取key,并把flag设置为0

  unsigned char key;//以代表是哪个键按下,分别给0、1、2、3、4、5、6、7、8、9、+、-、*、/、=、退格编码为0~15

  以上数据有冗余,在RAM极端受限的情况下,可以裁剪数据。

  而至于计算器所要实现的最高6位加减乘除,很容易实现,根本不需要大数计算,结合显示和按键,构成应用层程序,想想一个计算器的功能,你应该很容易的画出流程图,不是吗?

  如果作为学生,你选择的是cpld/fpga,我也支持你,我觉得一个可以自己独立做出来的学生应该还是不错的,但也和之前处理器的程序实现类似:分别设计键盘驱动模块、数码管驱动模块、计算模块,最后中间有一个核心模块以一个状态机形式存在,与其他三个模块都相连。当然,每个模块内部也可以分小模块,比如数码管模块里面最好把解码器单独实现一个小模块,而计算模块里加减乘除都是单独的小模块。

  

原文地址:https://www.cnblogs.com/Colin-Cai/p/8185972.html