基于FPGA的计算器设计---第一版

fpga · 浏览次数 : 0

小编点评

Sure, here is the summary you requested: **Code Explanation:** The code you provided is an implementation of a calculator using a 4x4 matrix keyboard. It uses a state machine to handle different operations and displays results on a seven-segment display. **Key Features:** * The code supports addition, subtraction, multiplication, and division operations. * It also handles equal sign and comparison operations. * The code uses a state machine to track the current operation and display results accordingly. * The simulation allows you to input numbers and perform operations to see results on the seven-segment display. **Additional Information:** * The code uses a 4x4 matrix keyboard simulation model. * The simulation allows you to input numbers and perform operations to see results on the seven-segment display. * The code is divided into several sections for clarity. **Resources:** * Video explanation and demonstration: BV1ew4m1S7Av * Code link: s0f8 * Design description link: Not provided in the context * Simulation link: Not provided in the context **Conclusion:** This code provides a functional calculator using a 4x4 matrix keyboard simulation model. The code uses a state machine to handle different operations and displays results on a seven-segment display.

正文

欢迎各位朋友关注“郝旭帅电子设计团队”,本篇为各位朋友介绍基于FPGA的计算器设计---第一版。

功能说明:

 

1. 计算器的显示屏幕为数码管。

2. 4x4矩阵键盘作为计算器的输入设备。

3. 计算任意两位正整数的加减乘除。

4. 当减法结果出现负数时(一个小的数字减去一个大的数字),数码管需要显示负数。 

5. 除法计算时,结果只输出商的整数,小数自动抹去。
注:矩阵键盘输入0-9,表示0-9;10表示加号(数码管显示A);11表示减号(数码管显示b);12表示乘号(数码管显示C);13表示除号(数码管显示d);14表示等于号。

 

使用平台:本次设计应用Altera的平台设计(芯片:EP4CE10F17C8N)。 

作者QQ:746833924

说明:本篇设计中不涉及到IP和原语,代码在其他平台依然可以适用;当其他板卡电路不同时,会导致不同的现象出现,如有需要修改代码请联系作者;如需作者使用的板卡,请联系作者;

 

设计思想如下:

 

       keyboard4x4_drive模块为4x4矩阵键盘的驱动模块,负责检测4x4矩阵键盘被按下的按键信息;cal_logic模块为计算逻辑和控制显示信息的逻辑,负责根据矩阵键盘传递的按键信息进行计算,根据计算的过程控制输出需要显示的信息;seven_tube_drive(七段数码管驱动)模块负责将产生的数字逻辑显示到数码管上。

 

keyboard4x4_drive模块的设计思想和具体设计可以参考本公众号,获取方式:关注本公众号,发送“FPGA矩阵键盘驱动第一版”。

cal_logic模块的设计思想:利用状态机设计进行实现。共有八个状态。

  localparam      STATE_IDLE        =     8'b0000_0001;       
  localparam      STATE_NUM1_1      =     8'b0000_0010;
  localparam      STATE_NUM1_2      =     8'b0000_0100;
  localparam      STATE_OPCODE      =     8'b0000_1000;
  localparam      STATE_NUM2_1      =     8'b0001_0000;
  localparam      STATE_NUM2_2      =     8'b0010_0000;
  localparam      STATE_EQUAL       =     8'b0100_0000;
  localparam      STATE_RESULT      =     8'b1000_0000;

 

STATE_IDLE :空闲初始化状态;

STATE_NUM1_1 :输入第一个操作数的第一位。

STATE_NUM1_2 :输入第一个操作数的第二位。

STATE_OPCODE :输入操作符。

STATE_NUM2_1 :输入第二个操作数的第一位。

STATE_NUM2_2 :输入第二个操作数的第二位。

STATE_EQUAL    :输入等于号。

STATE_RESULT   :计算输出结果。

 

