加入星計(jì)劃,您可以享受以下權(quán)益:

  • 創(chuàng)作內(nèi)容快速變現(xiàn)
  • 行業(yè)影響力擴(kuò)散
  • 作品版權(quán)保護(hù)
  • 300W+ 專業(yè)用戶
  • 1.5W+ 優(yōu)質(zhì)創(chuàng)作者
  • 5000+ 長(zhǎng)期合作伙伴
立即加入
  • 正文
    • 設(shè)計(jì)原理
    • 設(shè)計(jì)架構(gòu)
    • 仿真測(cè)試
  • 相關(guān)推薦
  • 電子產(chǎn)業(yè)圖譜
申請(qǐng)入駐 產(chǎn)業(yè)圖譜

源碼系列:基于FPGA的計(jì)算器設(shè)計(jì)(附源工程)

16小時(shí)前
242
閱讀需 24 分鐘
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點(diǎn)資訊討論

大俠好,歡迎來(lái)到FPGA技術(shù)江湖,江湖偌大,相見即是緣分。大俠可以關(guān)注FPGA技術(shù)江湖,在“闖蕩江湖”、"行俠仗義"欄里獲取其他感興趣的資源,或者一起煮酒言歡。

今天給大俠帶來(lái)基于FPGA的計(jì)算器設(shè)計(jì),附源碼,獲取源碼,請(qǐng)?jiān)凇癋PGA技術(shù)江湖”公眾號(hào)內(nèi)回復(fù)“?計(jì)算器設(shè)計(jì)源碼”,可獲取源碼文件。話不多說(shuō),上貨。

設(shè)計(jì)原理

在日常的生活和學(xué)習(xí)中,我們經(jīng)常能用到計(jì)算器,計(jì)算器的設(shè)計(jì)可以讓我們加深對(duì)設(shè)計(jì)思想以及設(shè)計(jì)方法的理解,訓(xùn)練實(shí)操能力,緊密的聯(lián)系各模塊,?對(duì)我們的學(xué)習(xí)有很大的幫助和提升。下面咱們就來(lái)一起看一下。

本次的設(shè)計(jì)主要通過(guò)矩陣鍵盤來(lái)實(shí)現(xiàn)按鍵的加減乘除運(yùn)算,通過(guò)按下有效鍵值來(lái)當(dāng)被加數(shù)或者被除數(shù)等等,按下10 -- 13等數(shù)字來(lái)表示對(duì)應(yīng)的運(yùn)算符。按鍵鍵值15表示等于號(hào)。

此次的設(shè)計(jì)是通過(guò)數(shù)碼管來(lái)實(shí)現(xiàn)顯示的,通過(guò)按下對(duì)應(yīng)的按鍵來(lái)顯示到數(shù)碼管上,百位十位個(gè)位等等。當(dāng)按下運(yùn)算算符的時(shí)候顯示清0不顯示東西,之后通過(guò)繼續(xù)按下別的鍵值來(lái)顯示出對(duì)應(yīng)的加數(shù)和除數(shù)等等,之后通過(guò)按下對(duì)應(yīng)的鍵值15表示等于后,然后數(shù)碼管清0之后立馬顯示出對(duì)應(yīng)的等于的數(shù)。

設(shè)計(jì)架構(gòu)

設(shè)計(jì)框架圖:

設(shè)計(jì)代碼:

頂層模塊calc代碼:

module calc(clk,rst_n,row,col,sel,seg7);  //端口列表  input clk;    //時(shí)鐘  input rst_n;  //復(fù)位  input [3:0] row;  //行信號(hào)
  output [3:0] col;  //列信號(hào)  output  [2:0] sel;  //數(shù)碼管位選信號(hào)  output  [7:0] seg7;  //數(shù)碼管段選信號(hào)
  wire [23:0] data;
  //例化數(shù)碼管模,和矩陣鍵盤模塊  key_borad key_borad_dut(         .clk(clk),        .rst_n(rst_n),        .row(row),        .col(col),        .data(data)      );  seg seg_dut(        .clk(clk),        .rst_n(rst_n),        .sel(sel),        .seg7(seg7),        .data_in(data)      );
endmodule

key_borad代碼:

