一、项目要求
- 使用串行DAC AD5626设计一款任意波形发生器
- 搭配单片机或FPGA或其它方式的控制逻辑能够产生10Hz到20KHz范围内的正弦波信号
- 输出信号幅度要达到3Vpp,直流偏移可调1.5V到3.5V
- -使用ADALP2000模拟套件中的器件实现
- 使用套件中的Micro USB适配器通过USB给面包板供电,供电电压为5V
- 使用ADALP2000套件中的运算放大器搭建一个Sallen-Key滤波器,滤除40KHz以上的混叠信号,输出运算放大器也选自ADALP2000套件
- 运算放大器可从套件中提供的几个型号中选用
- DAC采用AD5626
- -实现方式:
- 设计电路并使用LTSpice或CircuitJS进行仿真
- 搭建实际的电路进行测试验证
- 撰写一个不少于2000字的设计报告,并拍摄3-5分钟短视频分享在电子森林网站上
二、需求分析
- 搭配单片机或FPGA或其它方式的控制逻辑能够产生10Hz到20KHz范围内的正弦波信号:使用STM32+iCE40平台,里面的ICE40UP5K FPGA做本次控制,使用按键对输出频率进行调节。
- 输出信号幅度要达到3Vpp,直流偏移可调1.5V到3.5V:要求输出3Vpp,使用AD5626本身即可做到,在输出3Vpp时偏移1.5V,波形整体在0-3V的范围内;偏移3.5V时,波形在2-5V的范围内。这样的话使用运放使用5V单电源供电即可实现功能。
- 使用ADALP2000套件中的运算放大器搭建一个Sallen-Key滤波器,滤除40KHz以上的混叠信号,输出运算放大器也选自ADALP2000套件:利用Analog Filter Wizard进行设计,LTSpice仿真优化即可。
- DAC采用AD5626:依照要求使用。
三、仿真电路搭建
1.整体电路
2.搭建滤波器
Sallen-key是设计有源滤波器设计的一种拓扑结构,VCVS(Voltage-controlled voltage-source)滤波器的变种,由麻省理工学院林肯实验室的R. P. Sallen and E. L. Key 在1955所提出。
Sallen-key拓扑的特点:
- 高输入阻抗
- 增益容易被配置
- 运放被配置为电压跟随(Voltage Follower)模式
这是Sallen-key滤波器的低通滤波器模型。模型中运放被配置成电压跟随模式。
本次需要设计一个40KHz低通滤波器,类型为Sallen-Key,使用ADALP2000套件器件搭建,由于可选器件不多,核心思想是尽可能简单,先用Analog Filter Wizard进行设计,再用LTSpice在ADALP2000套件可以搭建的范围进行慢慢实验。
可以看到最终输出的截止频率在43.5kHz左右,与要求相符合。
3.搭建直流偏置电路
运放直流偏置电路是一种基于运算放大器的电路,它通过添加适当大小和极性的直流电压来调整输入信号的直流分量,使其能够被运算放大器正确地处理。
这里我设计了一个放大倍数为1的反相放大电路,通过调节运放正输入端的电压调节输出偏移。
搭建实际电路时 V3 电源将使用电阻与滑动变阻器代替。
调整输出偏移为1.5V时。
调整输出偏移为2.5V时。
调整输出偏移为3.5V时
四、DAC电路设计
1.DAC输出硬件设计
AD5626属于nanoDAC®系列,是一款完整的串行输入、12位电压输出数模转换器(DAC),采用5 V单电源供电。它集成了DAC、输入移位寄存器和锁存、基准电压源和一个轨到轨输出放大器。AD5626单芯片DAC适合仅有5 V电源的系统应用,具有成本低、易于使用的特点,输出运算放大器摆幅可达到任一供电轨,且设置范围为0 V至4.095 V,分辨率为每位1 mV。它能提供5 mA的吸电流和源电流。片内集成经激光调整后的基准电压源,提供精确的4.095 V满量程输出电压。该器件采用高速、三线式、兼容数据输入(SDIN)的DSP、时钟(SCLK)和负载选通(LDAC)的串线接口。它还有芯片选择引脚,可连接多个DAC。
整体框图
2.DAC输出软件设计
整体参考之前设计过的基于STM32+iCE40平台实现的DDS任意波形发生器项目进行改动。
AD5626时序图片
dds部分
module dds(
input sys_clk,
input sys_rst_n,
input [2:0] wave_type,
input [23:0] wave_freq,
input [4:0] wave_range,
output [11:0] wave_dac
);
reg [32:0] dds_phase;//33位相位累加器
always @(posedge sys_clk) dds_phase <= dds_phase + wave_freq * 33'd716;//33'd179; //在12MHz的主时钟时,输出对应频率的波形
wire [9:0] sin_data; //sin波
wire [9:0] square_data; //方波
wire [9:0] trig_data; //三角波
reg [15:0] wave_data;
reg [9:0] a_ver;
sin_table u_sin_table(
.address(dds_phase[32:25]),
.sin(sin_data)
);
assign square_data = {10{dds_phase[32]}};
assign trig_data = dds_phase[32] ? ~dds_phase[31:22]: dds_phase[31:22];
always @(*)begin
case(wave_type)
3'd0: wave_data = 0;
3'd1: wave_data = square_data * a_ver;
3'd2: wave_data = trig_data * a_ver;
3'd3: wave_data = sin_data * a_ver;
endcase
end
always @(*)begin
begin
case(wave_range)
5'd0: a_ver = 10'd0;
5'd1: a_ver = 10'd3;
5'd2: a_ver = 10'd5;
5'd3: a_ver = 10'd8;
5'd4: a_ver = 10'd11;
5'd5: a_ver = 10'd13;
5'd6: a_ver = 10'd16;
5'd7: a_ver = 10'd19;
5'd8: a_ver = 10'd21;
5'd9: a_ver = 10'd23;
5'd10: a_ver = 10'd26;
endcase
end
end
assign wave_dac = wave_data[14:3];
endmodule
sin生成部分
module sin_table(
input [7:0] address,
output reg [9:0] sin
);
wire [1:0] section;
reg [5:0] lut_address;
reg [8:0] lut_sin;
assign section = address[7:6];
always@(address)begin
case(section)
2'b00: begin
lut_address = address[5:0];
sin = 9'h1ff + lut_sin;
end
2'b01: begin
lut_address = ~address[5:0];
sin = 9'h1ff + lut_sin;
end
2'b10: begin
lut_address = address[5:0];
sin = 9'h1ff - lut_sin;
end
2'b11: begin
lut_address = ~address[5:0];
sin = 9'h1ff - lut_sin;
end
endcase
end
always @(lut_address)
begin
case(lut_address)
6'h0: lut_sin=9'h0;
6'h1: lut_sin=9'hC;
6'h2: lut_sin=9'h19;
6'h3: lut_sin=9'h25;
6'h4: lut_sin=9'h32;
6'h5: lut_sin=9'h3E;
6'h6: lut_sin=9'h4B;
6'h7: lut_sin=9'h57;
6'h8: lut_sin=9'h63;
6'h9: lut_sin=9'h70;
6'ha: lut_sin=9'h7C;
6'hb: lut_sin=9'h88;
6'hc: lut_sin=9'h94;
6'hd: lut_sin=9'hA0;
6'he: lut_sin=9'hAC;
6'hf: lut_sin=9'hB8;
6'h10: lut_sin=9'hC3;
6'h11: lut_sin=9'hCF;
6'h12: lut_sin=9'hDA;
6'h13: lut_sin=9'hE6;
6'h14: lut_sin=9'hF1;
6'h15: lut_sin=9'hFC;
6'h16: lut_sin=9'h107;
6'h17: lut_sin=9'h111;
6'h18: lut_sin=9'h11C;
6'h19: lut_sin=9'h126;
6'h1a: lut_sin=9'h130;
6'h1b: lut_sin=9'h13A;
6'h1c: lut_sin=9'h144;
6'h1d: lut_sin=9'h14E;
6'h1e: lut_sin=9'h157;
6'h1f: lut_sin=9'h161;
6'h20: lut_sin=9'h16A;
6'h21: lut_sin=9'h172;
6'h22: lut_sin=9'h17B;
6'h23: lut_sin=9'h183;
6'h24: lut_sin=9'h18B;
6'h25: lut_sin=9'h193;
6'h26: lut_sin=9'h19B;
6'h27: lut_sin=9'h1A2;
6'h28: lut_sin=9'h1A9;
6'h29: lut_sin=9'h1B0;
6'h2a: lut_sin=9'h1B7;
6'h2b: lut_sin=9'h1BD;
6'h2c: lut_sin=9'h1C3;
6'h2d: lut_sin=9'h1C9;
6'h2e: lut_sin=9'h1CE;
6'h2f: lut_sin=9'h1D4;
6'h30: lut_sin=9'h1D9;
6'h31: lut_sin=9'h1DD;
6'h32: lut_sin=9'h1E2;
6'h33: lut_sin=9'h1E6;
6'h34: lut_sin=9'h1E9;
6'h35: lut_sin=9'h1ED;
6'h36: lut_sin=9'h1F0;
6'h37: lut_sin=9'h1F3;
6'h38: lut_sin=9'h1F6;
6'h39: lut_sin=9'h1F8;
6'h3a: lut_sin=9'h1FA;
6'h3b: lut_sin=9'h1FC;
6'h3c: lut_sin=9'h1FD;
6'h3d: lut_sin=9'h1FE;
6'h3e: lut_sin=9'h1FF;
6'h3f: lut_sin=9'h1FF;
endcase
end
endmodule
AD5626驱动
module ad5626(
input sys_clk,
input sys_rst_n,
input [11:0] data,
output reg spi_clk,
output reg spi_mosi,
output reg spi_cs,
output reg pin_clr,
output reg pin_ldac
);
reg [5:0] bit_cnt;
reg spi_en;
reg [11:0] data_r;
reg [2:0] freq_cnt;
always @(posedge sys_clk or negedge sys_rst_n)
begin
if(!sys_rst_n)
begin
freq_cnt <= 0;
spi_clk <= 1;
end
else
begin
if(freq_cnt == 0)
begin
spi_clk <= ~spi_clk;
freq_cnt <= 0;
end
else
begin
freq_cnt <= freq_cnt + 1;
spi_clk <= spi_clk;
end
end
end
always@(posedge sys_clk or negedge sys_rst_n)
begin
if(!sys_rst_n)
begin
spi_en<=0;
pin_clr<=0;
end
else
begin
spi_en<=1;
pin_clr<=1;
end
end
always@(posedge spi_clk)
begin
if(spi_en==0)
begin
bit_cnt<=20;
end
else
begin
case(bit_cnt)
0:begin spi_cs<=0;pin_ldac<=1;bit_cnt<=1; data_r<=data;end
1:begin spi_mosi<=data_r[11];bit_cnt<=2; end
2:begin spi_mosi<=data_r[10];bit_cnt<=3; end
3:begin spi_mosi<=data_r[9];bit_cnt<=4; end
4:begin spi_mosi<=data_r[8];bit_cnt<=5; end
5:begin spi_mosi<=data_r[7];bit_cnt<=6; end
6:begin spi_mosi<=data_r[6];bit_cnt<=7; end
7:begin spi_mosi<=data_r[5];bit_cnt<=8; end
8:begin spi_mosi<=data_r[4];bit_cnt<=9; end
9:begin spi_mosi<=data_r[3];bit_cnt<=10; end
10:begin spi_mosi<=data_r[2];bit_cnt<=11; end
11:begin spi_mosi<=data_r[1];bit_cnt<=12; end
12:begin spi_mosi<=data_r[0];bit_cnt<=13; end
13:begin spi_cs<=1;pin_ldac<=0;bit_cnt<=14; end
default:begin spi_cs<=1;pin_ldac<=0;bit_cnt<=0; end
endcase
end
end
endmodule
五、实际演示
实际电路
输出10KHz,3V幅度,1.5V偏移的正弦波
输出20KHz,3V幅度,1.5V偏移的正弦波
输出10KHz,3V幅度,3.5V偏移的正弦波
输出43KHz,3V幅度的正弦波,可以看到被衰减为2.1V,基本符合-3dB衰减。
六、心得体会
通过参与这个项目,我获得了很多宝贵的经验和知识。在第二阶段的实战作业中,我学会了如何根据需求产生信号,深入了解LTSpice和ADI常用工具使用方式。这些实践项目让我对模拟电路有了更深入的了解,让我对这个领域有了更全面的认识。不仅学习了很多理论知识,还通过实践操作加深了对模拟电路的理解。这种结合理论和实践的教学方法让我更好地掌握了知识,也更容易应用到实际工作中。我相信这将对我的未来发展和工作起到很大的帮助作用。在第三阶段的实战项目中,我将会继续努力,让这个课程有一个圆满的结束。非常感谢硬禾学堂提供了这样一门精彩的课程,让我在这个领域有了更深入的了解和掌握。