复位结束后,在IDLE状态,初始化所有的中间变量和输出,之后进入STATE_NUM1_1。

 

        STATE_IDLE        :     begin
          state <= STATE_NUM1_1;
          num1 <= 8'd0;
          num2 <= 8'd0;
          opcode <= 4'd0;
          show_data <= 24'hfffff0;
        end

 

在STATE_NUM1_1状态中,当输入的数字0-9,认为是第一个操作数的第一位(显示到最后的数码管),然后进入STATE_NUM1_2,准备接收第一个操作数的第二位;如果输入数字10-13,认为是第一个操作数为0(数码管显示第一个操作数0和操作符),并且存储好操作符,进入STATE_NUM2_1,准备接收第二个操作数的第一位;如果输入为其他数字,则认为无效输入。

        STATE_NUM1_1      :     begin
          if (flag == 1'b1)
            if (press_num < 4'd10) begin
              state <= STATE_NUM1_2;
              num1 <= {4'd0, press_num};
              show_data <= {20'hfffff, press_num};
            end
            else 
              if (press_num > 4'd9 && press_num < 4'd14) begin
                num1 <= 8'd0;
                state <= STATE_NUM2_1;
                opcode <= press_num;
                show_data <= {show_data[19:0], press_num};
              end
              else 
                state <= STATE_NUM1_1;
          else
            state <= STATE_NUM1_1;
        end

在STATE_NUM1_2状态中,当输入的数字0-9,认为是第一个操作数的第二位(将第一个操作数的第一位和第二位都显示到数码管上)(计算得出num1),然后进入STATE_OPCODE,准备接收操作符;如果输入数字10-13,认为是第一个操作数为STATE_NUM1_1输入的数字(数码管显示第一个操作数和操作符),并且存储好操作符,进入STATE_NUM2_1,准备接收第二个操作数的第一位;如果输入为其他数字,则认为无效输入。

 

        STATE_NUM1_2      :     begin
          if (flag == 1'b1)
            if (press_num < 4'd10) begin
              state <= STATE_OPCODE;
              num1 <= num1 * 10 + press_num;
              show_data <= {show_data[19:0], press_num};
            end
            else 
              if (press_num > 4'd9 && press_num < 4'd14) begin
                state <= STATE_NUM2_1;
                opcode <= press_num;
                show_data <= {show_data[19:0], press_num};
              end
              else 
                state <= STATE_NUM1_2;
          else
            state <= STATE_NUM1_2;
        end

 

      在STATE_OPCODE状态中,如果输入数字10-13,认为是第一个操作数为STATE_NUM1_1和STATE_NUM1_2输入的数字(数码管显示第一个操作数和操作符),并且存储好操作符,进入STATE_NUM2_1,准备接收第二个操作数的第一位;如果输入为其他数字,则认为无效输入。

 

        STATE_OPCODE      :     begin
          if (flag == 1'b1)
            if (press_num > 4'd9 && press_num < 4'd14) begin
              state <= STATE_NUM2_1;
              opcode <= press_num;
              show_data <= {show_data[19:0], press_num};
            end
            else 
              state <= STATE_OPCODE;
          else
            state <= STATE_OPCODE;
        end

 

      在STATE_NUM2_1状态中,如果输入数字0-9,认为是第二个操作数的第一个数字(数码管显示第一个操作数、操作符和第二个操作数的第一个数字),进入STATE_NUM2_2,准备接收第二个操作数的第二位;如果输入为其他数字,则认为无效输入。

 

        STATE_NUM2_1      :     begin
          if (flag == 1'b1)
            if (press_num < 4'd10) begin
              state <= STATE_NUM2_2;
              num2 <= press_num;
              show_data <= {show_data[19:0], press_num};
            end
            else 
              state <= STATE_NUM2_1;
          else
            state <= STATE_NUM2_1;
        end

 

     在STATE_NUM2_2状态中,当输入的数字0-9,认为是第二个操作数的第二位(将第一个操作数、操作符和第二个操作数显示到数码管上)(计算得出num2),然后进入STATE_EQUAL,准备接收等于号;如果输入数字14,认为是等于号,进入STATE_RESULT状态。如果输入为其他数字,则认为无效输入。

        STATE_NUM2_2      :     begin
          if (flag == 1'b1)
            if (press_num < 4'd10) begin
              state <= STATE_EQUAL;
              num2 <= num2 * 10 + press_num;
              show_data <= {show_data[19:0], press_num};
            end
            else 
              if (press_num == 4'd14) begin
                state <= STATE_RESULT;
              end
              else 
                state <= STATE_NUM2_2;
          else
            state <= STATE_NUM2_2;
        end

 

在STATE_EQUAL状态中,如果输入数字14,认为是等于号,进入STATE_RESULT状态。如果输入为其他数字,则认为无效输入。

        STATE_EQUAL       :     begin
          if (flag == 1'b1)
            if (press_num == 4'd14) begin
              state <= STATE_RESULT;
            end
            else 
              state <= STATE_EQUAL;
          else
            state <= STATE_EQUAL;
        end

 

在STATE_RESULT状态中,只有按下复位才可以再次进行计算;在本状态中根据第一个操作数、操作符和第二个操作数进行计算,并且将计算的结果作为输出。

 

       STATE_RESULT      :     begin
          state <= STATE_RESULT;
          show_data[23:20] <= result[15] ? 4'he : 4'h0;
          show_data[19:16] <= result[15] ? (-result)/10000 : result/10000;
          show_data[15:12] <= result[15] ? (-result)/1000 % 10 : result/1000 % 10;
          show_data[11:8] <= result[15] ? (-result)/100 % 10 : result/100 % 10;
          show_data[7:4] <= result[15] ? (-result)/10 % 10 : result/10 % 10;
          show_data[3:0] <= result[15] ? (-result) % 10 : result % 10;
        end

 

七段数码管为普通六位一体的共阳极数码,采用动态驱动的方式,在此不再赘述。

 

仿真时,需要利用4x4矩阵键盘的仿真模型,否则不容易仿真(相关代码,下方链接提供)。

 

  calculator calculator_inst(

    .clk                    (clk            ),
    .rst_n                  (rst_n          ),
                             
    .keyboard4x4_row        (keyboard4x4_row),
    .keyboard4x4_col        (keyboard4x4_col),
                             
    .sel                    (sel            ),// 数码管位选信号
    .seg                    (seg            ) // 数码管段选信号
  );
  
  keyboard4x4 keyboard4x4_inst(

    .press_num              (press_num      ),
                                     
    .keyboard4x4_col        (keyboard4x4_col),
    .keyboard4x4_row        (keyboard4x4_row)
  );

 

模拟2+8;

    press_data(5'd2);
    press_data(5'd10);
    press_data(5'd8);
    press_data(5'd14);

 

 

 

 

 

 

 

 

模拟55-8;

 

    press_data(5'd5);
    press_data(5'd5);
    press_data(5'd11);
    press_data(5'd8);
    press_data(5'd14);

 

 

 

 

其他模拟情况,可以根据设计者自由模拟;

 

注意在计算一次完成后,需要进行一次复位(相当于计算器中的清除),然后才可以进行下一次计算。

  讲解和演示视频链接如下:
https://www.bilibili.com/video/BV1ew4m1S7Av/?vd_source=b5405faeab8632f02533bcbfc5e52e55
     本设计所有内容(设计代码、设计工程)链接为:

   

链接:https://pan.baidu.com/s/1WKkfXU7XInPBNCUSvgs5Pw 

提取码:s0f8

 

  本篇内容中有部分资源来源于网络,如有侵权,请联系作者。

 

  如果您觉得本公众号还不错的话,可以推给身边的朋友们,感谢并祝好!

与基于FPGA的计算器设计---第一版相似的内容:

基于FPGA的计算器设计---第一版

欢迎各位朋友关注“郝旭帅电子设计团队”,本篇为各位朋友介绍基于FPGA的计算器设计 第一版。 功能说明: 1. 计算器的显示屏幕为数码管。 2. 4x4矩阵键盘作为计算器的输入设备。 3. 计算任意两位正整数的加减乘除。 4. 当减法结果出现负数时(一个小的数字减去一个大的数字),数码管需要显示负数

基于FPGA的4x4矩阵键盘驱动设计---第一版

欢迎各位朋友关注“郝旭帅电子设计团队”,本篇为各位朋友介绍基于FPGA的4x4矩阵键盘驱动设计 第一版 功能说明: 1. 驱动4x4矩阵键盘:按下任意一个按键,解析出对应按键信息,并给出标志 使用平台:纯代码形式 使用语言:Verilog HDL 作者QQ:746833924 说明:本篇设计中不涉及

基于FPGA的数字钟设计---第三版

欢迎各位朋友关注“郝旭帅电子设计团队”,本篇为各位朋友介绍基于FPGA的数字钟设计 第三版。 功能说明: 1. 在数码管上面显示时分秒(共计六个数码管,前两个显示小时;中间两个显示分钟;最后两个显示秒)。 2. 利用按键可以切换24/12小时制(默认24小时制)。 3. led1的亮灭表示24小时制

基于FPGA的电子琴设计(按键和蜂鸣器)----第一版

欢迎各位朋友关注“郝旭帅电子设计团队”,本篇为各位朋友介绍基于FPGA的电子琴设计(按键和蜂鸣器) 第一版。 功能说明: 外部输入七个按键,分别对应音符的“1、2、3、4、5、6、7”,唱作do、re、mi、fa、sol、la、si。当某个按键按下时,蜂鸣器发出对应的声音 1. 默认发出0.2秒(可

基于FPGA的贪吃蛇游戏 之代码解析

基于FPGA的贪吃蛇游戏 之代码解析 1. 代码结构 代码结构包含7格.v文件。 下面依次解析。 2. 代码解析 (1) seg_display.v 数码管的译码模块是最熟悉,最简单的模块了。这里是共阳极的数码管,用case语句编码即可。从上图可以看到,这个模块被例化了3次,分别驱动3个数码管显示,

ZynqMP PL固件通过U-BOOT从指定位置加载FPGA BIT

原因 PL固件可能经常修改,而BOOT.BIN和文件系统、内核实际上基本不会变,在一个平台上可以用同一份。如果每次修改都要重新打包PL 固件到BOOT.BIN,操作起来非常麻烦。所以希望PL 的固件可以直接从指定位置加载。典型的可以从SD卡的FAT32分区加载。 https://xilinx-wik

基于 Three.js 的 3D 模型加载优化

作为一个3D的项目,从用户打开页面到最终模型的渲染加载的时间也会比普通的H5项目要更长一些,从而造成大量的用户流失。为了提升首屏加载的转化率,需要尽可能的降低loading的时间。这里就分享一些我们在模型加载优化方面的心得。

基于MindSpore实现BERT对话情绪识别

本文分享自华为云社区《【昇思25天学习打卡营打卡指南-第二十四天】基于 MindSpore 实现 BERT 对话情绪识别》,作者:JeffDing。 模型简介 BERT全称是来自变换器的双向编码器表征量(Bidirectional Encoder Representations from Trans

基于 Vagrant 手动部署多个 Redis Server

环境准备 宿主机环境:Windows 10 虚拟机环境:Vagrant + VirtualBox Vagrantfile 配置 首先,我们需要编写一个 Vagrantfile 来定义我们的虚拟机配置。假设已经在 D:\Vagrant\redis 目录下创建了一个 Vagrantfile,其内容如下:

基于EF Core存储的Serilog持久化服务

前言 Serilog是 .NET 上的一个原生结构化高性能日志库,这个库能实现一些比内置库更高度的定制。日志持久化是其中一个非常重要的功能,生产环境通常很难挂接调试器或者某些bug的触发条件很奇怪。为了在脱离调试环境的情况下尽可能保留更多线索来辅助解决生产问题,持久化的日志就显得很重要了。目前Ser