一、 项目功能介绍
本项目通过小脚丫FPGA套件STEP BaseBoard V4.0实现两位十进制加、减、乘、除计算器。其中,显示方式通过尺寸为320*240的LCD屏幕和八个数码管进行显示。LCD屏可以显示整个运算过程,数码管从左往右的前两位显示第一位数,第三第四位显示第二位数,第五到第八位显示运算结果。其中,加法、减法、乘法都可以全精度显示,对于除法只能显示四位有效数字,并且除法会对最后一位进行四舍五入处理。
二、 设计思路
本项目要求实现两位十进制加、减、乘、除计算器,从输入输出的角度设计,需要能够输入数字和运算符号的按键和能够显示输入数字和运算结果的显示器件。本项目使用了小脚丫FPGA套件STEP BaseBoard V4.0上板载的矩阵键盘、八个数码管、320*240的LCD屏幕。矩阵键盘通过4个输入引脚和4个输出引脚来实现按键的消抖以及对应数字的输入;八个数码管通过两个74HC595芯片进行动态扫描,利用人眼的视觉暂留来实现对应数字的显示;320*240的LCD屏幕则通过符合ST7789数据手册的SPI通信方式进行显示相关数字、运算符。
三、 硬件框图
上图为硬件框图,从图中可以看出,先通过矩阵键盘输入数字和运算符,经过FPGA的处理,将显示数据传送给数码管和LCD屏幕。
四、 软件流程图
上图为硬件框图,从图中可以看出,FPGA上电之后先对LCD进行了初始化,只有在LCD初始化完成之后才能进行矩阵键盘的输入。在输入完成之后,FPGA会对相关运算进行处理,处理完成之后,将显示数据传输给数码管和LCD屏,传输完成之后,程序结束。
五、FPGA资源占用报
此图为FPGA硬件占用资源的报告
六、简单的硬件介绍
本项目的硬件框图在下面进行展示
上图为4×4矩阵按键的硬件电路图,可以看到4根行线(ROW1、ROW2、ROW3、ROW4)和4根列线(COL1、COL2、COL3、COL4),同时列线通过上拉电阻连接到VCC电压(3.3V),对于矩阵按键来讲:4根行线是输入的是由FPGA控制拉高或拉低,4根列线数输出的,是由4根行线的输入及按键的状态决定输出的高低电平
上图是用于显示运算数字和运算结果的数码管模块。考虑到节约使用引脚,这里使用了两块串行转并行的74HC595芯片进行动态扫描输出,利用人眼的视觉暂留效应使每个数码管都可以正常显示不同的数字。
上图是320*240的LCD模块电路,从上图可以看出,屏幕有六个引脚的输入,其中LED-引脚用于控制背光的亮度,RES引脚用于屏幕复位 ,DC引脚用于数据/命令的选择,SDA引脚用于SPI数据的输入,SCL引脚用于SPI时钟信号的输入,CS引脚用于SPI片选信号的输入。
七、实现的功能以及图片展示
在本项目中,通过小脚丫FPGA套件STEP BaseBoard V4.0实现两位十进制加、减、乘、除计算器。其中,显示方式通过尺寸为320*240的LCD屏幕和八个数码管进行显示。LCD屏可以显示整个运算过程,包括运算数、运算符号、数值正负;数码管从左往右的前两位显示第一位数,第三第四位显示第二位数,第五到第八位显示运算结果。其中,加法、减法、乘法都可以全精度显示,并且支持负数显示;对于除法,可以正确显示小数点的位置,但是考虑只有四位数码管显示运算结果,所以只能显示四位有效数字,并且除法会对最后一位数进行四舍五入处理。
以下对实现的功能进行图片展示:
加法:
减法:
乘法:
除法:
八、主要代码片段及说明
首先是顶层文件代码:
module calculator(
input clk, //system clock
input rst_n, //system reset
input [3:0] col,
output [3:0] row,
output seg_rck, //74HC595的RCK管脚
output seg_sck, //74HC595的SCK管脚
output seg_din, //74HC595的SER管脚
output lcd_rst,
output lcd_blk,
output lcd_dc,
output lcd_sclk,
output lcd_mosi,
output lcd_cs
);
wire [15:0] key_out;
wire [15:0] key_pulse;
wire init_done;
wire [15:0] T_data;
wire [15:0] H_data;
wire [7:0] dat_en;
wire [7:0] dot_en;
wire [2:0] c_state;
wire [3:0] symbol;
//Array_KeyBoard
array_keyboard u1(
.clk(clk),
.rst_n(rst_n),
.col(col),
.row(row),
.key_out(key_out),
.key_pulse(key_pulse)
);
//calculate module
calculate u2(
.clk (clk ),
.rst_n (rst_n ), //系统复位,低有效
.init_done (init_done ), //LCD初始化结束信号
.key_pulse (key_pulse ), //按键矩阵输出脉冲
.T_data (T_data ), //运算数
.H_data (H_data ), //运算结果
.dat_en (dat_en ), //数码显示使能
.dot_en (dot_en ), //小数点显示使能
.c_state (c_state ), //计算器当前状态
.symbol (symbol ) //运算符号
);
//segment_show
segment_scan u3(
.clk (clk ), //系统时钟
.rst_n (rst_n ), //系统复位,低有效
.dat_1 (T_data[15:12] ), //SEG1 显示运算数第一位十位
.dat_2 (T_data[11: 8] ), //SEG2 显示运算数第一位个位
.dat_3 (T_data[ 7: 4] ), //SEG3 显示运算数第二位十位
.dat_4 (T_data[ 3: 0] ), //SEG4 显示运算数第二位个位
.dat_5 (H_data[15:12] ), //SEG5 显示运算结果第一位
.dat_6 (H_data[11: 8] ), //SEG6 显示运算结果第二位
.dat_7 (H_data[ 7: 4] ), //SEG7 显示运算结果第三位
.dat_8 (H_data[ 3: 0] ), //SEG8 显示运算结果第四位
.dat_en (dat_en ), //各位数码管数据显示使能,[MSB~LSB]=[SEG1~SEG8]
.dot_en (dot_en ), //各位数码管小数点显示使能,[MSB~LSB]=[SEG1~SEG8]
.seg_rck (seg_rck ), //74HC595的RCK管脚
.seg_sck (seg_sck ), //74HC595的SCK管脚
.seg_din (seg_din ) //74HC595的SER管脚
);
//LCD_show
picture_display u4(
.clk (clk ),
.rst_n (rst_n ),
.cal_state (c_state ),//计算器当前状态
.cal_symbol (symbol ),//运算符号
.T_data (T_data ),//运算数
.H_data (H_data ),//运算结果
.dat_en (dat_en ),//数字显示使能
.dot_en (dot_en ),//小数点使能
.lcd_rst (lcd_rst ),
.lcd_blk (lcd_blk ),
.lcd_dc (lcd_dc ),
.lcd_sclk (lcd_sclk ),
.lcd_mosi (lcd_mosi ),
.lcd_cs (lcd_cs ),
.init_done (init_done )
);
endmodule
这部分是顶层文件的代码,可以看到,整个工程被分成四部分:第一部分是按键矩阵的输入输出,该模块将按键信号读入处理之后变成一个16位的脉冲信号传输给计算模块;第二部分是计算模块,它控制计算器的运行状态,并将运算结果、运算符、运算状态进行输出;第三个部分是数码管显示模块,负责将运算模块输出的运算结果进行显示;第四部分是LCD显示模块,负责将运算模块输出的运算结果、运算符等在LCD上进行显示。
由于按键矩阵、数码管显示模块、LCD驱动模块参考官方的例程代码,这里不再进行赘述。
接下来只对运算模块进行说明:
首先是calculate模块:
//按键数值对应
reg[3:0] but_val;
always @ (key_pulse)
begin
case(key_pulse) //首先按照任务图片里的按键进行映射
16'h0001: but_val = 4'h7; // 7
16'h0002: but_val = 4'h8; // 8
16'h0004: but_val = 4'h9; // 9
16'h0008: but_val = 4'hd; // /
16'h0010: but_val = 4'h4; // 4
16'h0020: but_val = 4'h5; // 5
16'h0040: but_val = 4'h6; // 6
16'h0080: but_val = 4'hc; // *
16'h0100: but_val = 4'h3; // 3
16'h0200: but_val = 4'h2; // 2
16'h0400: but_val = 4'h1; // 1
16'h0800: but_val = 4'hb; // -
16'h1000: but_val = 4'h0; // 0
16'h2000: but_val = 4'he; // .
16'h4000: but_val = 4'hf; // =
16'h8000: but_val = 4'ha; // +
default: but_val = 4'h0; //
endcase
end
按照任务图片里的按键进行映射
//状态机,根据输入的多少个数、运算符号、等号等进行状态跳转
always@(posedge clk or negedge rst_n) begin
if(!rst_n)
begin
c_state <= STATE0;
num[0]<=4'd0;num[1]<=4'd0;num[2]<=4'd0;num[3]<=4'd0;symbol<=4'd0;
end
else if(init_done == 1'd0)
begin
c_state <= STATE0;
num[0]<=4'd0;num[1]<=4'd0;num[2]<=4'd0;num[3]<=4'd0;symbol<=4'd0;
end
else if(key_pulse!=(16'd0))
begin
case(c_state)
//
STATE0: begin //初始状态
if((key_pulse&16'b0001011101110111)!=16'd0)
begin
c_state <= STATE1;
num[0]<=num[0];num[1]<=but_val;symbol<=symbol;num[2]<=num[2];num[3]<=num[3];
end
else
begin
c_state <= STATE0;
num[0]<=4'd0;num[1]<=4'd0;symbol<=4'd0;num[2]<=4'd0;num[3]<=4'd0;
end
end
STATE1: begin//已经输入一个数
if((key_pulse&16'b1000100010001000)!=16'd0)
begin
c_state <= STATE3;
num[0]<=num[0];num[1]<=num[1];symbol<=but_val;num[2]<=num[2];num[3]<=num[3];
end
else if((key_pulse&16'b0001011101110111)!=16'd0)
begin
c_state <= STATE2;
num[0]<=num[1];num[1]<=but_val;symbol<=symbol;num[2]<=num[2];num[3]<=num[3];
end
else
begin
c_state <= c_state;
num[0]<=num[0];num[1]<=num[1];symbol<=symbol;num[2]<=num[2];num[3]<=num[3];
end
end
STATE2: begin //已经第二个数
if((key_pulse&16'b1000100010001000)!=16'd0)
begin
c_state <= STATE3;
num[0]<=num[0];num[1]<=num[1];symbol<=but_val;num[2]<=num[2];num[3]<=num[3];
end
else
begin
c_state <= c_state;
num[0]<=num[0];num[1]<=num[1];symbol<=symbol;num[2]<=num[2];num[3]<=num[3];
end
end
STATE3: begin //已经输入了运算符号
if((key_pulse&16'b0001011101110111)!=16'd0)
begin
c_state <= STATE4;
num[0]<=num[0];num[1]<=num[1];symbol<=symbol;num[2]<=num[2];num[3]<=but_val;
end
else
begin
c_state <= c_state;
num[0]<=num[0];num[1]<=num[1];symbol<=symbol;num[2]<=num[2];num[3]<=num[3];
end
end
STATE4: begin//已经输入第三个数
if((key_pulse&16'b0100000000000000)!=16'd0)
begin
c_state <= STATE6;
num[0]<=num[0];num[1]<=num[1];symbol<=symbol;num[2]<=num[2];num[3]<=num[3];
end
else if((key_pulse&16'b0001011101110111)!=16'd0)
begin
c_state <= STATE5;
num[0]<=num[0];num[1]<=num[1];symbol<=symbol;num[2]<=num[3];num[3]<=but_val;
end
else
begin
c_state <= c_state;
num[0]<=num[0];num[1]<=num[1];symbol<=symbol;num[2]<=num[2];num[3]<=num[3];
end
end
STATE5: begin //已经输入第四个数
if((key_pulse&16'b0100000000000000)!=16'd0)
begin
c_state <= STATE6;
num[0]<=num[0];num[1]<=num[1];symbol<=symbol;num[2]<=num[2];num[3]<=num[3];
end
else
begin
c_state <= c_state;
num[0]<=num[0];num[1]<=num[1];symbol<=symbol;num[2]<=num[2];num[3]<=num[3];
end
end
STATE6: begin//已经输入等号
c_state <= c_state;
num[0]<=num[0];num[1]<=num[1];symbol<=symbol;num[2]<=num[2];num[3]<=num[3];
end
default:begin
c_state <= STATE0;
num[0]<=4'd0;num[1]<=4'd0;symbol<=4'd0;num[2]<=4'd0;num[3]<=4'd0;
end
endcase
end
end
状态机,完成整个计算器的状态跳转
//加法运算
my_add my_add_inst(
.clk(clk) ,
.rst_n(rst_n), //复位信号
.symbol(symbol), //运算符号
.num1(num1),
.num2(num2),
.state(c_state),
.add_out(add_out), //
.add_flag(add_flag)
);
//减法运算
my_sub my_sub_inst(
.clk(clk) ,
.rst_n(rst_n), //复位信号
.symbol(symbol), //运算符号
.num1(num1),
.num2(num2),
.state(c_state),
.sub_out(sub_out), //
.sub_flag(sub_flag),
.zf(zf)
);
//乘法运算
my_mul my_mul_inst(
.clk(clk) ,
.rst_n(rst_n), //复位信号
.symbol(symbol), //运算符号
.num1(num1),
.num2(num2),
.state(c_state),
.mul_out(mul_out), //
.mul_flag(mul_flag)
);
//除法运算
my_div my_div_inst(
.clk(clk) ,
.rst_n(rst_n), //复位信号
.symbol(symbol), //运算符号
.num1(num1),
.num2(num2),
.state(c_state),
.div_out(div_out), //
.div_flag(div_flag),
.point_pos(point_pos)
);
四个运算模块,实现加减乘除。
//对运算结果进行拆解,拆解成数码管和LCD可以显示的单个数
reg [13:0] ans;
reg [15:0] ans_num;
reg c_flag;
always@(posedge clk or negedge rst_n) begin
if(!rst_n)
begin
ans<=14'd1;c_flag<=1'b0;
ans_num<=16'd0;
end
else if(c_flag)
begin
if(ans>=14'd1000)
begin
ans<=ans-14'd1000;
c_flag<=c_flag;
ans_num<={(ans_num[15:12]+4'd1),ans_num[11:0]};
end
else if(ans>=14'd100)
begin
ans<=ans-14'd100;
c_flag<=c_flag;
ans_num<={ans_num[15:12],(ans_num[11:8]+4'd1),ans_num[7:0]};
end
else if(ans>=14'd10)
begin
ans<=ans-14'd10;
c_flag<=c_flag;
ans_num<={ans_num[15:8],(ans_num[7:4]+4'd1),ans_num[3:0]};
end
else if(ans>=14'd1)
begin
ans<=ans-14'd1;
c_flag<=c_flag;
ans_num<={ans_num[15:4],(ans_num[3:0]+4'd1)};
end
else
begin
ans<=ans;
c_flag<=c_flag;
ans_num<=ans_num;
end
end
else if(((symbol==4'ha)&&add_flag)||((symbol==4'hc)&&mul_flag))
begin
ans<=(add_flag) ? add_out : mul_out;
c_flag<=1'b1;
ans_num<=16'd0;
end
else if(((symbol==4'hb)&&sub_flag))
begin
ans<=sub_out;
c_flag<=1'b1;
ans_num<=(~zf)?(16'd0):((sub_out>8'd9)?(16'h0b00):(16'h00b0));
end
else if(((symbol==4'hd)&&div_flag))
begin
ans<=div_out;
c_flag<=1'b1;
ans_num<=16'd0;
end
else
begin
ans<=ans;
c_flag<=c_flag;
ans_num<=ans_num;
end
end
对运算结果进行每个位拆解,用于数码管和LCD显示数据
//对显示数据进行更新
always@(posedge clk or negedge rst_n) begin
if(!rst_n)
begin
T_data<= 16'd0;
H_data<= 16'd0;
end
else
begin
case(c_state)
STATE0: begin
T_data<= 16'd0;
H_data<= 16'd0;
end
STATE1: begin
T_data<= {T_data[15:12],num[1],T_data[7:0]};
H_data<= H_data;
end
STATE2: begin
T_data<= {num[0],num[1],T_data[7:0]};
H_data<= H_data;
end
STATE3: begin
T_data<= T_data;
H_data<= H_data;
end
STATE4: begin
T_data<= {T_data[15:4],num[3]};
H_data<= H_data;
end
STATE5: begin
T_data<= {T_data[15:8],num[2],num[3]};
H_data<= H_data;
end
STATE6: begin
T_data<= T_data;
H_data<= ans_num;
end
default:begin
T_data<= T_data;
H_data<= H_data;
end
endcase
end
end
完成显示数据的更新;
//数字使能,小数点使能进行更新
reg [3:0] dat_en_1234;
reg [3:0] dat_en_5678;
always@(posedge clk or negedge rst_n) begin
if(!rst_n)
begin
dat_en_1234<= 4'd0;
end
else
begin
case(c_state)
STATE0: dat_en_1234 <= 4'd0; //L1,
STATE1: dat_en_1234 <= dat_en_1234|4'b0100; //L2,
STATE2: dat_en_1234 <= dat_en_1234|4'b1000; //L3,
STATE3: dat_en_1234 <= dat_en_1234; //L4,
STATE4: dat_en_1234 <= dat_en_1234|4'b0001; //L5,
STATE5: dat_en_1234 <= dat_en_1234|4'b0010; //L6,
STATE6: dat_en_1234 <= dat_en_1234;
default: dat_en_1234 <= dat_en_1234; //cycle为0,PWM占空比为0,低电平
endcase
end
end
reg [1:0] cnt_dat;
always@(posedge clk or negedge rst_n) begin
if(!rst_n)
begin
dat_en_5678<= 4'd0;
end
else if(c_state==STATE6&&ans==14'd0&&dat_en_5678==4'd0)
begin
if(symbol==4'hd)
begin
dat_en_5678<=4'b1111;
end
else
begin
if(ans_num[15:12]!=4'd0)
dat_en_5678<=4'b1111;
else if(ans_num[11:8]!=4'd0)
dat_en_5678<=4'b0111;
else if(ans_num[7:4]!=4'd0)
dat_en_5678<=4'b0011;
else
dat_en_5678<=4'b0001;
end
end
else
begin
dat_en_5678<= dat_en_5678;
end
end
assign dat_en ={dat_en_1234,dat_en_5678};
always@(posedge clk or negedge rst_n) begin
if(!rst_n)
begin
dot_en<= 8'd0;
end
else if(((symbol==4'hd)&&div_flag))
begin
dot_en<=(point_pos==2'd3)?(8'b00001000):(8'b00000100);
end
else
begin
dot_en<= dot_en;
end
end
完成数码管使能和小数点使能更新
接下来是每个运算模块
module my_add(
input clk ,
input rst_n, //复位信号
input [3:0] symbol, //运算符号
input [6:0] num1,
input [6:0] num2,
input [2:0] state,
output reg [7:0] add_out, //
output add_flag
);
reg flag;
reg flag_r;
always@(posedge clk or negedge rst_n) begin
if(!rst_n)
begin
add_out <= 8'd0;
flag<= 1'd0;
end
else if((state==3'd6)&&(symbol==4'ha))
begin
add_out <= num1 + num2;
flag<= 1'd1;
end
else
begin
add_out <= 8'd0;
flag<= 1'd0;
end
end
always@(posedge clk or negedge rst_n) begin
if(!rst_n)
flag_r<= 1'd0;
else
flag_r<=flag;
end
assign add_flag = flag&(~flag_r);
endmodule
加法模块,当状态机进入运算状态时进行相加,完成时输出一个脉冲信号
module my_sub(
input clk ,
input rst_n , //复位信号
input [3:0] symbol , //运算符号
input [6:0] num1 ,
input [6:0] num2 ,
input [2:0] state ,
output reg [7:0] sub_out , //
output sub_flag ,
output reg zf
);
reg flag;
reg flag_r;
always@(posedge clk or negedge rst_n) begin
if(!rst_n)
begin
sub_out <= 8'd0;
zf<= 1'b0;
flag<= 1'd0;
end
else if((state==3'd6)&&(symbol==4'hb))
begin
sub_out <= (num1>=num2)?(num1-num2):(num2-num1);
zf<= (num1==num2||num1>num2)?(1'b0):(1'b1);
flag<= 1'd1;
end
else
begin
sub_out <= 8'd0;
zf<= 1'b0;
flag<= 1'd0;
end
end
always@(posedge clk or negedge rst_n) begin
if(!rst_n)
flag_r<= 1'd0;
else
flag_r<=flag;
end
assign sub_flag = flag&(~flag_r);
endmodule
减法模块,当状态机进入运算状态时进行相减,完成时输出脉冲信号,同时需要输出运算结果的正负信号
module my_mul(
input clk ,
input rst_n , //复位信号
input [3:0] symbol , //运算符号
input [6:0] num1 ,
input [6:0] num2 ,
input [2:0] state ,
output reg [13:0] mul_out , //
output mul_flag
);
reg flag;
reg flag_r;
reg [3:0] cnt;
always@(posedge clk or negedge rst_n) begin
if(!rst_n)
begin
mul_out <= 14'd0;
flag<= 1'd0;
cnt <= 4'd0;
end
else if(cnt >= 4'd8)
begin
mul_out<=mul_out;
flag<=1'd1;
cnt <= cnt;
end
else if(cnt>4'd0)
begin
mul_out<=(num2[7-cnt])?({mul_out[12:0],1'b0}+num1):({mul_out[12:0],1'b0});//进行移位相加
flag<= 1'd0;
cnt <= cnt +4'd1;
end
else if((state==3'd6)&&(symbol==4'hc)&&(cnt==4'd0))
begin
mul_out <= 14'd0;
flag<= 1'd0;
cnt <= 4'd1;
end
else
begin
mul_out <= 14'd0;
flag<= 1'd0;
cnt <= 4'd0;
end
end
always@(posedge clk or negedge rst_n) begin
if(!rst_n)
flag_r<= 1'd0;
else
flag_r<=flag;
end
assign mul_flag = flag&(~flag_r);
endmodule
乘法模块,主要核心思想是进行移位相加,运算完成时输出脉冲信号
module my_div(
input clk ,
input rst_n , //复位信号
input [3:0] symbol , //运算符号
input [6:0] num1 ,
input [6:0] num2 ,
input [2:0] state ,
output [15:0] div_out , //
output div_flag ,
output reg [1:0] point_pos
);
reg flag;
reg flag_r;
reg [4:0] cnt;
reg [2:0] cnt_bit;
reg [3:0] zero_pos;
reg [7:0] num_d;
reg [15:0] bin_div;
reg [28:0] bin_x;
wire [7:0] num_d_2;
wire num_bu;
assign num_d_2=num_d-num2;
assign num_bu=((cnt_bit==3'd7)?(1'b0):(num1[6-cnt_bit]));
//完成移位相减功能
always@(posedge clk or negedge rst_n) begin
if(!rst_n)
begin
bin_div <= 16'd0;
num_d <= 8'd0;
cnt <= 5'd0;
cnt_bit <= 3'd0;
end
else if(cnt == 5'd17)
begin
bin_div <= bin_div;
num_d <= num_d;
cnt <= cnt;
cnt_bit <= cnt_bit;
end
else if(cnt>=5'd1)
begin
bin_div <= {bin_div[14:0],(num_d>=num2)};
num_d <= (num_d>=num2)?({num_d_2[6:0],num_bu}):({num_d[6:0],num_bu});
cnt <= (num1>num2)?((bin_div==16'd0)?(cnt +(num_d>=num2)):(cnt+5'd1)):(cnt+5'd1);
cnt_bit <=(cnt_bit==3'd7)?(cnt_bit):(cnt_bit+3'd1);
end
else if((state==3'd6)&&(symbol==4'hd)&&(cnt==5'd0))
begin
bin_div <= 16'd0;
num_d <= (num1>num2)?(8'd0):(num1);
cnt <=5'd1;
cnt_bit <= (num1>num2)?(3'd0):(3'd7);
end
else
begin
bin_div <= 16'd0;
num_d <= 8'd0;
cnt <= 5'd0;
cnt_bit <= 3'd0;
end
end
reg flag_z;
//记录小数点的位置
always@(posedge clk or negedge rst_n) begin
if(!rst_n)
begin
zero_pos<= 4'd0;
flag_z <= 1'b0;
end
else if(cnt>=5'd1 && cnt<=5'd16 &&flag_z==1'b0)
begin
zero_pos<=(cnt_bit==3'd7)?(cnt-1):(4'd0);
flag_z <=(cnt_bit==3'd7)?(1'b1):(1'b0);
end
else
begin
zero_pos<=zero_pos;
flag_z <=flag_z;
end
end
//将除法结果乘100或者1000,方便后面进行拆分,用于显示
always@(posedge clk or negedge rst_n) begin
if(!rst_n)
begin
bin_x<= 26'd0;
point_pos<=2'd0;
flag<=1'b0;
end
else if(cnt == 5'd17)
begin
bin_x<=(zero_pos>=4'd4)?({bin_div,6'd0}+{bin_div,5'd0}+{bin_div,2'd0}):({bin_div,10'd0}-{bin_div,4'd0}-{bin_div,3'd0});
point_pos<=(zero_pos>=4'd4)?(2'd2):(2'd3);
flag<=1'b1;
end
else
begin
bin_x<=bin_x;
point_pos<=point_pos;
flag<=flag;
end
end
wire [13:0] div_mid;
//对乘100或者1000的结果进行截位,截取乘100或1000之后小数点之前的数
assign div_mid = {bin_x[28-zero_pos],bin_x[27-zero_pos],bin_x[26-zero_pos],bin_x[25-zero_pos],bin_x[24-zero_pos],bin_x[23-zero_pos]
,bin_x[22-zero_pos],bin_x[21-zero_pos],bin_x[20-zero_pos],bin_x[19-zero_pos],bin_x[18-zero_pos],bin_x[17-zero_pos],bin_x[16-zero_pos]
,bin_x[15-zero_pos]};
always@(posedge clk or negedge rst_n) begin
if(!rst_n)
flag_r<= 1'd0;
else
flag_r<=flag;
end
assign div_flag = flag&(~flag_r);
assign div_out = div_mid+ bin_x[14-zero_pos];
endmodule
这是除法模块
九、仿真波形图
顶层文件calculator仿真图
按键输入部分仿真
计算模块仿真
数码管显示模块仿真
LCD驱动仿真模块