本文主要是介绍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 isgeneric (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 issignal 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)beginif rising_edge(Clk) thenif Clk_div_2 = '1' thenSbd_NRZ_reg(0) <= Sbd_NRZ;Sbd_NRZ_reg(1) <= Sbd_NRZ_reg(0);Sbd_NRZ_reg(2) <= Sbd_NRZ_reg(1);elsenull;end if;end if;end process;----------------------------------------------------------------------------------
--时钟计数进程,计数值Sbd_cnt用于对并转串和编码进程进行控制
----------------------------------------------------------------------------------
Pr_count : process(Clk) begin if rising_edge(Clk) then if Clk_div_2 = '1' thenif Sbd_cnt < (head_wide + dat_wide +10) then--4+21+8+2=35Sbd_cnt <= Sbd_cnt + 1;elseSbd_cnt <= 0;end if;elsenull;end if;end if;end process;
----------------------------------------------------------------------------------
--并转串进程,通过计数移位的方式实现,并行输入:Pid_data,串行输出:Sbd_NRZ
----------------------------------------------------------------------------------
Pr_1 : process(CLK)beginif rising_edge(CLK) thenif Clk_div_2 = '1' thencase Sbd_cnt iswhen 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;elsenull;end if;end if;end process;----------------------------------------------------------------------------------
--曼切斯特编码进程,加入3个时钟的高电平同步头,编码完成输出标志位Poc_flag
----------------------------------------------------------------------------------Pr_2 : process(Clk)beginif rising_edge(Clk) thencase Sbd_cnt iswhen 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' thenSbd_manch <= not Clk_div_2;elseSbd_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 isgeneric (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)beginif falling_edge(CLK) thenif DECODE_EN = '0' thencoder_cnt <= (others => '0'); elseif coder_cnt < "10" then--3coder_cnt <= coder_cnt + 1; elsecoder_cnt <= "01";end if;end if;end if;end process;----------------------------------------------------------------------------------
--判断电平
---------------------------------------------------------------------------------- Pr_just : process(CLK)beginif rising_edge(CLK) thenif DECODE_EN = '0' thendecode_reg1 <= '0';decode_reg2 <= '0';elseif (coder_cnt = "01") thenif MANCHESTER_WITHOUT_HEADER = '0' thendecode_reg1 <= '0';decode_reg2 <= '1';elsedecode_reg1 <= '1';decode_reg2 <= '0';end if;elsenull;end if;end if;end if;end process;Pr_decode : process(CLK)beginif rising_edge(CLK) thenif DECODE_EN = '0' thenDECODE_ERROR <= '0';decode_coder <= '0';elseif coder_cnt = "10" thenif decode_reg1 = '0' and decode_reg2 = '1' thendecode_coder <= '0';DECODE_ERROR <= '0';elsif decode_reg1 = '1' and decode_reg2 = '0' thendecode_coder <= '1';DECODE_ERROR <= '0';elseDECODE_ERROR <= '1';end if;elseDECODE_ERROR <= '0';end if;end if;end if;end process; ----------------------------------------------------------------------------------
--串转并处理和CRC8校验
---------------------------------------------------------------------------------- Pr_tran : process(CLK)beginif rising_edge(CLK) thenif DECODE_EN = '0' thenmanchester_cnt <= (others => '0');crc8_data_reg <= (others => '0');decoder_end <= '0';elseif coder_cnt < "10" then--7manchester_cnt <= manchester_cnt;elsemanchester_cnt <= manchester_cnt + 1;manchester_data ( (dat_wide + 8) - conv_integer( manchester_cnt ) ) <= decode_coder;--以串行码开头作为高位if manchester_cnt < dat_wide+1 then--21decoder_end <= '0';crc8_data_reg <= nextCRC8_D1( decode_coder, crc8_data_reg);elsif manchester_cnt < (dat_wide + 8) then--29decoder_end <= '0';elsedecoder_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)beginif rising_edge(CLK) thendecod_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)beginif rising_edge(CLK) thenif ( crc8_data = manchester_data(7 downto 0) )and ( decoder_end_reg = '1' ) thenDECODE_OUT <= manchester_data((dat_wide + 7) downto 8);elsenull;end if;end if;end process;
end Behavioral;
这篇关于Quartus 曼彻斯特码 CRC校验的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!