2024年寒假练 - 基于小脚丫FPGA套件STEP BaseBoard V4.0设计两位十进制加、减、乘、除计算器
该项目使用了小脚丫FPGA套件STEP BaseBoard V4.0,实现了两位十进制加、减、乘、除计算器的设计,它的主要功能为:运算数和计算结果通过8个八段数码管显示。每个运算数使用两个数码管显示,左侧显示十位数,右侧显示个位数。输入两位十进制数时,最高位先在右侧显示,然后其跳变到左侧的数码管上,低位在刚才高位占据的数码管上显示。。
标签
FPGA
open-os
更新2024-04-01
中国计量大学
191

两位十进制加、减、乘、除计算器设计

image.png

实验任务

·       项目任务:实现一个两位十进制数加、减、乘、除运算的计算器,运算数和运算符(加、减、乘、除)由按键来控制,4×4键盘按键分配如下图所示。

image.png


·       普通列表项目要求:运算数和计算结果通过8个八段数码管显示。每个运算数使用两个数码管显示,左侧显示十位数,右侧显示个位数。输入两位十进制数时,最高位先在右侧显示,然后其跳变到左侧的数码管上,低位在刚才高位占据的数码管上显示。

·       解析:通过FPGA编程驱动矩阵键盘电路,获取操作信息,设计一个计算模块根据矩阵键盘操作信息控制计算逻辑(包括加减乘除),最后驱动数码管显示计算过程和结果。

实验目的

本实验主要学习独立显示数码管的驱动原理及方法,矩阵键盘的原理及驱动设计,。

·       掌握独立显示数码管驱动模块的应用

·       掌握状态机FSM的编程方法

·       掌握矩阵键盘的工作原理

·       完成FPGA两位十进制加、减、乘、除计算器的设计实现

设计框图

根据前面的实验解析我们可以得知,该设计可以拆分成5个功能模块实现:

·       input_key_board:通过驱动矩阵键盘工作获取键盘的操作信息数据。

·       bin2bcd通过编码方式将数码管要显示的信息译码成对应的bcd码。

·       segment_led:通过驱动核心板独立数码管将键盘按键的键值显示在数码管上。

·       segment_board:通过驱动串转并芯片74HC595控制数码管扫描显示计算数据。

·       function_count:根据按键的操作信息计算相应结果

顶层模块main通过实例化几个子模块并将对应的信号连接,最终实现两位十进制加、减、乘、除计算器的总体设计。
image.png

图 1 设计思路

实验原理&仿真验证

键盘类型

嵌入式设计中常见的键盘有两种类型,独立键盘与矩阵键盘,

image.png

图 2 独立键盘与矩阵键盘

·       独立式按键:每个按键单独连接到一个I/O口上,通过判断按键端口的电位识别按键的操作,编程简单,需要更多I/O资源

·       矩阵式按键:通过行列交叉编码连接,通过分时扫描的方法识别按键的操作,节约I/O资源,编程相对复杂。在键盘中按键数量较多时,为了减少I/O口的占用,通常将按键排列成矩阵形式,使用行线和列线分别连接到按键开关的两端,通过4根行线和4根列线(共8个I/O口)连接16个按键。

这里我们以STEP BaseBoard 4.0底板上的4×4矩阵键盘为例,其电路图如下:

image.png

图 3 STEP BaseBoard 底板上的4×4矩阵键盘

上图为4×4矩阵按键的硬件电路图,可以看到4根行线(ROW1、ROW2、ROW3、ROW4)和4根列线(COL1、COL2、COL3、COL4),同时列线通过上拉电阻连接到VCC电压(3.3V),对于矩阵按键来讲:

·       4根行线是输入的,是由FPGA控制拉高或拉低,

·       4根列线数输出的,是由4根行线的输入及按键的状态决定,输出给FPGA

当某时刻,FPGA控制4根行线分别为ROW1=0、ROW2=1、ROW3=1、ROW4=1时,

