项目需求:
- 可调电压源:能够产生直流电压,且电压值可以数控,变化范围从-3V到+3V,由于是原型设计,负载能力支持到20mA即可;
- 信号发生器:基于DDS的任意波形产生,能够生成频谱分量高达100KHz的任意波形,尤其是3种常用的波形:正弦波、方波、三角波,除了波形可以选择外,频率设置的精度达到1Hz,幅度调节范围为最高5Vpp,且都可数字控制;
- 电压表/示波器:能够测量直流电压、采集0-10KHz的交流信号,并将采集到的波形进行频谱分析;
- 频率计的功能:能够测量外部信号的频率
项目系统设计及核心代码:
基于需求,本项目通过利用PWM和低通滤波器产生任意幅度的信号,进而实现信号发生器和可调电压源;通过利用PWM和低通滤波器产生任意幅度的信号,再通过比较器将参考信号和外部输入信号进行比较,进而实现电压表和示波器。此外,本项目通过UART和上位机进行通信,并在上位机设计相应的界面来实现人机交互。
项目管脚分配如下图所示,其中,为了节约资源和便于与示波器相连,任意信号发生器模块和直流电压模块均采用23号管脚。
项目整体的RTL示意图如下图所示:
项目总体资源占用情况(不包括fft)如下图所示:
任意信号发生器模块和直流电压模块均通过改变PWM的占空比并将输出信号通过低通滤波器来输出任意幅值的电压或波形。核心代码如下,其中clk_240为利用PLL输出的高频时钟信号,用于控制任意信号发生器中PWM的输出,以保证PWM信号的输出频率远高于相应电路图中二阶RC低通滤波器的截止频率:
reg signed[5:0]sin1[0:7];
reg signed[5:0]square[0:1];
reg signed[5:0]triangle[0:7];
reg [4:0]count_num;
reg signed [15:0] wave1;
always @(posedge clk_signal or negedge flag) begin
if(!flag) begin
sin1[0] = 0;sin1[1] = 5; sin1[2] = 7;sin1[3] = 5;sin1[4] = 0;sin1[5] = -5; sin1[6] = -7;sin1[7] = -5;
square[0] = 7;square[1]=-7;
triangle[0] = -7; triangle[1] = -3;triangle[2] = 0;triangle[3] = 3;triangle[4] = 7;triangle[5] = 3;triangle[6] = 0;triangle[7] = -3;
count_num <= 0;
duty = 0;
end
else begin
case(type)
2'b00: begin
if(count_num==7) count_num <= 0;
if(amplitude==32) wave1[15:5] = sin1[count_num];
if(amplitude<32&&litude>=16) wave1[15:4] = sin1[count_num];
if(amplitude<16&&litude>=8) wave1[15:3] = sin1[count_num];
if(amplitude==0) wave1 = 0;
end
2'b01: begin
if(count_num==1) count_num <= 0;
if(amplitude==32) wave1[15:5] = square[count_num];
if(amplitude<32&&litude>=16) wave1[15:4] = square[count_num];
if(amplitude<16&&litude>=8) wave1[15:3] = square[count_num];
if(amplitude==0) wave1 = 0;
end
2'b10: begin
if(count_num==7) count_num <= 0;
if(amplitude==32) wave1[15:5] = triangle[count_num];
if(amplitude<32&&litude>=16) wave1[15:4] = triangle[count_num];
if(amplitude<16&&litude>=8) wave1[15:3] = triangle[count_num];
if(amplitude==0) wave1 = 0;
end
endcase
count_num <= count_num+1;
wave1 = wave1+offset+448;
duty <=wave1[15:4];
end
end
reg [5:0] count_pwm;
always @(posedge clk_240) begin
if(!flag) begin
count_pwm<=0;
dds<=0;
end
else begin
count_pwm<=count_pwm+1;
if(count_pwm<=duty) dds<=0;
else dds<=1;
end
end
reg [23:0] count;
always @(posedge clk_in) begin
if(!flag) begin
clk_signal<=0;
count<=0;
end
else begin
count<=count+1;
if(count==freq) begin
count<=0;
clk_signal<=1;
end
else clk_signal<=0;
end
end
电压表和示波器模块也通过PWM和低通滤波器输出任意幅度的信号,并将输出值输入比较器作为参考信号。通过比较器,将参考信号和外部输入信号进行比较,并通过比较器的输出判断参考信号和外部输入信号的大小关系,进而实现任意电压值的测量和电压波形的显示。核心代码如下:
reg [5:0] duty;
always @(posedge clk_measure or negedge flag ) begin
if(!flag) begin
duty<=1;
data1=0;
end
else begin
if(current_state == 0) begin
data1 = duty;
duty<=duty-1;
end
else begin duty<=duty+1;end
end
end
reg [5:0] count_pwm;
always@(posedge clk_240) begin
if(!flag) begin
pwm1<=1;
count_pwm<=0;
end
else begin
count_pwm<=count_pwm+1;
if(count_pwm <= duty) pwm1 <= 1;
else pwm1 <= 0;
end
end
和上述两个模块相似,频率计模块主要利用的也是PWM,通过PWM和低通滤波器产生指定幅度的信号,再通过比较器的输出判断输入信号与该参考信号的大小关系。由于外部输入信号为正弦波、方波或三角波,在信号的一个周期内,比较器的输出相应的会发生一次切换。因此,可通过判断一定时间内,比较器输出的切换次数即可得到输出信号的频率。具体核心代码如下:
reg compare_out_r;
always @ (posedge clk_in) begin
if(!flag) compare_out_r <= 1'b0;
else compare_out_r <= compare_out;
end
wire neg_compare_out_en = compare_out_r & (~compare_out);
reg [7:0] freq_count;
reg [29:0] count_clk;
reg count_clk1;
always @(posedge clk_in or negedge flag) begin
if(!flag) begin
freq_count<=0;
count_clk<=0;
count_clk1<=0;
tx_data<=0;
end
else begin
count_clk<=count_clk+1;
if(count_clk==30'd119_999) begin
count_clk1<=1;
count_clk<=0;
end
if(neg_compare_out_en) begin
freq_count<=freq_count+1;
end
if(count_clk1&&freq_count!=0) begin
tx_data<=freq_count;
count_clk1<=0;
freq_count<=0;
end
end
end
UART通信模块用于实现人机交互,代码参考电子森林网站上的例程,网址:
https://www.eetree.cn/wiki/uart%E4%B8%B2%E5%8F%A3%E6%A8%A1%E5%9D%97
项目的功能:
实现了直流电压、任意波形发生器、电压表、示波器和频率计,但未能够实现信号的频谱分析。
遇到的问题:
- 由于假期内仅有一个比较器,设备有限,无法确保任意波形发生器中输出波形,误以为比较器产生了损坏,且无法得到符合要求的波形图
解决方案:在回校后,通过示波器查看实际发出信号的波形后,提高PWM信号的频率。并利用Lattice Diamond 中针对PLL的IP核实现时钟的倍频,进一步提升PWM信号的频率。
- 由于对Lattice Diamond 中针对FFT的IP核的了解有限,未能实现针对信号波形的FFT
解决方案:未解决
- 由于FPGA的资源有限,无法成功实现乘法器或除法器
解决方案:通过移位实现乘法或除法,从而大幅度降低FPGA的运算量