基于fpga的按键输入式计算器设计原理
一 设计思想
fpga开发板上有8个数码管及键盘,可模拟计算器功能,通过NEC红外遥控器获得数据值,后将运算结果显示在数码管上,输入范围0到99999999,输出范围0到99999999,当运算结果大于99999999时显示右边八位,输入数据可以直接显示在数码管上,支持删除,正负数运算等功能,
设计关键在于数据值的获取,只要能准确获得输入值,就可对其进行精确计算,计算部分与显示部分较为简单。
二 fpga实现
分为三部分,输入部分,计算部分,输出部分
输入部分代码如下
//an highlighted blocked
module calculate(
clk,
rst_n,
Get_flag,
irData,
irAddr,
cn,
bcd_tmp,
data,
in5,
minus
);
input clk;
input rst_n;
input [15:0]irData;
input [15:0]irAddr;
input Get_flag;
output reg[31:0]data;
output reg [31:0]in5;
output reg cn;
output reg minus;
reg [1:0]control;
reg cnt9;
reg en;
reg minus_r;
reg reset;
reg reset_1;
reg [3:0]get_data;
reg minus_get;
reg [31:0]in6,in7;
reg [1:0]cnt3,cnt4;
reg [2:0]cnt8;
reg [31:0]get_value;
wire [71:0]shift_reg_out;
reg value_en;
integer i;
output reg[71:0]bcd_tmp;
reg [71:0]shift_reg;
reg [7:0]cnt10;
wire [7:0]get_irData;
reg [31:0]get_value_r[0:6];
initial
begin
reset<=1'b0;
cnt4<=1'b0;
end
assign get_irData=irData[7:0];
always@(posedge clk or negedge reset)
begin
if(!reset)begin
get_data<=4'ha;
cn<=0;
en<=0;
end
else begin
case(get_irData)
8'h87:begin
get_data<=0;
cn<=1'b0;
en<=1'b0;
end
8'h92:begin
get_data<=1;
cn<=1'b0;
en<=1'b0;
end
8'h93:begin
get_data<=2;
cn<=1'b0;
en<=1'b0;
end
8'hcc:begin
get_data<=3;
cn<=1'b0;
en<=1'b0;
end
8'h8e:begin
get_data<=4;
cn<=1'b0;
en<=1'b0;
end
8'h8f:begin
get_data<=5;
cn<=1'b0;
en<=1'b0;
end
8'hc8:begin
get_data<=6;
cn<=1'b0;
en<=1'b0;
end
8'h8a:begin
get_data<=7;
cn<=1'b0;
en<=1'b0;
end
8'h8b:begin
get_data<=8;
cn<=1'b0;
en<=1'b0;
end
8'hc4:begin
get_data<=9;
cn<=1'b0;
en<=1'b0;
end
8'h82:begin
en<=1'b0;
control<=2'b01;
cn<=1'b1;
end
8'h95:begin
cn<=1'b0;
get_data<=4'hf;
en<=1'b0;
end
8'h79:begin
control<=2'b00;
cn<=1'b1;
en<=1'b0;
end
8'hda:begin
control<=2'b10;
en<=1'b0;
cn<=1'b1;
end
8'hd0:begin
control<=2'b11;
cn<=1'b1;
en<=1'b0;
end
8'hce:begin
cn<=1;
en<=1;
end
default:if((get_irData!=8'hce)&&(get_irData==8'hf1))
get_data<=4'ha;
endcase
end
end
always@(posedge clk)
begin
if(get_irData==8'hf1)begin
if((!Get_flag)==1'b1)begin
cnt4<=cnt4+1;
end
end
else begin
cnt4<=0;
end
end
always@(posedge clk or negedge reset)
begin
if(!reset)begin
cnt3<=0;
end
else if(get_irData==8'hce)begin
if((!Get_flag)==1'b1)begin
cnt3<=cnt3+1;
end
end
else begin
cnt3<=0;
end
end
always@(posedge clk or negedge reset)
begin
if(!reset)begin
cnt9<=0;
end
else begin
if(cn==1'b1)begin
cnt9<=1'b1;
end
end
end
always@(posedge clk)
begin
if(cnt4==2)begin
reset_1<=0;
end
else begin
reset_1<=1;
end
end
always@(posedge clk or negedge reset)
begin
if(!reset)begin
cnt8<=0;
end
else begin
if(get_irData==8'hc5)begin
if((!Get_flag)==1'b1)begin
cnt8<=cnt8+1;
end
end
else begin
cnt8<=0;
end
end
end
always@(posedge clk)
begin
if(cnt4==2)begin
reset<=0;
end
else begin
reset<=reset_1;
end
end
reg en_r;
wire en_get;
always@(posedge clk or negedge reset)
begin
if(!reset)begin
en_r<=1'b0;
end
else begin
en_r<=en;
end
end
reg cn_r,cn_r2;
wire cn_neg;
always@(posedge clk or negedge reset)
begin
if(!reset)begin
cn_r<=1'b0;
end
else begin
cn_r<=cn;
cn_r2<=cn_r;
end
end
assign en_get=en_r&(~en);
always@(posedge clk or negedge reset)
begin
if(!reset)begin
in6<=0;
in7<=0;
end
else if(cn==1'b0)begin
if(cnt9==1'b0)begin
in6<=get_value;
end
else begin
in7<=get_value;
end
end
else if(en_get==1'b1)begin
in6<=in5;
end
end
assign cn_neg=cn_r&(~cn);
always@(posedge clk or negedge reset)
begin
if(!reset)begin
in5<=0;
minus<=1'b0;
end
else if(en==1'b1)begin
case(control)
2'b00:begin
if(minus_r==1'b0)begin
in5<=in6+in7;
if(value_en)begin
minus<=1;
end
else begin
minus<=0;
end
end
else begin
if(in6>in7)begin
in5<=in6-in7;
if(!minus_r1)
minus<=1'b0;
else
minus<=1'b1;
end
else if(in6==in7)begin
in5<=in6-in7;
minus<=1'b0;
end
else begin
in5<=in7-in6;
if(!minus_r1)
minus<=1'b1;
else
minus<=1'b0;
end
end
end
2'b01:begin
if(minus_r==1'b1)begin
in5<=in6+in7;
if(value_en)begin
minus<=1'b1;
end
else begin
minus<=1'b0;
end
end
else begin
if(in6>=in7)begin
in5<=in6-in7;
if(minus_r1==1'b1)
minus<=1'b1;
else
minus<=1'b0;
end
else begin
in5<=in7-in6;
if(minus_r1==1'b1)
minus<=1'b0;
else
minus<=1'b1;
end
end
end
2'b10:begin
in5<=in6*in7;
minus<=minus_r;
end
2'b11:begin
in5<=in6/in7;
minus<=minus_r;
end
endcase
end
end
always@(posedge clk or negedge reset)
begin
if(!reset)begin
minus_r<=1'b0;
minus_r1<=1'b0;
minus_get<=1'b0;
end
else begin
if(en_get==1'b1)begin
minus_r<=minus;
minus_r1<=minus;
minus_get<=minus;
end
else if(cn==1'b0)begin
if((get_irData==8'h95)&&(Get_flag==1'b1)&&(minus_get==minus_r)&&(get_value==0))begin
minus_r<=~minus_r;
end
else if((get_irData==8'hc5)&&(data[3:0]==4'hf)&&(Get_flag==1'b1))begin
minus_r<=~minus_r;
end
end
else begin
minus_get<=minus_r;
end
end
end
reg minus_r1;
always@(posedge clk or negedge reset)
begin
if(!reset)begin
value_en<=1'b0;
end
else if(minus==0)begin
if((minus_r==1'b1)&&(cnt9==1'b0))begin
if(control==2'b01)begin
value_en<=1'b1;
end
end
else if((minus_get==1'b1)&&(cnt9==1'b1))begin
if(control==2'b00)begin
value_en<=1'b1;
end
end
else begin
value_en<=1'b0;
end
end
else begin
value_en<=1'b1;
end
end
always@(posedge clk or negedge reset)
begin
if(!reset)begin
cnt10<=0;
end
else if(en==1'b1)begin
if(cnt10<33)begin
cnt10<=cnt10+1;
end
else begin
cnt10<=0;
end
end
else begin
cnt10<=0;
end
end
always@(posedge clk or negedge reset)
begin
if(!reset)begin
shift_reg<={72{1'b0}};
end
else if(cnt10==0)begin
shift_reg<={72{1'b0}};
end
else if(cnt10==1)begin
shift_reg<={shift_reg[71:33],in5,1'b0};
end
else if(cnt10<32)begin
shift_reg<=(shift_reg_out<<1);
end
else if(cnt10==32)begin
bcd_tmp<=(shift_reg_out<<1);
end
else begin
shift_reg<=shift_reg;
end
end
wire [39:0]bcd_value;
wire [39:0]shift_reg_out_r;
assign shift_reg_out={shift_reg_out_r,shift_reg[31:0]};
assign bcd_value=shift_reg[71:32];
always@(shift_reg)
begin
for(i=1;i<10;i=i+1)
shift_reg_out_r[i*4-1-:4]<=(bcd_value[i*4-1-:4]>4)?bcd_value[i*4-1-:4]+3:bcd_value[i*4-1-:4];
end
always@(posedge clk or negedge reset)
begin
if(!reset)begin
get_value<={32{1'b0}};
data<={8{4'ha}};
get_value_r[0]<={32{1'b0}};
get_value_r[1]<={32{1'b0}};
get_value_r[2]<={32{1'b0}};
get_value_r[3]<={32{1'b0}};
get_value_r[4]<={32{1'b0}};
get_value_r[5]<={32{1'b0}};
get_value_r[6]<={32{1'b0}};
end
else begin
if((cn_r2==1'b0)&&(Get_flag==1'b1)&&(get_irData!=8'hce)&&(get_irData!=8'hc5)&&(get_irData!=8'hf1)&&(get_irData!=8'h95))begin
data<={data[27:0],get_data};
get_value<=((get_value<<3)+(get_value<<1))+get_data;
get_value_r[0]<=get_value;
get_value_r[1]<=get_value_r[0];
get_value_r[2]<=get_value_r[1];
get_value_r[3]<=get_value_r[2];
get_value_r[4]<=get_value_r[3];
get_value_r[5]<=get_value_r[4];
get_value_r[6]<=get_value_r[5];
end
else if((Get_flag==1'b1)&&(cn_r2==1'b0)&&(get_irData==8'h95)&&(data=={8{4'ha}}))begin
data<={data[27:0],get_data};
end
else if((cnt8>0)&&(Get_flag==1'b1))begin
data<={4'ha,data[31:4]};
if(cnt8<7)begin
get_value<=get_value_r[cnt8-1];
end
else begin
get_value<=get_value_r[6];
end
end
else if(cnt10==33)begin
data<=bcd_tmp[71:32];
get_value<=0;
end
else if(cn_neg)begin
data<={8{4'ha}};
get_value<=0;
end
end
end
endmodule
所有代码最好写在一个模块,除本模块外需接显示模块,烧写至开发板之后等大约5分钟左右开始工作,如想重新输入 即将复位键拨至0处