·       对于K1、K2、K3、K4按键:按下时对应4根列线输出COL1=0、COL2=0、COL3=0、COL4=0,不按时对应4根列线输出COL1=1、COL2=1、COL3=1、COL4=1,

·       对于K5~~~K16之间的按键:无论按下与否,对应4根列线输出COL1=1、COL2=1、COL3=1、COL4=1,

通过上面的描述:在这一时刻只有K1、K2、K3、K4按键被按下,才会导致4根列线输出COL1=0、COL2=0、COL3=0、COL4=0,否则COL1=1、COL2=1、COL3=1、COL4=1,反之当FPGA检测到列线(COL1、COL2、COL3、COL4)中有低电平信号时,对应的K1、K2、K3、K4按键应该是被按下了。 按照扫描的方式,一共分为4个时刻,分别对应4根行线中的一根拉低,4个时刻依次循环,这样就完成了矩阵按键的全部扫描检测,我们在程序中以这4个时刻对应状态机的4个状态。

矩阵键盘驱动设计

将矩阵键盘的扫描周期分为4个时刻,对应4个状态,使得状态机在4个状态上循环跳转,最终通过扫描的方式获取矩阵键盘的操作状态。

image.png

图 4 状态转换思路

image.png

图 5 矩阵按键仿真-无杂波无边沿检测

如上图,我们使用上面的方案,利用仿真工具检测到了按键按下的动作。其中第一行为时钟信号,我们为了仿真方便,将晶振时钟作为按键扫描的时钟。第二行为复位信号,可以看到有一个下降沿后,数据被置为初始值。第三四行为行列信号,我们分tb文件中设置某个按键一只按下。第五行位keyout输出结果,可以看到经过一个扫描周期后,成功做出了按键按下的对应反应。

但是按键是会抖动的,所以我们还要想办法对采集回来的数据做一些判定。

image.png

上图是市面上常见按键抖动的模型,有三个参数,按下抖动10ms以内,松开抖动10ms以内,按键周期数百ms;前面说过键盘的采样周期为20ms,可以得到以下结论:

·       按键周期内至少有4个FPGA采样点同时落在按键稳定区域内

·       按键周期内不会有相邻FPGA采样点同时落在按键抖动区域内

·       如果FPGA连续两次采样到低电平即可判定按键按下,否则判定为按键松开

 

但是按键按动这种长时间事件,这样得出的信号是不能直接使用的,这样一来我们最好将按键按动这种长时间事件转化成一个瞬间的脉冲,方法就是对key_out信号中的每一位进行下降沿(或上升沿)检测,方法如下:

下降沿检测程序实现如下:

assign key_pulse= 前一周期 & ( ~当前周期);   //通过前后两个时刻的值判断

经过上面程序的处理,我们就得到了16位脉冲信号,平时为低电平,当按键被按下时刻key_pulse产生一个高脉冲,脉冲的宽度为模块系统时钟clk的一个周期。

image.png

图 6 矩阵按键仿真-无杂波带边沿检测

如上图,我们使用上面的方案,利用仿真工具得出经过边沿检测后的信号。其中第一行为时钟信号,我们为了仿真方便,将晶振时钟作为按键扫描的时钟。第五行位keyout输出结果,可以看到经过一个扫描周期后,成功做出了按键按下的对应反应。第六行为下降沿检测信号,可以看到当第五行信号1→0时,对应的第六行信号0→1,并且仅仅持续一个周期。

数码管连接方式

实验平台的扩展板卡上的8位数码管,根据驱动方法不同,有以下比较:

image.png

图 7 数码管独立显示

独立显示:控制每个数码管至少需要8个I/O口控制,8位数码管就需要8*8 = 64根信号线才能分别显示。独立显示实现简单,但是需要大量的信号线。

image.png

图 8 数码管扫描显示

扫描显示:将每位数码管的同一段选信号连接在一起,这样我们就只需要8根段选信号和8根位选信号,共计16根信号。扫描显示可以有效节约I/O口资源,实现起来稍显复杂。

数码管模块电路连接

image.png

