为了产生发射信号,首先得产生m序列。本文选择的m序列的级数n为6,m序列周期N的计算公式为 ,故N取63
m序列自相关函数示意图如下
m序列生成代码如下
module m_generator(clk,rst_n,en,m);
input clk,rst_n,en;//clk决定码元宽度
output reg m;
reg [5:0]m_reg;//m序列寄存器
initial begin
m_reg=6'b100000;//m序列初始值,除了000000都行
end
always @(posedge clk or negedge rst_n) begin
if(!rst_n)begin
m<=0;
m_reg<=6'b100000;
end
else if(!en)begin
m<=0;
m_reg<=6'b100000;
end
else begin
m_reg<={m_reg[0]^m_reg[5],m_reg[5:1]};//右移+补全
m<=m_reg[0];//输出最低位(书上说输出的就是a0),此处写[1]仿真更符合逻辑,本质都一样
//移位后最高位的补全,具体参数和方法见通信原理390页表
end
end
endmodule
仿真出的m序列波形图
DDS信号发生模块代码如下
module DDS_Module(
Clk,
Rst_n,
EN,
Fword,
Pword,
DA_Clk,
DA_Data,
m
);
input Clk;/*系统时钟*/
input Rst_n;/*系统复位*/
input EN;/*DDS模块使能*/
input [31:0]Fword;/*频率控制字*/
input [13:0]Pword;/*相位控制字*/
input m;
output DA_Clk;/*DA数据输出时钟*/
output [13:0]DA_Data;/*D输出输出A*/
reg [31:0]Fre_acc;
reg [13:0]Rom_Addr;
/*---------------相位累加器------------------*/
always @(posedge Clk or negedge Rst_n)
if(!Rst_n)
Fre_acc <= 32'd0;
else if(!EN)
Fre_acc <= 32'd0;
else
Fre_acc <= Fre_acc + Fword;//频率控制字
/*----------生成查找表地址---------------------*/
always @(posedge Clk or negedge Rst_n)
if(!Rst_n)
Rom_Addr <= 14'd0;
else if(!EN)
Rom_Addr <= 14'd0;
else begin
Rom_Addr <= Fre_acc[31:18]+Pword;
end
/*----------例化查找表ROM-------*/
rom rom1(
.address(Rom_Addr),
.clock(Clk),
.q(DA_Data)
);
/*----------输出DA时钟----------*/
assign DA_Clk = DA_Data>8191?1:0;
endmodule
DDS模块产生的正弦信号如下
由游标测量出正弦波频率为50MHz(周期200ns)
顶层文件如下
module PSK(clk_50M,rst_n,DAC_DATA1,DAC_DATA2,DACA_CLK,DACB_CLK,DACA_WRT,DACB_WRT,key,led_en);
input clk_50M;
input rst_n;
input key;
output reg[13:0]DAC_DATA1;
output reg[13:0]DAC_DATA2;
output DACA_CLK;
output DACB_CLK;
output DACA_WRT;
output DACB_WRT;
output led_en;
wire clk_125M;
wire clk_5M;
wire [5:0]m_init=6'b100000;
wire m;
wire DA_CLK;
wire key_flag;
wire key_state;
reg en;
assign DACA_CLK =clk_125M;
assign DACB_CLK =clk_125M;
assign DACA_WRT =clk_125M;
assign DACB_WRT =clk_125M;
initial begin
en<=0;
end
pll pll0(
.inclk0(clk_50M),
.c0(clk_125M),
.c1(clk_5M)
);
m_generator m_generator0(
.clk(DA_CLK),
.rst_n(rst_n),
.en(1),
.m(m)
);
key_filter key_filter0(
.Clk(clk_50M),
.Rst_n(rst_n),
.key_in(key),
.key_flag(key_flag),
.key_state(key_state)
);
wire [13:0]DA_data_temp;
DDS_Module DDS_Module0(
.Clk(clk_125M),
.Rst_n(rst_n),
.EN(en),
.Fword(171798692),
.Pword(0),
.DA_Clk(DA_CLK),
.DA_Data(DA_data_temp),
.m(m)
);
always@(posedge clk_50M or negedge rst_n)begin
if(!rst_n)
en<=0;
else if(key_flag && (!key_state))
en<=!en;
else
en<=en;
end
always @(posedge clk_125M or negedge rst_n) begin
if(!rst_n)begin
DAC_DATA1<=0;
DAC_DATA2<=0;
end
else begin
if(m)begin
DAC_DATA1<=16383-DA_data_temp;
DAC_DATA2<=16383-DA_data_temp;
end
else begin
DAC_DATA1<=DA_data_temp;
DAC_DATA2<=DA_data_temp;
end
end
end
assign led_en = !en;
endmodule
实际应用中加入按键控制,所以需要加入按键消抖模块,参考学习小梅哥的代码如下
/***************************************************
* Module Name : key_filter
* Engineer : 小梅哥
* Target Device : EP4CE10F17C8
* Tool versions : Quartus II 13.0
* Create Date : 2017-3-31
* Revision : v1.0
* Description : 单按键消抖设计
**************************************************/
module key_filter(
Clk, //50M时钟输入
Rst_n, //模块复位
key_in, //按键输入
key_flag, //按键标志信号
key_state //按键状态信号
);
input Clk;
input Rst_n;
input key_in;
output reg key_flag;
output reg key_state;
localparam
IDEL = 4'b0001,
FILTER0 = 4'b0010,
DOWN = 4'b0100,
FILTER1 = 4'b1000;
reg [3:0]state;
reg [19:0]cnt;
reg en_cnt; //使能计数寄存器
//对外部输入的异步信号进行同步处理
reg key_in_sa,key_in_sb;
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)begin
key_in_sa <= 1'b0;
key_in_sb <= 1'b0;
end
else begin
key_in_sa <= key_in;
key_in_sb <= key_in_sa;
end
reg key_tmpa,key_tmpb;
wire pedge,nedge;
reg cnt_full;//计数满标志信号
//使用D触发器存储两个相邻时钟上升沿时外部输入信号(已经同步到系统时钟域中)的电平状态
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)begin
key_tmpa <= 1'b0;
key_tmpb <= 1'b0;
end
else begin
key_tmpa <= key_in_sb;
key_tmpb <= key_tmpa;
end
//产生跳变沿信号
assign nedge = !key_tmpa & key_tmpb;
assign pedge = key_tmpa & (!key_tmpb);
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)begin
en_cnt <= 1'b0;
state <= IDEL;
key_flag <= 1'b0;
key_state <= 1'b1;
end
else begin
case(state)
IDEL :
begin
key_flag <= 1'b0;
if(nedge)begin
state <= FILTER0;
en_cnt <= 1'b1;
end
else
state <= IDEL;
end
FILTER0:
if(cnt_full)begin
key_flag <= 1'b1;
key_state <= 1'b0;
en_cnt <= 1'b0;
state <= DOWN;
end
else if(pedge)begin
state <= IDEL;
en_cnt <= 1'b0;
end
else
state <= FILTER0;
DOWN:
begin
key_flag <= 1'b0;
if(pedge)begin
state <= FILTER1;
en_cnt <= 1'b1;
end
else
state <= DOWN;
end
FILTER1:
if(cnt_full)begin
key_flag <= 1'b1;
key_state <= 1'b1;
state <= IDEL;
en_cnt <= 1'b0;
end
else if(nedge)begin
en_cnt <= 1'b0;
state <= DOWN;
end
else
state <= FILTER1;
default:
begin
state <= IDEL;
en_cnt <= 1'b0;
key_flag <= 1'b0;
key_state <= 1'b1;
end
endcase
end
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)
cnt <= 20'd0;
else if(en_cnt)
cnt <= cnt + 1'b1;
else
cnt <= 20'd0;
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)
cnt_full <= 1'b0;
else if(cnt == 20'd999_999)
cnt_full <= 1'b1;
else
cnt_full <= 1'b0;
endmodule
按键消抖状态机流程图如下
总体电路的RTL图如下
引脚配置如下
仿真2PSK调制波形对应m序列如下图
由于注入端与220V零火线直接相连,为防止FPGA损坏,必须加入隔离模块再注入到线缆。隔离模块电路设计图如下
DDS输出的2PSK调制信号在示波器上测量如下
输入端(黄色)与反射端(绿色)信号在示波器上测量如下
通过示波器波形保存功能,保存采集到的波形(.csv格式),在matlab中对输入与反射的波形做互相关运算,得到互相关函数,找到最大峰值与第二大峰值,即可得出线缆长度
互相关函数示意图如下,此图表示故障点发生在线缆20米处左右
本文章使用limfx的vscode插件快速发布