Quartus 曼彻斯特码 CRC校验

VHDL 曼彻斯特编解码

曼彻斯特码

曼彻斯特码,即曼彻斯特编码(Manchester Encoding),也叫做相位编码(PE),是一个同步时钟编码技术,被物理层使用来编码一个同步位流的时钟和数据。在曼彻斯特编码中,每一位的中间有一跳变,位中间的跳变既作时钟信号,又作数据信号;从低到高跳变表示“1”,从高到低跳变表示“0”。

说明

最近完成了一个串行通信的项目,采用光纤作为物理层材料,FPGA为控制器。协议方面以4个高电平作为起始位,数据宽度28位数无停止位,通过修改程序使原8个时钟周期判断一位数据变为2位时钟判断一位数据,加快了解码的速度,降低了解码时钟所需频率。

曼彻斯特编码

编码部分较为简单,流程为加同步头、串并转换。

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use work.PCK_CRC8_D1.ALL;

entity coding is
 generic (dat_wide		: integer := 21;
 			head_wide	: integer := 4
 			);
 Port ( Clk 			: in  STD_LOGIC;
        Clk_div_2    : in  STD_LOGIC;
        Pid_data 		: in  STD_LOGIC_VECTOR (dat_wide-1 downto 0);--输入并行码
        Pod_manch 	: out STD_LOGIC);
end coding;

architecture Behavioral of coding is

 signal Sbd_manch		:	std_logic := '0';--曼切斯特码内部信号
 signal Sbd_NRZ			:	std_logic := '0';--串行码元
 signal Sbd_NRZ_reg	:	std_logic_vector(2 downto 0) := (others => '0');--串行码元(经3个时钟延时)
 signal Sbd_cnt			:	integer range 0 to head_wide + dat_wide +10 := 0;
 signal Sbd_data		:	std_logic_vector( dat_wide + 7 downto 0) := ( others => '0' );
 signal Sbd_crc_1		:	std_logic_vector( 7 downto 0 ) := ( others => '0' );

begin
----------------------------------------------------------------------------------
--组合运算
----------------------------------------------------------------------------------	
 Pod_manch	<=	Sbd_manch;
 Sbd_data		<= Pid_data & Sbd_crc_1;
----------------------------------------------------------------------------------
--NRZ串行码延时两个时钟进程,通过两个D触发器实现
----------------------------------------------------------------------------------	
Pr_d	:	process(Clk)
 		begin
 			if rising_edge(Clk) then
 				if Clk_div_2 = '1' then
 					Sbd_NRZ_reg(0) <= Sbd_NRZ;
 					Sbd_NRZ_reg(1) <= Sbd_NRZ_reg(0);
 					Sbd_NRZ_reg(2) <= Sbd_NRZ_reg(1);
 				else
 					null;
 				end if;
 			end if;
 		end process;
 		
----------------------------------------------------------------------------------
--时钟计数进程,计数值Sbd_cnt用于对并转串和编码进程进行控制
----------------------------------------------------------------------------------		
Pr_count	:	process(Clk)	
 			begin	
 				if rising_edge(Clk) then		
 					if Clk_div_2 = '1' then
 						if Sbd_cnt < (head_wide + dat_wide +10) then--4+21+8+2=35
 							Sbd_cnt <= Sbd_cnt + 1;
 						else
 							Sbd_cnt <= 0;
 						end if;
 					else
 						null;
 					end if;
 				end if;
 			end process;
----------------------------------------------------------------------------------
--并转串进程,通过计数移位的方式实现,并行输入:Pid_data,串行输出:Sbd_NRZ
----------------------------------------------------------------------------------
Pr_1	:	process(CLK)
 		begin
 			if rising_edge(CLK) then
 				if Clk_div_2 = '1' then
 					case Sbd_cnt is
 						when 0	=>	
 							Sbd_crc_1 <= ( others => '0' );
 						when 1	=>
 							Sbd_crc_1 <= nextCRC8_D1( Sbd_data( 28 ), Sbd_crc_1);
 						when 2 to dat_wide	=>
 							Sbd_NRZ 		<= Sbd_data( (dat_wide + 7) - conv_integer( Sbd_cnt - 2 ) );--并转串
 							Sbd_crc_1 	<= nextCRC8_D1( Sbd_data( (dat_wide + 7) - conv_integer( Sbd_cnt - 1 ) ), Sbd_crc_1);
 						when dat_wide + 1 to dat_wide + 9	=>
 							Sbd_NRZ <= Sbd_data( (dat_wide + 7) - conv_integer( Sbd_cnt - 2 ) );--并转串
 						when others	=>
 							Sbd_NRZ <= '0';
 					end case;
 				else
 					null;
 				end if;
 			end if;
 		end process;
 							