数码管模块驱动设计

74HC595是较为常用的串行转并行的芯片,内部集成了一个8位移位寄存器、一个存储器和8个三态缓冲输出。在最简单的情况下我们只需要控制3根引脚输入得到8根引脚并行输出信号,而且可以级联使用,我们使用3I/O口控制两个级联的74HC595芯片,产生16路并行输出,连接到扫描显示的8位数码管上。

image.png

image.png

image.png

根据74HC595内部结构及时序图可以得知,SHCP(SCK)每个上升沿都会将DS(SER)的数据采样到8位移位寄存器中,当STCP(RCK)上升沿时,8位移位寄存器中的数据被所存到8位锁存器中,同时对应Q0~Q7管脚刷新对应输出。对于我们的硬件,我们首先通过SHCP(SCK)和DS(SER)配合将需要传输的16位数据输出,然后控制STCP(RCK)产生上升沿,所以我们需要至少16个SH_CP(SCK)周期完成1次数码管控制。

8位数码管刷新1次需要8个数码管各点亮1次,每个数码管点亮1次需要16位数据,16位数据通过串行方式传输给74HC595需要至少16个SHCP(SCK)周期,按照我们前面说的数码管刷新率达到125次/秒,扫描方式下每个数码管会点亮1毫秒,数码管点亮的时间应该等于1次数码管控制的时间,也就是16个SHCP(SCK)周期,所以我们可以控制74HC595的SHCP(SCK)时钟周期计算: SHCP(SCK)周期 = 1ms / 16 = 62.5us 即是说,当 SHCP(SCK)周期小于62.5us,刷新率就应该大于125次/秒(注:以上为估算的结果) 为了计算方便,我们就取SHCP(SCK)周期为50us,那么触发74HC595串行驱动执行的敏感变量周期应该为25us,我们可以通过分频产生周期为25us时钟触发完成以上所以操作。

image.png

系统总体实现

当外设矩阵键盘(数据输入和运算符输入)和独立按键(复位)有输入时,引起一个时钟周期的数据变化,经过功能模块的译码和判断在8位数码管上面显示数字,

当第一个数字的个位数输入时8位数码管显示如下□■.□□.□□□□;

当第一个数字的十位数输入时8位数码管显示如下■■.□□.□□□□;

当运算符输入时,仅在核心板上面显示数字(01代表+02代表-03代表X01代表/;

当第二个数字的个位数输入时8位数码管显示如下■■.□■.□□□□;

当第二个数字的十位数输入时8位数码管显示如下■■.■■.□□□□;

当按下等号时,系统会判断输入正确与否,如果错误,将会执行复位操作,如果正确将会显示结果:

如果结果是个位数则8位数码管显示如下■■.■■.□□□■;

如果结果是十位数则8位数码管显示如下■■.■■.□□■■;

如果结果是百位数则8位数码管显示如下■■.■■.□■■■;

如果结果是带余数则8位数码管显示如下■■.■■.AABBAA代表商,BB代表余数)。

附加功能:设上一步运算结果为n,满足0<n<100,则可以进行下一步运算:直接输入运算符,和被操作数即可得出结果。

功能的设计框图如下:

image.png

重要代码讲解

顶层模块:
// Module: main
// Author: cjlu_wsj
// Description: 二位十进制计算器
module main (
               input                                                         clk,                           //系统时钟 12MHz
               input                                                         rst_n,                         //系统复位 低有效
               input                          [3:0]                          col,                           // 列扫描信号
               output                         [3:0]                          row,                           // 行扫描信号
              
               output                         [8:0]                          seg_1,                         //MSB~LSB = SEG,DP,G,F,E,D,C,B,A
               output                         [8:0]                          seg_2,                         //MSB~LSB = SEG,DP,G,F,E,D,C,B,A
              
               output                                                        seg_rck,                       // 74HC595的RCK管脚
               output                                                        seg_sck,                       // 74HC595的SCK管脚
               output                                                        seg_din                        // 74HC595的SER管脚
);