module key_borad(clk,rst_n,row,col,data);  input clk;      //時(shí)鐘 50M  input rst_n;    //復(fù)位  input [3:0] row;      //輸入行信號(hào)
  output reg [3:0] col;    //輸出列信號(hào)  output reg [23:0] data;
  //狀態(tài)變量,表示  parameter s0 = 3'b00;  parameter s1 = 3'b01;  parameter s2 = 3'b10;  parameter s3 = 3'b11;  parameter s4 = 3'b100;  parameter s5 = 3'b101;
  //parameter T1ms = 50000;    //掃描間隔  parameter T1ms = 2;  //parameter T10ms= 500_000;   //按鍵消抖時(shí)間  parameter T10ms = 20;
  wire flag;  reg [15:0] count;  always @ (posedge clk or negedge rst_n)    if(!rst_n)      begin        count <= 16'd0;      end    else      begin        if(count <  T1ms - 1 )      //計(jì)數(shù)1K的頻率時(shí)間          count <= count + 1'b1;        else          begin            count <= 16'b0;          end      end
  assign flag = (count == T1ms - 1) ? 1'b1 : 1'b0;  //計(jì)數(shù)到了就給一個(gè)高脈沖,反之低脈沖
  reg [2:0] state;  reg [7:0] row_col;  reg [18:0] cnt;  reg data_flag;  always @ (posedge clk or negedge rst_n)    if(!rst_n)      begin        state <= 3'b0;        row_col <= 8'b1111_1111;          data_flag <= 1'b0;        col <= 4'b0000;        cnt <= 19'b0;      end    else      begin        case (state)          s0: begin              if(row == 4'b1111)  //如果沒有按下                begin                  data_flag <= 1'b0;                  col <= 4'b0000;                end              else      //表示按下,跳轉(zhuǎn)下一個(gè)狀態(tài)                begin                  data_flag <= 1'b0;                    state <= s1;                end            end          s1: begin              if(row == 4'b1111)  //如果是抖動(dòng)跳轉(zhuǎn)0狀態(tài)                begin                  cnt <= 19'b0;                  state <= s0;                end              else                begin                  if(cnt < T10ms - 1)  //計(jì)數(shù)相應(yīng)的時(shí)間,消抖處理                    begin                      cnt <= cnt + 1'b1;                    end                  else                    begin                      cnt <= 19'b0;                      state <= s2;                      col <= 4'b0111;   //消抖完表示按鍵有效                    end                end            end          s2: begin              if (row != 4'b1111)      //表示導(dǎo)通                begin                    state <= s3;      //導(dǎo)通后跳轉(zhuǎn)下一個(gè)狀態(tài)                  row_col <= {row,col};  //拼接行和列信號(hào)                end              else      //行信號(hào)不導(dǎo)通,開始進(jìn)行列掃描                begin                  if(flag)                    begin                      col <= {col[2:0],col[3]};  //1ms進(jìn)行一次列掃描                    end                  else                    begin                      col <= col;                    end                end            end          s3:begin              if(row == 4'b1111)  //按鍵抬起                begin                  state <= s0;                  data_flag <= 1'b1;  //表示一次成功的按鍵,輸出一個(gè)高脈沖                end              else                begin                  state <= s3;                end            end          default: state <= s0;        endcase      end
  reg [3:0] key_num;    //鍵值的翻譯模塊的表示  always @ (posedge clk or negedge rst_n)    if(!rst_n)      key_num = 4'd0;    else      case ({row_col})         8'b0111_0111:key_num = 4'hf;        8'b0111_1011:key_num = 4'he;        8'b0111_1101:key_num = 4'hd;        8'b0111_1110:key_num = 4'hc;
        8'b1011_0111:key_num = 4'hb;        8'b1011_1011:key_num = 4'ha;        8'b1011_1101:key_num = 4'h9;        8'b1011_1110:key_num = 4'h8;
        8'b1101_0111:key_num = 4'h7;        8'b1101_1011:key_num = 4'h6;        8'b1101_1101:key_num = 4'h5;        8'b1101_1110:key_num = 4'h4;
        8'b1110_0111:key_num = 4'h3;        8'b1110_1011:key_num = 4'h2;        8'b1110_1101:key_num = 4'h1;        8'b1110_1110:key_num = 4'h0;        default: ;    endcase


  //計(jì)算模塊的表示  reg [2:0] state_s;   //狀態(tài)變量  reg [23:0] num1,num2,data_in,data_t;  //信號(hào)變量  reg [3:0]flag_s;    //運(yùn)算符  always @ (posedge clk or negedge rst_n)    begin      if(!rst_n)        begin          data <= 24'b0;          state_s <= s0;          num1 <= 24'b0;          num2 <= 24'b0;           data_t <= 24'b0;          flag_s <= 4'b0;          data_in <= 24'b0;        end      else        begin          case (state_s)            s0:begin                if(data_flag)  //如果有一次按下                  begin                    if(key_num < 4'd9)  //鍵值小于9便是有效                      begin                        num1 <= num1*10 + key_num;  //BCD碼轉(zhuǎn)為2進(jìn)制                        data <= {data[19:0],key_num};  //數(shù)碼管移位                      end                    if(key_num > 4'd9 && key_num < 4'd14) //10 -- 13 表示運(yùn)算符                      begin                        data <= 24'b0;                        state_s <= s1;                        flag_s <= key_num;                      end                    else   //否則無(wú)效信號(hào)                      state_s <= s0;                  end              end            s1:begin                if(data_flag)//如果有一次按下                 begin                  if(key_num <4'd9 )  //鍵值小于9便是有效                    begin                      num2 <= 10*num2 +key_num;//BCD碼轉(zhuǎn)為2進(jìn)制                      data <= {data[19:0],key_num};//數(shù)碼管移位                    end                  if(key_num > 4'd9 && key_num < 4'd14)//10 -- 13 表示運(yùn)算符                      begin                        state_s <= s1;                      end                    if(key_num == 15) //表示等于                    begin                          state_s <= s2;                    end                end                  end            s2:begin                state_s <= s3;                case (flag_s)
                  4'd10 :begin  //加運(yùn)算                      data_in <= num1 + num2;                        state_s <= s3;                  end
                  4'd13 :begin  //乘運(yùn)算                    data_in <= num1 * num2;                    state_s <= s3;                  end                endcase              end            s3:begin    //二進(jìn)制轉(zhuǎn)為BCD碼顯示到對(duì)應(yīng)的數(shù)碼管上                data[3:0] = data_in % 10;                data[7:4] = data_in / 10 % 10;                data[11:8] = data_in / 100 % 10;                  data[15:12] = data_in / 1000 % 10;                data[19:16] = data_in / 10000 % 10;                data[23:20] = data_in / 100000;                state_s <= s0;                data_in <= 24'b0;              end            default: state_s <= s0;          endcase        end    end
  /*  always @ (posedge clk or negedge rst_n)    if(!rst_n)      begin        data <= 24'b0;      end    else      begin        if(data_flag)          begin            data <= {data[19:0],key_num};   
            if(key_num == 4'hf)              data <= {data[15:0],4'hf,data[11:8] - data [3:0]};          end        else          begin            data <= data;          end      end  */endmodule

