基于FPGA的正弦波和及滤波
任务要求
现在要完成一个fpga的实验任务,要求是利用ZYNQ开发板FPGA板XILINX 7020 芯片,1.利用dds原理生成三种不同频率的正弦波,2.将生成的三种不同频率的正弦波加在一起3.能通过滤波器提取其中一种。
本文主要展示仿真,上板也没有问题,有问题可以评论区交流。其实就是FPGA实现的功能,只用到了PL端,没有用到PS端。
一、整体架构
该模块主要由以下几个部分组成:
时钟管理模块(PLL):生成系统所需的 200MHz 时钟
3 路 DDS 模块:分别生成 3M、10M 和 20M 频率的正弦波
信号叠加模块:将 3 路正弦波相加
FIR 滤波模块:对叠加后的的信号进行滤波处理
二、verilog代码功能实现
1.时钟模块
通过 PLL IP 核生成 200MHz 工作时钟:
pll pll_inst (
.clk_out1(clk_200m), // 输出200MHz时钟
.reset(~rst_n), // 复位信号(高有效)
.locked(locked), // 锁定信号,时钟稳定后为高
.clk_in1(clk) // 输入时钟
);
采用 PLL 可以提供稳定的高频时钟,有利于提高 DDS 输出波形的精度
rst_nn信号将外部复位和 PLL 锁定信号结合,确保系统在时钟稳定后才开始工作
2.DDS 信号生成模块
实例化了 3 个不同频率的 DDS 模块,频率通过改变频率字的大小来实现:
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2025/08/18 19:54:32
// Design Name:
// Module Name: DDS_3M
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module DDS_3M(
input clk,//50m Hz
input rst_n,
output [11:0] data
);
parameter fre_word = 32'd64424509; //频率控制字 fre_word = f_out * 2^N / fclk N为累加器位宽
reg [31:0] addr_sin;
//相位累加器
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
addr_sin <= 32'b0;
else
addr_sin <= addr_sin + fre_word;
end
wire [11:0]addra = addr_sin[31:20];
//ROM IP核的调用
sin_rom sin_rom1 (
.clka(clk), // input wire clk 时钟
.addra(addra), // input wire [11 : 0] addra 相位累加器输入给rom的地址
.douta(data) // output wire [11 : 0] douta 从ROM返回的数据(3M正弦波的采样点)
);
endmodule
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2025/08/18 19:54:32
// Design Name:
// Module Name: DDS_3M
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module DDS_10M(
input clk,//50m Hz
input rst_n,
output [11:0] data
);
parameter fre_word = 32'd214748364; //频率控制字 fre_word = f_out * 2^N / fclk N为累加器位宽
reg [31:0] addr_sin;
//相位累加器
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
addr_sin <= 32'b0;
else
addr_sin <= addr_sin + fre_word;
end
wire [11:0]addra = addr_sin[31:20];
//ROM IP核的调用
sin_rom sin_rom2 (
.clka(clk), // input wire clk 时钟
.addra(addra), // input wire [11 : 0] addra 相位累加器输入给rom的地址
.douta(data) // output wire [11 : 0] douta 从ROM返回的数据(3M正弦波的采样点)
);
endmodule
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2025/08/18 19:54:32
// Design Name:
// Module Name: DDS_3M
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module DDS_20M(
input clk,//50m Hz
input rst_n,
output [11:0] data
);
parameter fre_word = 32'd429496729; //频率控制字 fre_word = f_out * 2^N / fclk N为累加器位宽
reg [31:0] addr_sin;
wire [11:0] addra;
//相位累加器
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
addr_sin <= 32'b0;
else
addr_sin <= addr_sin + fre_word;
end
assign addra = addr_sin[31:20];
//ROM IP核的调用
sin_rom sin_rom3 (
.clka(clk), // input wire clk 时钟
.addra(addra), // input wire [11 : 0] addra 相位累加器输入给rom的地址
.douta(data) // output wire [11 : 0] douta 从ROM返回的数据(3M正弦波的采样点)
);
endmodule
三个 DDS 模块均工作在 200MHz 时钟下,保证相位同步
分别输出 3M、10M 和 20M 的正弦波信号
3.信号叠加
// 正弦波和
assign wave_sum1 = data_3M + data_10M + data_20M;
4.FIR滤波
输入为叠加后的 14bit 信号(wave_sum1)
输出为滤波后的信号(sin_data),位宽为 34bit([33:0])
m_tvalid2信号指示输出数据有效
滤波器可以设计为低通、高通或带通类型,根据需要提取 3M、10M 或 20M 中的某一频率成分
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2025/08/20 09:27:54
// Design Name:
// Module Name: FIR
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module FIR
(
input clk,
input rst_n,
input [13:0] Xin1,
output m_tvalid2,
output signed [33:0] Yout
);
reg s_tvalid;
//相位累加器
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
s_tvalid <= 1'b0;
else
s_tvalid <= 1'b1;
end
wire s_tready2;
wire [39:0] m_tdata2;
fir_unsig fir_unsig_inst (
.aclk(clk), // input wire aclk
.s_axis_data_tvalid(s_tvalid), // input wire s_axis_data_tvalid
.s_axis_data_tready(s_tready2), // output wire s_axis_data_tready
.s_axis_data_tdata({{2{1'b0}},Xin1}), // input wire [15 : 0] s_axis_data_tdata
.m_axis_data_tvalid(m_tvalid2), // output wire m_axis_data_tvalid
.m_axis_data_tdata(m_tdata2) // output wire [39 : 0] m_axis_data_tdata
);
assign Yout = m_tdata2[33:0];
endmodule
5.顶层模块
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2025/08/18 20:09:54
// Design Name:
// Module Name: DDS
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
`timescale 1ns / 1ps
module DDS(
input clk,
input rst_n,
output wire [11:0] data_3M,
output wire [11:0] data_10M,
output wire [11:0] data_20M,
output wire [13:0] wave_sum1,
output wire [33:0] sin_data
);
wire clk_200m;
wire locked;
wire rst_nn;
assign rst_nn = rst_n & locked;
// 正弦波和
assign wave_sum1 = data_3M + data_10M + data_20M;
pll pll_inst (
.clk_out1(clk_200m), // output clk_out1
.reset(~rst_n), // input reset
.locked(locked), // output locked
.clk_in1(clk) // input clk_in1
);
DDS_3M DDS_3M_inst(
.clk(clk_200m),
.rst_n(rst_nn),
.data(data_3M)
);
DDS_10M DDS_10M_inst(
.clk(clk_200m),
.rst_n(rst_nn),
.data(data_10M)
);
DDS_20M DDS_20M_inst(
.clk(clk_200m),
.rst_n(rst_nn),
.data(data_20M)
);
wire m_tvalid;
FIR FIR_inst (
.clk(clk),
.rst_n(rst_nn),
.Xin1(wave_sum1),
.m_tvalid2(m_tvalid),
.Yout(sin_data)
);
endmodule
6.TB仿真测试文件
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2025/08/18 20:19:30
// Design Name:
// Module Name: tb_DDS
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module tb_DDS();
// 输入信号
reg clk;
reg rst_n;
// 输出信号
wire [11:0] data_3M;
wire [11:0] data_10M;
wire [11:0] data_20M;
wire [13:0] wave_sum;
wire [33:0] sin_data;
// 实例化 DDS 模块
DDS uut (
.clk(clk),
.rst_n(rst_n),
.data_3M(data_3M),
.data_10M(data_10M),
.data_20M(data_20M),
.wave_sum1(wave_sum),
.sin_data(sin_data)
);
// 50 MHz 时钟生成 (周期 = 20 ns)
always #10 clk = ~clk; // 每10ns翻转一次,产生50MHz时钟
// 初始化信号
initial begin
// 初始化输入
clk = 0;
rst_n = 0; // 初始复位状态
// 释放复位
#20 rst_n = 1; // 20ns后释放复位
end
endmodule
总结
具体的ip核调用就搜一下配置就行,都是最简单的那种,基本都是默认。注意就是fir的话选择有符号系数,但是波形选的无符号输入,我忘了为啥这样了,反正两个都是有符号或者无符号的话,一直不对,也没管原因。