2024寒假FPGA电弧定位工作总结

1. m序列发生器

m序列理论分析

为了产生发射信号,首先得产生m序列。本文选择的m序列的级数n为6,m序列周期N的计算公式为 ,故N取63 m序列自相关函数示意图如下 Alt text

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序列波形图 alt text

2. DDS信号发生模块

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) alt text

3. 生成2PSK调制信号

顶层文件如下

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

按键消抖状态机流程图如下 Alt text 总体电路的RTL图如下 Alt text 引脚配置如下 Alt text Alt text 仿真2PSK调制波形对应m序列如下图 alt text

4. 调制信号注入电缆并采集

由于注入端与220V零火线直接相连,为防止FPGA损坏,必须加入隔离模块再注入到线缆。隔离模块电路设计图如下 Alt text DDS输出的2PSK调制信号在示波器上测量如下 Alt text 输入端(黄色)与反射端(绿色)信号在示波器上测量如下 Alt text 通过示波器波形保存功能,保存采集到的波形(.csv格式),在matlab中对输入与反射的波形做互相关运算,得到互相关函数,找到最大峰值与第二大峰值,即可得出线缆长度 互相关函数示意图如下,此图表示故障点发生在线缆20米处左右 Alt text

5. 总结

  1. 基本了解了DDS的相关应用,能较为熟练地写出生成指定频率、相位指定的verilog代码,生成相应的底层集成电路
  2. 学习了通信原理中的m序列,了解到m序列的生成原理并能通过代码实现
  3. 深刻理解了通信原理课程中2PSK调制在实际生活中的应用,领会到了其实学校所学知识是有用的
  4. 第一次尝试FPGA相关的开发,代码可能有冗余的部分,可能也有考虑不周到的bug,欢迎大佬指教,我会向大佬们多多学习请教
  5. 感谢小梅哥的大量学习视频及代码,从中收获了很多FPGA相关的开发流程及技巧,通过修改小梅哥的一些模块,达到我想要的效果,从而举一反三

本文章使用limfx的vscode插件快速发布