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;