1 项目介绍
项目四-DDS任意波形发生器/PC远程控制
- 通过板上的高速DAC配合FPGA内部DDS的逻辑,生成波形可调(正弦波、三角波、方波)、频率可调(DC-)、幅度可调的波形。
- 生成模拟信号的频率范围为DC-20MHz,调节精度为1Hz。
- 生成模拟信号的幅度为最大1Vpp,调节范围为0.1V-1V。
- 通过UART同PC连接,在PC上可以使用Matlab、Labview或其它调试工具来控制波形的切换、参数的改变。
2 设计思路
2.1 整体设计思路
- PC通过USB转TTL串口模块向FPGA发送波形、幅度、频率等信息。
- FPGA通过内部DDS逻辑产生数字数据。
- DAC进行数模转换产生不同波形。
- 示波器观测波形、幅度、频率等信息。
2.2 FPGA设计思路
- pll_120M:利用内部锁相环将12MHz的时钟倍频为120MHz的时钟。
- uart_rx:接收串行数据,经过抽样判决、串并转换,转换为并行数据。
- phase_acc:根据相位步进寄存器phase_k,进行相位累加。
- wave:根据不同波形、幅度、频率,输出数字数据。
- rom_sin:保存1/4周期的正弦数据,根据不同的地址输出不同的正弦数据。
框图如下:
3 硬件介绍
3.1 USB转TTL串口模块
USB转TTL串口模块是一个非常实用的工具,可以测试模块的UART串口通信,能够在电脑上的串口助手软件非常直观的显示出串口设备返回的数据以及发送相应的控制数据给串口设备。常见的有CP2102、PL2303、FT232、CH340等串口芯片方案的USB转串口模块。本项目采用CH340串口芯片方案的USB转串口模块。
3.2 基于小脚丫FPGA的电赛训练平台
采用Lattice小脚丫FPGA XO-4000HC、电赛训练板。利用板上的高速DAC配合FPGA内部DDS的逻辑实现本项目。
3.3 基于STM32F072的多功能掌中仪器
基于STM32F072微控制器,支持双通道示波器、单通道波形发生器、单通道脉冲发生器、双路可调直流电压源,240*240 LCD显示,2个按键和一个拨轮开关,适合教学实验使用以及低于100KHz频率以内的测试测量。本项目利用其观察生成的波形并测量频率。
4 项目内容
4.1 PC端MATLABAPP
使用MATLABAPP,基于uart通过串口发送串行数据。传输协议为:波特率为300000,一位开始位,八位数据位,无校验位,一位结束位。第一帧传输信号类型,第二帧传输幅度,第三帧到第六帧传输相位步进值(先传低位,再传高位),第七帧为结束帧,表示传输完毕。
以下为“生成波形”按钮的回调函数:
%关闭串口
delete(instrfindall);
%模式选择
if(app.DropDown.Value == "正弦波")
mode = 0;
elseif(app.DropDown.Value == "方波")
mode = 1;
elseif(app.DropDown.Value == "锯齿波")
mode = 2;
end
if(app.HzEditField.Value == 0)
mode = 3;
end
%幅值
amplitude = app.VEditField.Value;
%频率
frequency = app.HzEditField.Value;
%连接端口
baud = 300000;
port = serialport("COM5",baud);
%发送数据
data = zeros(1,7);
data(1) = mode;
data(2) = round(250*amplitude);
data(3) = mod(frequency,256);
data(4) = mod((frequency-data(3))/256,256);
data(5) = mod((frequency-data(3)-data(4)*256)/256/256,256);
data(6) = mod((frequency-data(3)-data(4)*256-data(5)*256*256)/256/256/256,256);
data(7) = 0;
write(port,data,"uint8");
%关闭串口
delete(instrfindall);
本程序将默认使用端口COM5进行传输数据的传输,验证前请先在设备管理器中更改串行设备的端口号为COM5,如图所示:
4.2 top模块
连接系统内各个模块。输入有:12MHz晶振(C1)、复位按键key1(L14)、uart接收管脚(核心模块管脚编号39)(E12);输出有DAC_D9~D0、DAC_CLK。系统复位之后,默认输出生成幅度1V、频率1kHz的正弦波。
4.3 pll_120M模块
调用IP核,利用内部锁相环将频率为12MHz的时钟倍频为频率为120MHz的时钟。从而提高板上高速DAC的采样率以及产生更高频率的波形。
4.4 uart_rx模块
接收PC通过串口发送的串行数据,经过输入对齐、抽样判决、串并转换,将其转换为并行数据。同时根据顺序识别数据类型,对模式寄存器mode、幅度寄存器mul、相位步进寄存器phase_k进行更改,从而实现对产生信号的波形、幅度、频率的更改。
一位数据内有400个时钟周期,在第180、200、220个周期时进行抽样判决,保证数据准确性。
//判决计数
always @(posedge clk_120M or negedge rst_n) begin
if(~rst_n)
jud_cnt <= 2'd0;
else if(clk_cnt == 17'd180 || clk_cnt == 17'd200 || clk_cnt == 17'd220)
jud_cnt <= jud_cnt + bit_in_dly[2];
else if(clk_cnt == 17'd260)
jud_cnt <= 2'd0;
end
当并行数据准备完毕时,根据传输顺序更改模式寄存器mode、幅度寄存器mul、相位步进寄存器phase_k。
//并行输出
always @(posedge clk_120M or negedge rst_n) begin
if(~rst_n)
dout <= 8'd0;
else if(clk_cnt == 17'd240 && bit_cnt >= 4'd1 && bit_cnt <= 4'd8) begin
if(jud_cnt >= 2'd2)
dout[bit_cnt-4'd1] <= 1'b1;
else
dout[bit_cnt-4'd1] <= 1'b0;
end
end
//模式幅度相位步进
always @(posedge clk_120M or negedge rst_n) begin
if(~rst_n) begin
mode <= 2'd0;
mul <= 8'd255;
phase_k <= 27'd1000;
end else if((clk_cnt == 17'd210) && (bit_cnt == 4'd9)) begin
case(sel_cnt)
3'd1: mode <= dout[1:0];
3'd2: mul <= dout[7:0];
3'd3: phase_k[7:0] <= dout[7:0];
3'd4: phase_k[15:8] <= dout[7:0];
3'd5: phase_k[23:16] <= dout[7:0];
3'd6: phase_k[26:24] <= dout[2:0];
endcase
end
end
4.5 phase_acc模块
根据相位步进寄存器phase_k,对相位进行累加,相位最大值为27'd29296*4096。相位步进寄存器大小不同,导致相位累加的速度不同,则信号频率不同。
4.6 wave模块
考虑到FPGA内有92Kbit RAM,因此采用了地址长度为7325、幅度量化分辨率为10位的波表,用来保存1/4周期的正弦波数据,占用空间73.25Kbit,因此正弦波一个周期内有29296个点。(此处考虑尽可能利用FPGA内的RAM,从而产生更加完美的波形,暂不考虑硬件成本)
此时相位累加器的长度为15位,将其长度增加12位,根据公式计算输出信号频率:
fo=k*fc/m
其中,fo为输出信号频率,k为频率控制字,fc为时钟频率,m为一个周期内的点数。
计算得到此时输出的频率分辨率可以达到1Hz,为使得波形不出现明显失真,输出频率的范围为DC-20MHz。
根据相位累加器的[26:12]位计算得到地址。
//正弦地址
always @(posedge clk_120M or negedge rst_n) begin
if (~rst_n)
Address <= 13'd0;
else if(phase[26:12] >= 15'd0 && phase[26:12] <=15'd7323)
Address <= phase[24:12];
else if(phase[26:12] >= 15'd7324 && phase[26:12] <=15'd14647)
Address <= 15'd14648 - phase[26:12];
else if(phase[26:12] >= 15'd14648 && phase[26:12] <=15'd21971)
Address <= phase[26:12] - 15'd14648;
else if(phase[26:12] >= 15'd21972 && phase[26:12] <=15'd29295)
Address <= 15'd29296 - phase[26:12];
end
为节省内存资源,产生方波与锯齿波时,根据相位计算应当输出的电压值(模式0为正弦波,模式1为方波,模式2为锯齿波,模式3为直流)。
//数字数据
always @(posedge clk_120M or negedge rst_n) begin
if (~rst_n)
data <= 10'd0;
else if(mode == 2'd0) begin
if(phase_dly_3[26:12] >= 15'd7324 && phase_dly_3[26:12] <= 15'd21971)
data <= 10'd480 + ({8'd0,sin}*mul>>8);
else
data <= 10'd480 - ({8'd0,sin}*mul>>8);
end else if(mode == 2'd1) begin
if(phase_dly_3[26:12] >= 15'd0 && phase_dly_3[26:12] <= 15'd14647)
data <= 10'd480 + (18'd210*mul>>8);
else
data <= 10'd480 - (18'd210*mul>>8);
end else if(mode == 2'd2) begin
if(phase_dly_3[26:12] >= 15'd0 && phase_dly_3[26:12] <= 15'd7323)
data <= 10'd480 - ((23'd7323 -{8'd0,phase_dly_3[26:12]})*mul/6'd35>>8);
else if(phase_dly_3[26:12] >= 15'd7324 && phase_dly_3[26:12] <=15'd14647)
data <= 10'd480 + (({8'd0,phase_dly_3[26:12]}-23'd7324 )*mul/6'd35>>8);
else if(phase_dly_3[26:12] >= 15'd14648 && phase_dly_3[26:12] <=15'd21971)
data <= 10'd480 + ((23'd21971-{8'd0,phase_dly_3[26:12]})*mul/6'd35>>8);
else if(phase_dly_3[26:12] >= 15'd21972 && phase_dly_3[26:12] <=15'd29295)
data <= 10'd480 - (({8'd0,phase_dly_3[26:12]}-23'd21972)*mul/6'd35>>8);
end else if(mode == 2'd3) begin
data <= 10'd480;
end
end
4.7 rom_sin模块
采用了地址长度为7325、幅度量化分辨率为10位的波表,用来保存1/4周期的正弦波数据,根据不同的地址输出不同的正弦波数据。
5 项目成果
资源占用情况如下:
硬件连接如下:
通过UART同PC连接,在PC上使用Matlab控制波形的切换、参数的改变。
控制波形的切换:(生成1V;10Hz;正弦波、方波、锯齿波)
控制幅度的改变:(生成1V、0.6V、0.2V;10Hz;正弦波)
控制频率的改变:(生成1V;直流、10Hz、100Hz、1kHz、10kHz、50kHz;正弦波)
直流:
10Hz:
100Hz:
1kHz:
10kHz:
50kHz:
6 项目难点与改进方向
- 我认为确定波表地址、周期点数等数据是本项目的难点之一,需要计算硬件成本并且通过计算符合频率步进值与频率范围;其次,理解并且硬件实现DDS直接数字频率合成也是重难点之一。本项目中我投入了较多时间与精力来理解与计算,最终成功实现。
- 本项目中高速DAC的模拟参考电压Vref固定,无法改变,本项目要求Vpp为0.1V~1V,可以考虑降低模拟参考电压Vref,从而得到更加精细的模拟电压输出。
- 本项目中要求输出的频率范围比较广,因此DAC输出端较难选择滤波电路,为了得到频谱更加纯净的正弦波,可以考虑在DAC输出端连接合适的滤波电路。
7 附录
本项目的验证方式如下:
- 连接硬件:USB转TTL串口模块的TXD连接核心模块管脚39、GND连接核心模块管脚21(共地),USB口连接PC,设置端口号为COM5;DAC输出端连接示波器。
- 软件操作:下载SignalGenerator_impl1.jed至FPGA;使用MATLAB运行SignalGenerator.mlappinstall进行安装,之后运行该App。