seg代碼:

module seg(clk,rst_n,sel,seg7,data_in);
  input clk;  input rst_n;  input [23:0] data_in;
  output reg [2:0] sel;  output reg [7:0] seg7;
  parameter s0 = 3'b000;  parameter s1 = 3'b001;  parameter s2 = 3'b010;  parameter s3 = 3'b011;  parameter s4 = 3'b100;  parameter s5 = 3'b101;
  `define T1ms  50_000  //`define T1ms  5  reg [15:0] count;  wire flag;  always @ (posedge clk or negedge rst_n)    if(!rst_n)      begin        count <= 15'b0;      end    else      if(count == `T1ms - 1)        begin          count <= 15'b0;        end      else        begin          count <= count + 1'b1;        end
  assign flag =(count == `T1ms  - 1) ? 1'b1 : 1'b0;
  reg [2:0] state;   reg [3:0] num;  always @ (posedge clk or negedge rst_n)    if(!rst_n)      begin        sel <= 3'b0;        state <= 3'b0;        num <= 4'b0;      end    else      begin        case (state)          s0:begin              if(flag)                state <= s1;              else                begin                  sel <= 3'b000;                  num <= data_in[23:20];                end            end          s1:begin              if(flag)                state <= s2;              else                begin                  sel <= 3'b001;                  num <= data_in[19:16];                end            end          s2:begin              if(flag)                state <= s3;              else                begin                  sel <= 3'b010;                  num <= data_in[15:12];                end            end          s3:begin              if(flag)                state <= s4;              else                begin                  sel <= 3'b011;                  num <= data_in[11:8];                end            end          s4:begin              if(flag)                state <= s5;              else                begin                  sel <= 3'b100;                  num <= data_in[7:4];                end            end          s5:begin              if(flag)                state <= s0;              else                begin                  sel <= 3'b101;                  num <= data_in[3:0];                end            end          default:state <= s0;        endcase      end
  always @ (*)      begin        case (num)          0:seg7 <= 8'b1100_0000;          1:seg7 <= 8'b1111_1001;          2:seg7 <= 8'b1010_0100;          3:seg7 <= 8'b1011_0000;          4:seg7 <= 8'b1001_1001;          5:seg7 <= 8'b1001_0010;          6:seg7 <= 8'b1000_0010;          7:seg7 <= 8'b1111_1000;          8:seg7 <= 8'b1000_0000;          9:seg7 <= 8'b1001_0000;          10:seg7 <= 8'b1000_1000;             11:seg7 <= 8'b1111_0111;  // '-'          12:seg7 <= 8'b1100_0110;          13:seg7 <= 8'b1010_0001;          14:seg7 <= 8'b1000_0110;          15:seg7 <= 8'b1111_0110;  // '= '          default:;        endcase      endendmodule

yingjian模塊代碼:

module yingjian(clk,rst_n,col,row,pressnum);
  input clk;  input rst_n;  input [3:0] col;  input [4:0] pressnum;
  output reg [3:0] row;

  always @ (*)      begin        case (pressnum)          0: row = {1'b1,1'b1,1'b1,col[0]};          1: row = {1'b1,1'b1,1'b1,col[1]};          2: row = {1'b1,1'b1,1'b1,col[2]};          3: row = {1'b1,1'b1,1'b1,col[3]};
          4: row = {1'b1,1'b1,col[0],1'b1};          5: row = {1'b1,1'b1,col[1],1'b1};          6: row = {1'b1,1'b1,col[2],1'b1};          7: row = {1'b1,1'b1,col[3],1'b1};
          8: row = {1'b1,col[0],1'b1,1'b1};          9: row = {1'b1,col[1],1'b1,1'b1};          10: row = {1'b1,col[2],1'b1,1'b1};          11: row = {1'b1,col[3],1'b1,1'b1};
          12: row = {col[0],1'b1,1'b1,1'b1};          13: row = {col[1],1'b1,1'b1,1'b1};          14: row = {col[2],1'b1,1'b1,1'b1};          15: row = {col[3],1'b1,1'b1,1'b1};
          16: row = {1'b1,1'b1,1'b1,1'b1};          default:;        endcase      endendmodule

仿真測(cè)試

測(cè)試模塊calc_tb代碼:

`timescale 1ns/1ps
module calc_tb();  reg clk;  reg rst_n;  reg [4:0] pressnum;  wire [3:0] row;
  wire [3:0] col;  wire [3:0] key_num;
  initial begin      clk = 1'b1;      rst_n = 1'b0;      pressnum = 5'd16;
      #200.1        rst_n = 1'b1;      #2000        pressnum = 5'd16;
      #1000        pressnum = 5'd5;
      #1000        pressnum = 5'd16;
      #1250        pressnum = 5'd10;      #1250        pressnum = 5'd16;      #1250        pressnum = 5'd2;      #1250        pressnum = 5'd16;      #1250        pressnum = 5'd15;      #1250        pressnum = 5'd16;      #2000      #2000        $stop;
    end  always #10 clk = ~clk;
  calc calc_dut(      .clk(clk),      .rst_n(rst_n),      .row(row),      .col(col),      .sel(sel),      .seg7(seg7)    );  yingjian yingjian_dut(      .clk(clk),      .rst_n(rst_n),      .col(col),      .row(row),      .pressnum(pressnum)    );endmodule

仿真圖:

從仿真圖中可以看出,在仿真中我們?cè)O(shè)置的是先按下5,再10,之后2,然后按下等于15.通過(guò)觀察仿真正確,之后由于設(shè)計(jì)中我們10是表示加法,那么5 + 2 = 7 :結(jié)果顯示正確。

相關(guān)推薦

電子產(chǎn)業(yè)圖譜

任何技術(shù)的學(xué)習(xí)就好比一個(gè)江湖,對(duì)于每一位俠客都需要不斷的歷練,從初入江湖的小白到歸隱山林的隱世高人,需要不斷的自我感悟自己修煉,讓我們一起仗劍闖FPGA乃至更大的江湖。