该代码段主要讲了调用了哪些引脚,分别为时钟输入,复位按键,矩阵键盘的行列扫描,核心板的数码管,以及控制主板数码管显示的芯片接口。

function_count:
// Module: function_count
// Author: cjlu_wsj
16'h0008:begin
if(symbol==0)symbol<='d4;//第一次计算
else if(symbol==4) state<=2;//出错处理
else if(result>=100) state<=2;//出错处理
else begin symbol<='d4; data1<=result;data2<=0;flag<='d0;dat_en_1234<={result>10,1'b1,2'b00}; end //连续计算
end //÷
16'h4000:begin
flag<='d1;//按下标志
case(symbol)
0:state<=2;//出错
1:result<=data1+data2;
2:result<=data1-data2;
3:result<=data1*data2;
4:state<=1;//跳转到除法运算
endcase
end //=

上面代码是用于计算的moudle一部分,一部分是当除法按下的一瞬间,检测当前是否进行过运算,并执行出错判断和处理。第二部分是按下=后,检测当前是否进行过运算,并执行出错判断和处理,如果是+-x则直接输出结果,如果是除法,跳转到另一部分处理。

case(state)//状态机

0: begin//按键扫描
case(scan_pulse)
.........//按键处理
endcase
end
1: begin//除法运算
data3<=data1/data2;
data4<=data1%data2;
state<=0;
end
2: begin//错误&复位
dat_en_1234<='b0000;
dot_en<='b0101_0000;
data1<=0;data2<=0;data3<=0;data4<=0;
symbol<=0;result<=0;flag<='d0;
state<=0;
end
endcase

上面代码是用于计算的moudle一部分,当状态机跳到1时,进行除法运算,计算出余数和商。当状态机跳到2时(出错),进行复位操作。

Design Summary(设计资源占用报告)

实验步骤

1.    程序烧录:点击一键下载.exe进行下载(需要设备盘符在D盘),或者将编译文件复制到设备盘符;

2.    观察设计运行结果。

实验现象

按动矩阵键盘上的按键,主板数码管会显示计算器的运算过程和结果。

例如上电默认显示□□.□□.□□□□,比如我们要计算34 x 2 / 5

先按动3按键,数码管显示□3.□□.□□□□,

再按动4按键,数码管显示34.□□.□□□□ ,

再按动x按键,独立数码管显示03 ,

再按动2按键,数码管显示34.□2.□□□□,

再按动=按键,数码管显示34.□2.□□68

再按动 / 按键,独立数码管显示04 ,

再按动5按键,数码管显示68.□5.□□□□,

再按动=按键,数码管显示68.□5.133

表示上述运算结果为13……3

image.png

图 9 加法运算展示

image.png

图 10 减法运算展示

 image.png

图 11 乘法运算展示

image.png

图 12 除法运算展示(此处为1……3)

 

  

未来的计划建议

该项目已经成功实现了两位十进制计算器的基本功能,并达到了预期指标。然而还有许多可以提升与扩展的地方:

目前仅支持正数运算,可以增加负数计算的功能。

除法运算结果有余数时,显示余数功能,后续可以增加分数显示和小数显示功能。

显示功能当前使用数码管显示,可以调用LCD库实现屏幕显示,但是lcd显示较为复杂,可以考虑增加一个M0及以上内核的单片机用于处理图像显示的模块,实现ARM+FPGA。

主要设计参考

FPGA系统性学习笔记连载_Day15【按键检测、按键消抖】 【原理及verilog仿真】篇 - 知乎 (zhihu.com)

矩阵键盘键入系统设计 [小脚丫STEP开源社区] (stepfpga.com)

小脚丫FPGA套件STEP BaseBoard V4.0 (eetree.cn)

相关链接

 STEP-FPGA · OPEN_OS/笔记 - 码云 - 开源中国 (gitee.com)

附件下载
Calculator.rar
程序代码和设计报告
团队介绍
团队成员
open-os
评论
0 / 100
查看更多
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2024 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号