----------------------------------------------------------------------------------
--曼切斯特编码进程,加入3个时钟的高电平同步头,编码完成输出标志位Poc_flag
----------------------------------------------------------------------------------
 Pr_2	:	
 process(Clk)
 begin
 	if rising_edge(Clk) then
 		case Sbd_cnt is
 			when 0 to 1		=>	
 				Sbd_manch <= '0'; 
 			when 2 to head_wide + 1	=>
 				Sbd_manch <= '1';
 			when head_wide + 2 to 34	=>
 				if Sbd_NRZ_reg(2) = '1' then
 					Sbd_manch <= not Clk_div_2;
 				else
 					Sbd_manch <= Clk_div_2;
 				end if;
 			when others		=>
 				Sbd_manch <= '0'; 
 		end case;
 	end if;
 end process;
end Behavioral;

曼彻斯特解码

解码采用状态机实现,分为三个状态:idle(空闲),decod(编码),error(错误)。解码流程如下:1、判断同步头,连续接收到4个高电平即可认为是同步头。2、判断是接收的一位数据是0还是1,详情见下图示意。3、接收到指定长度的数据后串转并输出。
判断数据
判断接收的数据,在 计数器为01的时刻判断,如果此时接收的电平为高电平就判断为1,反之为0。上述通过01时刻就可以判断出数据为0或1,增加10时刻判断是因为01时刻此时的寄存器还没更新数据,从寄存器读到的数据是旧的数据,而10时刻寄存器已更新。


library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use work.PCK_CRC8_D1.ALL;

entity decoding is
	generic (dat_wide		: integer := 21
				);
    Port ( 	
				CLK								: in  STD_LOGIC;
				DECODE_EN						: in  STD_LOGIC;
				MANCHESTER_WITHOUT_HEADER	: in  STD_LOGIC;	--输入的曼切斯特码
				DECODE_ERROR					: out	STD_LOGIC;
				DECODE_OUT						: out std_logic_vector( (dat_wide-1) downto 0)	--解码后的串行编码
				);
end decoding;
 
architecture Behavioral of decoding is
----------------------------------------------------------------------------------
	signal crc8_data_reg 		:	std_logic_vector( 7 downto 0 ) := (others => '0');
	signal crc8_data				:	std_logic_vector( 7 downto 0 ) := (others => '0');
	signal manchester_data		:  std_logic_vector( dat_wide + 8 downto 0) := (others => '0');
	signal decode_reg1			:	std_logic := '0';
	signal decode_reg2			:	std_logic := '0';
	signal decode_coder			:	std_logic := '0';--输出串行码元内部信号
	signal coder_cnt				:	std_logic_vector( 1 downto 0 ) := (others => '0');--时钟计数
   --signal coder_fall_cnt		:	std_logic_vector( 1 downto 0 ) := (others => '0');--时钟计数,用于判断码的‘0’‘1’状态
	signal manchester_cnt		:	std_logic_vector( 4 downto 0 ) := (others => '0');--
	signal decoder_end			:	std_logic := '0';
	signal decoder_end_reg		:	std_logic := '0';
	signal decod_end_reg_cnt1	:	std_logic_vector(10 downto 0) := (others => '0');

