1.任务

设计一个四位数简易计算器,数字键由矩阵键盘输入,显示由用四位数码管输出,能够正确实现+、-、*、/ 四种运算(不考虑小数的运算)。

2.系统框图

主要由五个模块组成,分别是矩阵键盘扫描模块、数码管显示模块、二进制转BCD模块、运算模块,框图如下图所示:

3.模块化设计

3.1顶层模块编写

顶层模块作为程序的入口处,分别去调用每个模块,实现各个模块的功能。源码如下:

module cal_top(Clk,Rst_n,key_c,key_r,dig_sel,dig_data);// 输入input Clk;                       //50MHzinput Rst_n;                 //复位 低电平有效input [3:0]key_r;             //矩阵键盘 行// 输出output wire [3:0]key_c;            //矩阵键盘 列output wire[7:0]dig_data;       //数码管段码output wire[3:0]dig_sel;     //4位数码管位选wire key_in;wire [3:0]key_out;             wire key_flag;                  //按键按下标志位wire key_state;                    //按键状态reg [4:0]key_num;             //按键按下的键值reg [13:0]num_a;               //操作数 areg [13:0]num_b;             //操作数 breg dis_flag;                    reg [3:0]opera_flag;wire [13:0]out_a;wire [13:0]out_b;wire dis_flago;wire [3:0]opera_flago;wire out_flagd;reg [13:0]num_sel;wire [3:0]data_q;           //千位wire [3:0]data_b;           //百位wire [3:0]data_s;           //十位wire [3:0]data_g;           //个位reg en;wire [13:0]out_num;wire num_flag;key_filter my_key_filter(.Clk(Clk),.Rst_n(Rst_n),.key_in(key_in),.key_flag(key_flag),.key_state(key_state));key_array my_array(.Clk(Clk),.Rst_n(Rst_n),.key_c(key_c),.key_out(key_out),.key_r(key_r),.key_in(key_in));dig_dynamic my_dig_dynamic(.Clk(Clk),.Rst_n(Rst_n),.En(1'b1),.disp_data({data_q[3:0],data_b[3:0],data_s[3:0],data_g[3:0]}),.dig_sel(dig_sel),.dig_data(dig_data));bcd_d my_bcd_d(.binary(num_sel),.g(data_g),.s(data_s),.b(data_b),.q(data_q));  add  my_add(.num_a(num_sel),.en(en),.key_num(key_num),.out_a(out_num),.num_flag(num_flag));opera my_opera(.num_a(num_a),.num_b(num_b),.en(en),.dis_flag(dis_flag),.opera_flag(opera_flag),.key_num(key_num),.out_a(out_a),.out_b(out_b),.dis_flago(dis_flago),.opera_flago(opera_flago),.out_flagd(out_flagd));     /********选择数******/ always@(posedge Clk or negedge Rst_n)if(!Rst_n) beginnum_a <= 14'd0;num_b <= 14'd0;dis_flag <= 1'b0;endelse if(out_flagd == 1'b1) beginnum_a <= out_a;num_b <= out_b;dis_flag <= dis_flago;opera_flag <= opera_flago; end            else if(dis_flag == 1'b0) beginnum_sel <= num_a;if(num_flag == 1'b1)num_a <= out_num;elsenum_a <= num_a;endelse if(dis_flag == 1'b1) beginnum_sel <= num_b;if(num_flag == 1'b1)             num_b <= out_num;elsenum_b <= num_b;end/*************数操作en************/     always@(posedge Clk or negedge Rst_n)if(!Rst_n)en <= 1'b0;else if(key_flag && (!key_state)) beginkey_num <= key_out;en <= 1'b1;endelseen <= 1'b0;
endmodule

3.2 数码管动态显示模块

数码管这里选择的是共阴数码管,虽然原理图中有8位,但实际上只使用了四位数码管,有需要的可以自己更改为共阳的数码管或者增加数码管显示的位数。然后数码管是直接连接的IO,没有经过其他芯片,有些其他开发板可能会经过138译码器,大家下载了的话,请自行修改。原理图如下:

