资源描述
(word完整版)FPGA查找表法sin函数的实现
实验一 Sin(x)函数的计算
一、实验要求
1、系统可以根据输入的角度(或弧度)x,显示相应的sin(x)数值,保证角度精度≤0。1度。
2、编辑测试激励文件,进行相关测试,注意测试的完备性。
3、根据DE2板资源,设计下载测试方案,并且完成硬件下载测试。
二、实验方案
本实验要求用FPGA实现角度(0度~360度)的Sin函数的计算,角度的分辨率小于等于0.1度。考虑到实现的简便性,本实验采用查表法实现Sin函数的计算。首先我们用Matlab计算出Sin函数值,然后生成.mif文件.用Matlab生成的.mif文件在Quartus中配置FPGA的Rom。跟具输入的角度值得到其Sin函数值存储的Rom地址,然后根据地址取出Rom中存储的Sin函数值,最后显示在数码管上,从而实现Sin函数的计算。
三、实验过程及代码
1. Matlab中.mif文件的生成
由于输入的角度值为0度~360度,所以计算出的Sin函数值至少有3600个,但由于Sin函数值的对称性,所以实际上存储在FPGA的Rom中的值只需要900个。因此在Matlab中我们设置depth=1024,在这里我们对Sin函数值做了扩大10000倍后四舍五入取整的处理,以便于在Rom中存储,所以在这里我们设置width=14。Matlab中的程序如下:
clear all;
close all;
clc;
t=[0:0。1:90]; %角度
x=pi*t/180; %弧度数
sin_val=sin(x); %sin函数值
fid=fopen(’sine。mif’,'wt'); %以wt格式打开文件sine。mif
fprintf(fid,'width=14;\r\n'); %设置width=14
fprintf(fid,'depth=1024;\n'); %设置depth=1024
fprintf(fid,’address_radix=uns;\n');
fprintf(fid,’data_radix=dec;\n’);
fprintf(fid,'content begin\n');
for j=1:901
i=j-1;
fprintf(fid,’%d:% d;\n’,i,round(sin_val(j)*10000));
end
fprintf(fid,'end;\n’);
fclose(fid);
然后利用宏功能模块编制LPM_ROM存放上面的数据,取名sin_rom。v,用上面编写的sine。mif初始化这个模块,自动生成的Verilog代码。
2、顶层模块
顶层模块采用Verilog HDL语言编写,保存为sinx.v。输入信号包括一个时钟信号clk,一个复位信号rst_n,一个9位的输入角度的整数部分a,一个4位的输入角度的小数部分b,输出信号包括6个7位的数码管显示信号。由于在Rom中只存储了900个Sin函数值,所以需要对输入的角度进行转换,然后根据转换后的地址对Rom寻址,得在其函数值,在顶层模块中对得到的函数值进行为的的分离,得到函数值的每一位,用于数码管的显示。代码如下:
module sinx(clk,rst_n,a,b,hex0,hex1,hex2,hex3,hex4,hex5);
input clk,rst_n;
input [8:0] a;
input [3:0] b;
output [6:0] hex0,hex1,hex2,hex3,hex4,hex5;
reg [3:0] data1,data2,data3,data4,data5;
wire [3:0] data0;
wire [13:0] q;
wire [9:0] addr;
reg [13:0] qr;
jiaodu U(
.clk(clk),
.a(a),
。b(b),
.addr(addr),
.fh(data0)
);
sin_rom sin_rom_inst (
。address ( addr ),
.clock ( clk ),
。q ( q )
);
reg [2:0] num;
always @(posedge clk or negedge rst_n)
begin
if (!rst_n)
begin
num <=3’d0;
qr <=14'd0;
end
else
begin
qr <= q;
num 〈= num+1’b1;
case(num)
3'd1 : data1 <=qr%4’d10;
3’d2 : data2 <=(qr/4’d10)%4’d10;
3'd3 : data3 <=(qr/8'd100)%4'd10;
3'd4 : data4 〈=(qr/10'd1000)%4'd10;
3'd5 : data5 <=(qr/10’d10000);
default : ;
endcase
if(num ==3'd6) num <=3'd0;
end
end
led led0(rst_n,data0,hex0);
led led1(rst_n,data1,hex1);
led led2(rst_n,data2,hex2);
led led3(rst_n,data3,hex3);
led led4(rst_n,data4,hex4);
led led5(rst_n,data5,hex5);
endmodule
3、输入角度的转换
由于在Rom中只存储了900个Sin函数值,所以需要对输入的角度根据其所在的象限得到其Sin函数值的Rom地址,同时给出Sin函数值的符号。在这里输入的角度值分为整数和小数部分,整数部分从0~360共360个值,所以在这里输入的整数部分a定义9位,用9个开关输入。小数部分从0~9共10个值,在这里输入的小数部分b定义4位,用4个开关输入。程序中addr是Sin函数值2的储存地址,fh代表的函数值的符号。
module jiaodu(clk,a,b,addr,fh);
input clk;
input [8:0] a;
input [3:0] b;
output [9:0] addr;
output [3:0] fh;
reg [3:0] fh;
reg [9:0] addr;
reg [12:0] c;
always @(posedge clk )
begin
c <= a*4'd10+b;
if (2700< c 〈=3600)
begin
addr 〈= 3600-c;
fh <=4'ha;
end
else if(1800< c 〈=2700)
begin
addr <= c—1800;
fh <=4’ha;
end
else if (900< c 〈=1800)
begin
addr <=1800-c;
fh 〈=4’hb;
end
else
begin
addr 〈=c;
fh 〈=4’hb;
end
end
endmodule
4、数码管显示
根据输入的data_in的值别对sm_db赋值用于数码管的显示。
module led( rst_n,data_in,sm_db);
input rst_n;
input[3:0] data_in;
output[6:0] sm_db;
reg[6:0] sm_db;
always @ (data_in or rst_n)
begin
if(!rst_n)
sm_db <= 7’b1000000;
else
begin
case (data_in)
4’h0: sm_db <= 7’b1000000;
4'h1: sm_db <= 7’b1111001;
4’h2: sm_db <= 7'b0100100;
4’h3: sm_db <= 7’b0110000;
4’h4: sm_db <= 7'b0011001;
4’h5: sm_db 〈= 7’b0010010;
4'h6: sm_db 〈= 7’b0000010;
4'h7: sm_db <= 7'b1111000;
4'h8: sm_db <= 7'b0000000;
4’h9: sm_db 〈= 7’b0011000;
4’ha: sm_db 〈= 7'b0111111;
4'hb: sm_db 〈= 7’b1111111;
default: ;
endcase
end
end
endmodule
四、实验体会
通过此次实验,我系统的了解了FPGA系统设计的全过程.学会了用verilog语言描述电路,学会了利用宏功能模块编制LPM_ROM存放数据,并用编写的.mif文件初始化这个模块。在这过程中我遇到了一些问题,但通过努力解决了。这让我明白了我们要有随时面对突发问题的心理准备。
展开阅读全文