begin
----------------------------------------------------------------------------------
--组合运算 
----------------------------------------------------------------------------------
--	DECODE_OUT	<= manchester_data(28 downto 8);
--	Pod_crc 		<= crc8_data;
----------------------------------------------------------------------------------
--曼切斯特码解码
----------------------------------------------------------------------------------
	Pr_rising_cnt_CLK	:	
	process(CLK)
	begin
		if falling_edge(CLK) then
			if DECODE_EN = '0' then
				coder_cnt <= (others => '0');								
			else
				if coder_cnt < "10" then--3
					coder_cnt <= coder_cnt + 1; 
				else
					coder_cnt <= "01";
				end if;
			end if;
		end if;
	end process;
	
----------------------------------------------------------------------------------
--判断电平
----------------------------------------------------------------------------------				
	Pr_just	:	process(CLK)
						begin
							if rising_edge(CLK) then
								if DECODE_EN = '0' then
									decode_reg1 <= '0';
									decode_reg2 <= '0';
								else
									if (coder_cnt = "01") then
										if MANCHESTER_WITHOUT_HEADER = '0' then
											decode_reg1 <= '0';
											decode_reg2 <= '1';
										else
											decode_reg1 <= '1';
											decode_reg2 <= '0';
										end if;
									else
										null;
									end if;
								end if;
							end if;
						end process;
	Pr_decode	:	process(CLK)
						begin
							if rising_edge(CLK) then
								if DECODE_EN = '0' then
									DECODE_ERROR <= '0';
									decode_coder <= '0';
								else
									if coder_cnt = "10" then
										if decode_reg1 = '0' and decode_reg2 = '1' then
											decode_coder <= '0';
											DECODE_ERROR <= '0';
										elsif decode_reg1 = '1' and decode_reg2 = '0' then
											decode_coder <= '1';
											DECODE_ERROR <= '0';
										else
											DECODE_ERROR <= '1';
										end if;
									else
										DECODE_ERROR <= '0';
									end if;
								end if;
							end if;
						end process;									
											
----------------------------------------------------------------------------------	
--串转并处理和CRC8校验
----------------------------------------------------------------------------------				
	Pr_tran	:	
	process(CLK)
	begin
		if rising_edge(CLK) then
			if DECODE_EN = '0' then
				manchester_cnt <= (others => '0');
				crc8_data_reg <= (others => '0');
				decoder_end <= '0';
			else
				if coder_cnt < "10" then--7
					manchester_cnt <= manchester_cnt;
				else
					manchester_cnt <= manchester_cnt + 1;
					manchester_data ( (dat_wide + 8) - conv_integer( manchester_cnt ) ) <= decode_coder;--以串行码开头作为高位
					if manchester_cnt < dat_wide+1 then--21
						decoder_end <= '0';
						crc8_data_reg <= nextCRC8_D1( decode_coder, crc8_data_reg);
					elsif manchester_cnt < (dat_wide + 8) then--29
						decoder_end <= '0';
					else
						decoder_end <= '1';
--						DECODE_OUT	<= manchester_data(28 downto 8);
						crc8_data <= crc8_data_reg;
					end if;
				end if;
			end if;
		end if;
	end process;
----------------------------------------------------------------------------------
--输出标志位
----------------------------------------------------------------------------------
	Pr_d	:	
	process(CLK)
	begin
		if rising_edge(CLK) then
			decod_end_reg_cnt1(0) 				<= decoder_end;
			decod_end_reg_cnt1(10 downto 1) 	<= decod_end_reg_cnt1(9 downto 0);
			decoder_end_reg 						<= decod_end_reg_cnt1(10);
		end if;
	end process;
	
	Pr_mark	:	
	process(CLK)
	begin
		if rising_edge(CLK) then
			if ( crc8_data = manchester_data(7 downto 0) )and ( decoder_end_reg = '1' ) then
				DECODE_OUT	<= manchester_data((dat_wide + 7) downto 8);
			else
				null;
			end if;
		end if;
	end process;
end Behavioral; 


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
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`是解后的二进制数据输出。通过检测输入信号的电平变化和之前一位数据的状态,该模块能够将编后的数据重新还原为原始的二进制信号。 曼彻斯特在许多通信和储存应用中广泛使用,因为它具有高可靠性和防止误的特性。它还可用于解决数据传输中的时钟同步问题,确保数据始终与接收方的时钟同步。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值