module dig_dynamic(Clk,Rst_n,En,disp_data,dig_sel,dig_data   );// 输入input        Clk;//时钟,50MHzinput      Rst_n;//异步复位信号,低电平有效input        En; //使能端,高电平有效,有效时数码管正常显示,非能//时数码管全部熄灭input   [15:0]disp_data;//16位宽的待显示数据// 输出output [3:0]dig_sel;   //数码管的位选驱动端口output  [7:0]dig_data;//数码管的段选驱动端口reg       [7:0]dig_data;reg       [14:0]Cnt;          //分频计数器reg      Clk_1k;             //1kHz的扫频信号reg      [3:0]dig_sel_r; //位选数据的临时寄存器reg     [3:0]dig_data_temp;//需要显示的数据的暂存寄存器//扫描周期计数器,计数到25000后返回零,并控制产生1KHz的扫频信号always@(posedge Clk or negedge Rst_n)if(!Rst_n)Cnt <= 15'h0;else if(En) beginif(Cnt == 15'd25000)Cnt <= 15'h0;elseCnt <= Cnt + 15'h1;endelseCnt <= Cnt;always@(posedge Clk or negedge Rst_n)if(!Rst_n)Clk_1k <= 1'h0;else if(Cnt == 15'd25000)Clk_1k <= ~Clk_1k;elseClk_1k <= Clk_1k;//产生不断变化的位选信号,更新频率1KHz    always@(posedge Clk_1k or negedge Rst_n)if(!Rst_n)dig_sel_r <= 4'b1110;else if(En)dig_sel_r <= {dig_sel_r[2:0],dig_sel_r[3]};elsedig_sel_r <= dig_sel_r;//使能时正常输出位选数据,非能时输出全0,即数码管全部熄灭assign    dig_sel = (En)?dig_sel_r:4'b0000;always@(*)case(dig_sel_r)4'b1110:dig_data_temp <= disp_data[3:0];      //最低位数码管4'b1101:dig_data_temp <= disp_data[7:4];4'b1011:dig_data_temp <= disp_data[11:8];4'b0111:dig_data_temp <= disp_data[15:12];default:dig_data_temp <= 4'b0000;endcase// 共阴数码管always@(*)case(dig_data_temp)0: dig_data <= 8'h3F;     // 01: dig_data <= 8'h06;2: dig_data <= 8'h5B;3: dig_data <= 8'h4F;4: dig_data <= 8'h66;5: dig_data <= 8'h6D;6: dig_data <= 8'h7D;7: dig_data <= 8'h07;8: dig_data <= 8'h7F;9: dig_data <= 8'h6F;10: dig_data <= 8'h77;11: dig_data <= 8'h7C;12: dig_data <= 8'h39;13: dig_data <= 8'h5E;14: dig_data <= 8'h79;15: dig_data <= 8'h71;default:;endcase        endmodule

3.3 矩阵键盘扫描

矩阵键盘选的是4*4行列式键盘;矩阵键盘的扫描原理为,先让四个横行或者四个竖列输出高电平,另外四个为输入模式,若扫描到高电平,则表示该行或该列有按键按下,接着切换输入输出,扫描另外四个,得到另外的坐标,由此确定按键按下的位置,原理图如下图所示:

/********************************************************************
*                   矩阵键盘扫描
*   功能:采用扫描法来检测矩阵键盘
*   作者:Ray
*   起始时间:2021-4-24
*   完成时间:2021-5-26
********************************************************************/
module key_array(Clk,Rst_n,key_r,key_c,key_out,key_in);input Clk;input Rst_n;input [3:0]key_r;          //行output reg [3:0]key_c;       //列output reg [3:0]key_out;output reg key_in;always@(posedge Clk or negedge Rst_n)if(!Rst_n)key_c <= 4'b1110;else if (key_r == 4'b1111) beginif (key_c == 4'b0111)key_c <= 4'b1110;else beginkey_c <= {key_c[2:0],key_c[3]};endendalways@(posedge Clk or negedge Rst_n)if(!Rst_n)key_out <= 4'h6;else if (key_r == 4'b1111)key_in<=1'b1;elsecase(key_c)4'b1110 :case(key_r)4'b1110 :   beginkey_out <= 4'h1;key_in <= key_r[0];end4'b1101 :  beginkey_out <= 4'h4;key_in <= key_r[1];end4'b1011 :  beginkey_out <= 4'h7;key_in <= key_r[2];end4'b0111 :  beginkey_out <= 4'ha;key_in <= key_r[3];endendcase4'b1101 :case(key_r)    4'b1110 :  beginkey_out <= 4'h2;key_in <= key_r[0];end4'b1101 :  beginkey_out <= 4'h5;key_in <= key_r[1];end4'b1011 :  beginkey_out <= 4'h8;key_in <= key_r[2];end4'b0111 :  beginkey_out <= 4'hb;key_in <= key_r[3];endendcase4'b1011 :case(key_r)4'b1110 :  beginkey_out <= 4'h3;key_in <= key_r[0];end4'b1101 :  beginkey_out <= 4'h6;key_in <= key_r[1];end4'b1011 :  beginkey_out <= 4'h9;key_in <= key_r[2];end4'b0111 :  beginkey_out <= 4'hc;key_in <= key_r[3];endendcase4'b0111 :case(key_r)4'b1110 :  beginkey_out <= 4'hf;key_in <= key_r[0];end4'b1101 :  beginkey_out <= 4'h0;key_in <= key_r[1];end4'b1011 :  beginkey_out <= 4'he;key_in <= key_r[2];end4'b0111 :  beginkey_out <= 4'hd;key_in <= key_r[3];endendcaseendcase
endmodule

