FPGA_实验小项目:四位运算小计算器

     最近在武汉参加至芯科技的FPGA培训,经过了第一周的强化基础培训,我们掌握了分频模块的书写,以及按键消抖的书写,还有就是边沿检测的方法,当然按键消抖模块我们这里用到的是通过移位打拍然后相或的方法,达到了消抖的目的,不过运用过程中这种方法也会遇到一些BUG,比如时间过短的问题,所以我计划是好要学习一下按键消抖的状态机的实现方法,除了这些还有7段数码管的显示驱动的编写,状态机与TB文件的编写,常用加法期间_74ls161的驱动等等。。。这里就不赘述了 ,当然还有另外一个实验,数字钟的实现的实验,这个实验会在另外一篇随笔中详述。

  现在开始今天这次四位运算小计算器的实现,设计之前首先得明确要实现的功能,以及按照老师所说,自顶向下的设计思路,首先要明确顶层模块需要有哪些输入以及输出,然后顶层以下有哪些模块构建。

 首先明确四则运算模块的实现需要哪些子模块构成:

    1. 7段数码管显示模块    2.  4*4键盘码扫描分析电路    3.  算数逻辑运算模块   4. 数制转换模块: 涉及BCD转bin   bin转BCD   5. 运算操作状态机的书写

首先是7段数码管显示模块的书写,这一任务在第一周的培训中已经讲解,并已经写出,参考我原来写的7段数码管显示原理的介绍。

其中在计算模块时要先对码制进行转换,计算器只能对二进制码进行运算,而显示的时候要显示BCD码,所以要对其进行转换,就要编写bin2BCD 和BCD2bin模块。

此次设计的计算器可实现的功能有:  可以实现4位以内的加减乘除,以及固定两位小数的运算。

矩阵键盘与数码管显示模块已经写出,现在主要说一下操作输入输出控制这一模块。

因为要考虑小数的计算,所以对应的要显示小数点的标志位。

第一个操作数显示,操作符显示,第二个操作数显示,以及连续运算模块。

module key2bcd1 (clk, 
              rst_n, 
              real_number, 
              opcode, 
              BCDa, 
              BCDb, 
              result ,
                  iKey); 
    
    input [4:0] real_number;
    input rst_n,clk;
   input  iKey;// 小数点控制位
    input [24:0] result;
    
    output reg [24:0] BCDa,BCDb;
    output reg [3:0] opcode;
    
    reg [3:0] opcode_reg;
    reg [3:0] state;
    reg datacoming_state,datacoming_flag;
//    ,rst_dian;
    reg dian_flag;
//always @( posedge rst_dian or negedge iKey)
//    begin
//     if(rst_dian)
//        dian_flag <= 0;
//     else
//      dian_flag <= 1;   
//    end 
    
always @(posedge clk)
    if (!rst_n)
    begin
        datacoming_state <=0;
        datacoming_flag <=0;
    end
     
    else
      if (real_number!=17)    
      case(datacoming_state)
       0: begin                
                datacoming_flag <=1;
                datacoming_state <=1;
             end
       1: begin
                datacoming_flag  <=0;
                datacoming_state <=1;
          end
        endcase
        else
        begin
            datacoming_state <= 0;
            datacoming_flag <= 0;
        end
    reg [2:0] i;
    
    always @ (posedge clk or negedge rst_n)
    begin
        if(!rst_n)
        begin
            BCDa <= 0;
            BCDb <= 0;
            state <= 0;
            opcode <= 0;
            dian_flag <=1;
            i<=0;
        end    
        else if (iKey)
       dian_flag <= 1;  
        else
        if(datacoming_flag)
        begin
            case(state)
                0:    case(real_number)
                    0,1,2,3,4,5,6,7,8,9:
                    if(!dian_flag)
                      BCDa[23:8] <={BCDa[19:8],real_number[3:0]};
                    else if (dian_flag==1 && i==0)
                    begin  
                        BCDa[7:4]  <= real_number [3:0];
                        i <= i+1;
                     end 
                     else if(dian_flag==1 && i==1)
                       begin
                         BCDa[3:0] <= real_number [3:0];
                        end
