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

欢迎各位朋友关注“郝旭帅电子设计团队”,本篇为各位朋友介绍基于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

 

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

 

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

posted on 2024-05-29 15:53  郝旭帅电子设计团队  阅读(130)  评论(0编辑  收藏  举报

导航