3.4运算模块

该模块是本次设计的核心部分,用于实现四则运算,两位十进制数num_a,num_b作为计算器的输入值;1010代表加法运算,1011代表减法运算,1100代表乘法运算,1101代表除法运算。输出14位二进制数out_a,因为输出的是二进制数,而我们在数码管看见的数是十进制,所以需要将二进制数再转换为BCD码(需调用二进制转BCD模块),经过转换后的数据,再输出到数码管显示,程序如下:

/********************************************************************
*                   运算模块
*   功能:对输入的两个数进行运算
*   作者:Ray
*   起始时间:2021-4-24
*   完成时间:2021-5-26
********************************************************************/
module opera(// 输入input wire [13:0]num_a,input wire [13:0]num_b,input wire dis_flag,input wire [3:0]opera_flag,input wire en,input wire[3:0]key_num,// 输出output reg[13:0]out_a,output reg[13:0]out_b,output reg dis_flago,output reg [3:0]opera_flago,output reg out_flagd);always@(*)if(en && (key_num > 4'b1001)) beginif(key_num < 4'b1110)if(dis_flag == 1'b0) beginopera_flago <= key_num;out_a <= num_a;out_b <= num_b;dis_flago <= 1'b1;endelse if(dis_flag == 1'b1) begin// 加法if(opera_flag == 4'b1010)beginout_a <= num_a + num_b;out_b <= 14'h0;end// 减法else if(opera_flag == 4'b1011) beginout_a <= num_a - num_b;out_b <= 14'h0;end// 乘法else if(opera_flag == 4'b1100) beginout_a <= num_a * num_b;out_b <= 14'h0;end// 除法else if(opera_flag == 4'b1101) beginout_a <= num_a / num_b;out_b <= 14'h0;end    opera_flago <= key_num; dis_flago <= 1'b0;endout_flagd = 1'b1;endelse beginout_flagd <= 1'b0;end
endmodule

4 总体功能调试

在实际调试中需要进行波形仿真,这里主要是偷懒,并没有写测试文件,大家可以自己写下;调试过程如下,首先用按键按下“12”(图4-1),然后按下运算符“/”号,按下运算符后,数码管会显示“0000”,随后再按下数字按键“3”(图4-2),再按下运算符“/”号即可显示运算结果(图上4-3)。


5.总结

工程已打包至github,有需要的直接双击链接即可。
https://github.com/Jeff-Ray/Calculator/tree/master

基于Verilog的简易计算器相关推荐

  1. 简单计算器的设计java_(基于java的简易计算器的设计.doc

    (基于java的简易计算器的设计 基于java的简易计算器的设计 摘要 自从java语言诞生以来,java语言就以不可抵挡的趋势很快成为国际上广泛流行的面向对象编程语言,它既具有高级语言的特点,又少了 ...

  2. 51单片机设计简易计算机原理,基于AT89C51单片机简易计算器的设计(DOC).docx

    PAGE PAGE # 基于AT89C51单片机简易计算器的设计 [摘要]单片机的出现是计算机制造技术高速发展的产物,它是嵌 入式控制系统的核心,如今,它已广泛的应用到我们生活的各个领域, 电子.科技 ...

  3. 基于PyQt5的简易计算器

    基于PyQt5的简易计算器之四 提示:基于PyQt5的简易计算器之一为环境搭建 基于PyQt5的简易计算器之二为Qt Designer使用 基于PyQt5的简易计算器之三为按键的功能实现 基于PyQt ...

  4. 基于QT5实现简易计算器

    基于QT5实现简易计算器 一.写在前面 二.成品展示 三.界面布局 四.按钮功能 五.源码下载 六.补充 一.写在前面 软件介绍: 仿照win10计算器,基于qt5实现具有简单运算的计算器. 环境: ...

  5. 基于Atmega16的简易计算器实验设计和Proteus仿真

    基于Atmega16的简易计算器实验设计和Proteus仿真 该程序参考https://zhuanlan.zhihu.com/p/128593249,实现了两个多位数字的加减乘除,在此基础上增加了按键 ...

  6. 基于java平台简易计算器_基于java的简易计算器的设计

    基于java的简易计算器的设计 基于java的简易计算器的设计 摘要 自从java语言诞生以来,java语言就以不可抵挡的趋势很快成为国际上广泛流行的面向对象编程语言,它既具有高级语言的特点,又少了C ...

  7. 基于JavaScript的简易计算器(可处理连续加减乘除运算)

    相信大家对于计算器都并不陌生,很多朋友们一定也能完成简易的可以完成加减乘除运算的计算器的制作,那该怎么把简易的计算器美化并且可以完成连续运算,并且可以完成简单的先乘除后加减的动作呢?接下来我们一起来看 ...

  8. 基于Android平台的简易计算器,基于Andriod的简易计算器

    这学期有安卓这门课,这里做了一个简易的计算器,实现了两位数加减乘除的基本功能,比较简单适合用来入门学习. 运行效果 预备知识 实现这个计算器之前要先了解实现计算器需要的基本组件 1.TextView ...

  9. c语言计算器开题报告,基于单片机的简易电子计算器设计开题报告.doc

    第 PAGE 3页 授人以渔能力为本 毕业设计开题报告 学生姓名 学生学号 毕业设计题目 基于单片机的简易电子计算器设计 1.选题背景(含国内外相关研究综述及评价)与意义 随着社会的发展,科学的进步, ...

  10. 基于51单片机的简易计算器的实现

    目录 一.硬件简介 1.LCD1602液晶显示器介绍 (1)LCD1602的组成 (2)各引脚功能介绍 (3)DDRAM 2.矩阵按键介绍 (1)矩阵按键的优点: (2)原理: (3)检测方法: (4 ...

最新文章

  1. 构建linux下的web服务器
  2. stm32无法进入串口接收中断
  3. mysql windows集群_Mysql集群windows服务器版搭建过程
  4. Oracle自定义函数
  5. 一个简易的webpack开发环境
  6. linux centos更换用户名和密码忘记了,centos7系统中忘记root管理员账号密码,怎么修改密码的解决方式...
  7. Lecture 2: Preliminary Review--Mind Map
  8. 第6课 仿Siri机器人-语音朗读和语音识别
  9. Kylin, Mondrian, Saiku系统的整合
  10. 程序员听歌该有的样子
  11. bzoj1935 [Shoi2007]Tree 园丁的烦恼 二维偏序
  12. 深度优先搜索之踩方格问题
  13. 8月28日服务器例行维护公告,天涯明月刀8月28日更新了什么-8月28日更新内容介绍...
  14. 新益华基层医疗系统使用方法_「热缩带」管道防腐新方向,聚乙烯热缩带安装使用方法...
  15. stm32_电容触摸按键
  16. 电机与拖动课程最全思维导图笔记
  17. 微服务下蓝绿发布、滚动发布、灰度发布等方案
  18. iphone6s从ios10升级到ios12遇到的问题
  19. 拳皇重生服务器维护,《拳皇97 OL》3月10日更新维护公告
  20. 集成学习-Bagging和Pasting

热门文章

  1. centos7安装tomcat9过程
  2. HDFView 3.1.2win10百度云资源
  3. 华为设备OSPF配置命令
  4. 一位AI CEO的生死四十天
  5. 学生管理系统实训报告
  6. 基于java的网上书店系统设计(含源文件)
  7. 树莓派上使用 LCD1602 显示状态
  8. 软件测试基础理论选择题(含答案)
  9. 2022-2028年中国电子政务行业投资策略探讨及市场规模预测报告
  10. 金蝶k3服务器系统吗,金蝶k3server2008服务器配置