FPGA Verilog 曼彻斯特编码译码 同步 DPLL(二)


前言

前面进行了曼彻斯特编码的讲解,只要注意数据来源频率与编码时钟频率之间的关系就能够精准进行编码工作。同样这两个问题也是保证译码工作的关键!


一、译码时钟与数据之间的相位差

目前是两个cpld开发板之间的通信,板a对数据源进行曼彻斯特编码,将编码完的数据通过传输线接到板b进行译码,但是由于传输过程本身的干扰,数据到达板b之后出现了一定的频率后移,表现为数据与译码时钟存在不规则的相位差,同时这个相位差不断变化影响到了译码的正确率。
如图所示:
在这里插入图片描述
这样的话,即使你和编码时钟保持一致,译码也会完全出错,所以这时候需要引入数字锁相环DPLL对曼彻斯特编码进行时钟的提取,保障时钟与数据的对齐,通过数字锁相环消除相位差对于译码造成的影响。不过对于高频的信号来讲,数字锁相环不一定能够完全使得提取的时钟与数据之间的稳定,它会缩小两者之间的相位差,但这时候的相位差小于半个周期,并不会对译码正确率造成影响。

二、数字锁相环

这是整体数字锁相环的工作框架,其中包括相位比较器、振荡器以及滤波器。其中我觉得比较关键的就是相位比较器。这是相位比较器需要实现的功能,通过获取相位差进行生成超前和滞后信号,为后续的振荡器以及滤波器提供输入以及方向。
在这里插入图片描述
在这里插入图片描述

三、使用步骤

1.顶层结构

代码如下:

/* Top module, output 2 clocks, one for clk_base and one for clk_freq */
//`include "freqdivider_multiple.v"
//`include "phasecomparator.v"
//`include "randomwalkfilter.v"
//`include "variableresetrandomwalkfilter.v"
module dpll(
	 sys_rst,
    MainClock,
    SignalIn, SignalOut, SignalOutX2, SynchronousSignal,
    Lock,InputSignalEdge, OutputSignalEdge,InputSignalDownEdge,
	 Positive, Negative,
	 Lead, Lag,
	 PeriodCount,DividerMaxValue,
	 crc_flag,
	 data,data_code,data_code1,led,led1,led2,
	 spi_cs,spi_sclk,spi_miso,spi_mosi,
	 dis_clk,dis_miso,dis_cs,dis_flag,
    );
	 input sys_rst;
    input  SignalIn;                // input signal
    input  MainClock;               // reference signal
    output wire SignalOut;               // output
	 output wire SignalOutX2;				   // output of multiple of 2
    output  wire Positive, Negative;      // internal DPLL signals
    output wire Lead, Lag;               // internal DPLL signals
    output wire InputSignalEdge, OutputSignalEdge,InputSignalDownEdge;
    output wire Lock;
    output wire SynchronousSignal;
    output wire  [7:0] PeriodCount;
    output wire  [7:0] DividerMaxValue;
	 output  led,led1,led2;
	 output data;
	 output wire crc_flag;
	 output wire data_code;
	 output wire data_code1;
	 output spi_cs,spi_sclk,spi_mosi;//cs16-pb12  sclk18-pb13 mosi26-pb15
	 input spi_miso;//miso20-pb14
	 output dis_clk,dis_miso,dis_cs,dis_flag;

	// reg sys_rst=1'b1;
	wire [15:0] data_uart;
	wire flag;
    parameter DividerMultiple = 2;//输出为基带时钟的二倍频,即频带时钟
	
    // phase comparator 
    phasecomparator inst_ph_cmp(.sys_rst(sys_rst),.MainClock(MainClock), .InputSignal(SignalIn),
                                .OutputSignal(SignalOut), .Lead(Lead), .Lag(Lag),
                                .InputSignalEdge(InputSignalEdge), .OutputSignalEdge(OutputSignalEdge),.InputSignalDownEdge(InputSignalDownEdge),
                                .Lock(Lock), .SynchronousSignal(SynchronousSignal),
                                .PeriodCount(PeriodCount)
                                );
    /*
    // "Zero-Reset Random Walk Filter"
    randomwalkfilter inst_zrwf(.MainClock(MainClock), .Lead(Lead), .Lag(Lag),
                               .Positive(Positive), .Negative(Negative)
                               );
    */
    
	//    defparam inst_freqdiv.DividerMaxValue;
    
    // "Variable-Reset Random Walk Filter"
    variableresetrandomwalkfilter inst_zrwf(.MainClock(MainClock), .Lead(Lead), .Lag(Lag),
                               .Positive(Positive), .Negative(Negative)
                               );
    
    // controlled frequency divider
    freqdivider_multiple inst_freqdivmul(.sys_rst(sys_rst),.MainClock(MainClock), .FrequencyOut(SignalOut), .FrequencyOutX2(SignalOutX2), .DividerMax(PeriodCount/DividerMultiple),
                               .Positive(Positive), .Negative(Negative), .DividerMaxValue(DividerMaxValue)
                               );
										 
	 yima inst_yima(.clk(SignalOut),.rst_n(sys_rst),.rxd(SignalIn),.data_code(data_code)
						);
