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 阅读(3678) 评论(0) 编辑 收藏 举报