//                    begin
//                        BCDa[23:0] <= {BCDa[19:0],real_number[3:0]};
//                        state <= 0;
//                    end
                    10,11,12,13:    
                    begin
                        opcode_reg <= real_number[3:0];    
                        state <= 1;
                        i <=0; 
                        dian_flag <=0;
                    end
                    15:
                     begin
                        BCDa[24]= ~BCDa[24];
                        state <= 0 ;
                     end
            
                    default:state <= 0;
                    endcase
                    
                1:    case(real_number)
                    0,1,2,3,4,5,6,7,8,9:
                    begin
                        opcode <= opcode_reg;dian_flag <=0;
                       if(!dian_flag)       
                            BCDb[23:8] <={BCDb[19:8],real_number[3:0]};        
             else if (dian_flag && i==0)
                    begin
                     BCDb[7:4] <= real_number [3:0];
                     i <= i+1;
                    end 
             else if(dian_flag && i==1)
                   begin
                     BCDb[3:0] <= real_number[3:0];       
                       end  
                   end            
//                        if(!dian_flag)
//                      BCDa[23:8] <={BCDa[19:8],real_number[3:0]};
//                    else if (dian_flag && i=1)
//                    begin  
//                        BCDa[7:4]  <= real_number [3:0];
//                       i <= i+1;
//                     end 
//                     else if(dian_flag && i=2)
//                       begin
//                         BCDa[3:0] <= real_number [3:0];
//                        end    
                    
                    
                
                    14:        
                    begin
                        BCDa <= result;    
                        BCDb <= 0;        
                        opcode <= 0;
                        state <= 2;
                        i <=0;
                        dian_flag<=0;
                    end
                    15:
                    begin
                        BCDb[24]= ~BCDb[24];
                        state <= 1;
                    end 
                    
                    default:state <= 1;
                    
                    endcase
                

           //  连续运算模块
                2:    
                 begin
                  dian_flag<=1;
                case( real_number)    
                    0,1,2,3,4,5,6,7,8,9:
                    begin
                        BCDa <= {real_number,8'h00};
                        
                        state <= 0;  
                    end
                    10,11,12,13:    
                    begin
                        opcode_reg <= real_number[3:0];    
                        state <= 1;
                    end
                    15:
                      begin
                        BCDa[24]= ~BCDa[24];
                        state <= 2 ;
                      end 
                      
                    default:state <= 2;
                    endcase
                end
            default : state <= 0;
            
            endcase
            
        end
    end
endmodule

计算模块中涉及到的理论图:

  

计算时是利用二进制来进行的所以要先利用bcd2bin模块来进行码制转换。转换计算之后然后再利用bin2BCD转换成BCD码输入给按键输入输出模块

module bcd2bin0(BCDa,BCDb,a,b);

input [24:0] BCDa,BCDb;
output [24:0] a,b;
    
assign  a[23:0] = BCDa[23:20]*100000 + BCDa[19:16]*10000 +
                   BCDa[15:12]*1000 + BCDa[11:8]*100 +
                   BCDa[7:4]*10+ BCDa[3:0];
assign  b[23:0] = BCDb[23:20]*100000 + BCDb[19:16]*10000 +
                   BCDb[15:12]*1000 + BCDb[11:8]*100 + 
                   BCDb[7:4]*10+ BCDb[3:0];
assign  a[24] =BCDa[24], b[24] =BCDb [24];

endmodule

BCD2bin

 

module bin2bcd0(bin,bcd);
    
    input [24:0] bin;
    output [24:0] bcd;
    
   assign bcd[24]= bin[24];
    
    assign bcd[23:20] =  bin[23:0]/100000;            //十万位
    assign bcd[19:16] = (bin[23:0]/10000)%10;        //万位  取余运算 
    assign bcd[15:12] = (bin[23:0]/1000)%10;        //千位
    assign bcd[11:8]  = (bin[23:0]/100)%10;            //百位
    assign bcd[7:4]   = (bin[23:0]/10)%10;            //十位
    assign bcd[3:0]   =  bin[23:0]%10;                //个位


endmodule

BCD到2进制数的转化还可以通过移位的方式来实现。上面显示的模块大量运用了除法和取余运算,会消耗大量资源,所以可以通过移位的方法来实现转换。

未完待续。。。。。。

 

posted on 2016-08-21 23:10  Crazy_body_01  阅读(3483)  评论(0编辑  收藏  举报

导航