//    data_change data_change_inst(.clk(MainClock),.rst_n(sys_rst),.data_i(data_code),.error_flag(crc_flag)
//    );
//	 

		//SignalOut-3pin-10m  SignalOutX2-2pin-5m
//	 data_singe_double data_singe_double_inst(
//           .clk(SignalOutX2),
//           .rst_n(sys_rst),
//           .data_i(data_i),   //一位输入
//			  .flag(flag),
//			  .flag2(flag2),
//			  .pllout(pllout),
//           .data_o(data_o) 	//8位并行输出
//    );
one_sixteen one_sixteen_inst(
	                         .clk(SignalOutX2),
	                         .rst_n(sys_rst),
	                         .din(data_code),
	                         .send(flag),
	                         .dout(data_uart)
);	 

SPI_Master SPI_Master_inst(
           .I_clk(MainClock)       , // 全局时钟50MHz
           .I_rst_n(sys_rst)     , // 复位信号,低电平有效
	        .I_tx_en(flag)     , // 数据打包完成,可以进行spi传输标志
           .I_data_in(data_uart)   , // 要发送的数据

           .I_spi_miso(spi_miso)  , // SPI串行输入,用来接收从机的数据
           .O_spi_sck(spi_sclk)   , // SPI时钟
           .O_spi_cs(spi_cs)    , // SPI片选信号
           .O_spi_mosi(spi_mosi)    // SPI输出,用来给从机发送数据    
);
	 assign dis_miso = spi_mosi;
    assign dis_clk = spi_sclk;
	 assign dis_cs = spi_cs;
	 assign dis_flag = flag;
    assign data = SignalIn;
	 

endmodule


2.译码

代码如下:

//该代码主要负责接受曼彻斯特编码 并进行解码 解码后的数据在28pin 展示 

module yima(
	//global signal                           
	input  clk,
	input  rst_n,
	//STM32 port

	input rxd,	
	//input clk_bps_en,
	output reg data_code
	
	
);

//编码数据定义
reg [1:0] temp; //存储1-01 0-10
reg flag1=0;
reg flag2=0;
reg fail=0;


always @ (posedge clk)
begin
	temp <= {rxd,temp[1]};
	if(temp == 2'b00 || temp == 2'b11)
	begin
		flag1 <= 1;//开始译码标志
	end
end

always @ (negedge clk)
begin
	if(flag1==1 )
	begin
	
		flag2 <= ~flag2;//开始译码标志
	end
end

always @ (posedge flag2)
begin
	if(temp == 2'b10)
	begin
		data_code <= 0;
		fail <= 0;
	end
	else if(temp == 2'b01)
	begin
		data_code <= 1;
		fail <= 0;
	end
	else if(temp == 2'b00 || temp ==2'b11)
	begin
		data_code <= 0;
		fail <= 1;
	end
end



endmodule

代码太多了,没有全复制,如果有人想看一下可以后台私信联系我。本身这一部分代码是参考网上很多人的进行整合修改的。

总结

实际上板之后仿真通过,通过示波器观察信号波形能够获取正确的信号波形。

  • 7
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Verilog曼彻斯特译码是一种数字信号编码技术,适用于将进制信号传输到物理媒介中,并能有效降低传输过程中的错误率。 曼彻斯特编码通过将一位进制数据分成两个时钟周期,在每个周期内通过改变信号电平的方式来编码数据。如果输入数据位为0,则第一个时钟周期的输出为高电平,而第个时钟周期的输出为低电平。相反,如果输入数据位为1,则第一个时钟周期的输出为低电平,而第个时钟周期的输出为高电平。 在Verilog中,可以使用if-else语句来实现曼彻斯特译码逻辑。以下是一个简化的Verilog代码示例: ``` module manchester_decoder( input wire clk, input wire encoded_data, output wire decoded_data ); reg previous_bit; always @(posedge clk) begin if (encoded_data) begin // 数据位为1 if (previous_bit == 0) decoded_data <= 1; else decoded_data <= 0; end else begin // 数据位为0 if (previous_bit == 0) decoded_data <= 0; else decoded_data <= 1; end previous_bit <= encoded_data; end endmodule ``` 在上面的代码中,输入参数`clk`是时钟信号,`encoded_data`是经过曼彻斯特编码后的信号输入,`decoded_data`是解码后的进制数据输出。通过检测输入信号的电平变化和之前一位数据的状态,该模块能够将编码后的数据重新还原为原始的进制信号。 曼彻斯特译码在许多通信和储存应用中广泛使用,因为它具有高可靠性和防止误码的特性。它还可用于解决数据传输中的时钟同步问题,确保数据始终与接收方的时钟同步

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值