官方论坛
官方淘宝
官方博客
微信公众号
点击联系吴工 点击联系周老师

【案例】曼彻斯特编码解码设计

发布时间:2021-06-16   作者:admin 浏览量:

实验简述

将输入的数据流经过曼彻斯特编码器编码后经过解码器恢复为原来的输入序列。


一、曼彻斯特码简介

曼彻斯特码(Manchester code),又称数字双向码、分相码或相位编码(PE),是一种常用的二源码线路编码方式之一,被物理层使用来编码一个同步位流的时钟和数据。在通信技术中,用来表示所要发送比特流中的数据宇定时信号所结合起来的代码。常用在以太网通信,列车总线控制,工业总线等领域。


二、编码规则

有两个输入时钟,一个是基带时钟(起同步信号作用),一个是频带时钟。输入的数据流是基带时钟域信号,经过编码后变成频带时钟域信号输出。曼彻斯特编码是将输入为1的变成输出前半拍为1,后半拍为0,输入为0的变成前半拍为0,后半拍为1的频带信号。


三、时序图

输入序列以101为例,经过编码后应为100110

null


四、FPGA实现

1、顶层架构

null


2、信号说明

信号

功能

说明

clk_b

基带时钟,作为同步信号使用

外部输入

clk_f

频带时钟,系统工作时钟

外部输入

rst_n

系统复位

外部输入

enc_in

输入数据流

外部输入

enc_en

编码使能

外部输入

enc_out

数据流经编码后的输出,输入到解码模块

编码输出,解码输入

dec_en

解码使能

外部输入

dec_out

解码输出

输出


3、顶层代码

module manchester(clk_b, clk_f, rst_n, enc_in, enc_en, dec_out, dec_en);


   input clk_b, clk_f, rst_n;

   input enc_in;

   input enc_en;

   output dec_out;

   input dec_en;

   

   wire enc_out;

   

   manchester_enc ENC(

       .clk_f(clk_f),

       .clk_b(clk_b),

       .rst_n(rst_n),

       .enc_en(enc_en),

       .enc_in(enc_in),

       .enc_out(enc_out)

   );

   

   manchester_dec DEC(

       .clk_f(clk_f),

       .clk_b(clk_b),

       .rst_n(rst_n),

       .dec_en(dec_en),

       .enc_out(enc_out),

       .dec_out(dec_out)

   );

   

endmodule




4、编码模块


采用状态机来实现编码模块。

当检测到编码使能为高时,状态机开始执行,判断clk_b的值为1时,在S1状态等待,当clk_b的值为0时,判断输入的值是1还是0。(clk_b主要起基频同步作用)如果是1,跳转到S2状态,并将enc_out赋值为1。到S2状态后,无条件跳回S1状态,并将enc_out赋值为0。如果是0,跳转到S3状态,并将enc_out赋值为0。到S3状态后,无条件跳回S1状态,并将enc_out赋值为1。

状态转移图如下:


null

说明:圆圈代表状态,→ 代表转移,转移下面的文本框代表转移时的动作。以后文章的状态转移图均按此绘制。


编码模块代码

module manchester_enc(clk_f, clk_b, rst_n, enc_en, enc_in, enc_out);


   input clk_f, clk_b, rst_n;

   input enc_en;

   input enc_in;

   output reg enc_out;

   

   reg [2:0] state_c, state_n;

   

   localparam S1 = 3'b001;

   localparam S2 = 3'b010;

   localparam S3 = 3'b100;

   

   wire S12S2_start  ;

   wire S12S3_start  ;

   wire S22S1_start  ;

   wire S33S1_start  ;

   

    //四段式状态机


//第一段:同步时序always模块,格式化描述次态寄存器迁移到现态寄存器(不需更改-

   always@(posedge clk_f or negedge rst_n)begin

       if(!rst_n)begin

           state_c <= S1;

       end

       else begin

           state_c <= state_n;

       end

   end


//第二段:组合逻辑always模块,描述状态转移条件判斍

   always@(*)begin

       if(enc_en)

           case(state_c)

               S1:begin

                   if(S12S2_start)begin

                       state_n = S2;

                   end

                   else if(S12S3_start)begin

                       state_n = S3;

                   end

                   else begin

                       state_n = state_c;

                   end

               end

               S2:begin

                   if(S22S1_start)begin

                       state_n = S1;

                   end

                   else begin

                       state_n = state_c;

                   end

               end

               S3:begin

                   if(S33S1_start)begin

                       state_n = S1;

                   end

                   else begin

                       state_n = state_c;

                   end

               end

               default:begin

                   state_n = S1;

               end

           endcase

       else

           state_n = S1;

   end

//第三段:设计转移条件

   assign S12S2_start   = state_c==S1    && clk_b && !enc_in;

   assign S12S3_start   = state_c==S1    && clk_b && enc_in;

   assign S22S1_start   = state_c==S2    && 1;

   assign S33S1_start   = state_c==S3    && 1;


//第四段:同步时序always模块,格式化描述寄存器输出(可有多个输出-

   always @(posedge clk_f or negedge rst_n)begin

       if(!rst_n)begin

           enc_out <=1'b0;      //初始匍

       end

       else if(enc_en)

           if((state_c==S1 && !enc_in) || (state_c==S3))begin

               enc_out <= 1'b0;

           end

           else if((state_c==S1 && enc_in) || (state_c==S2))begin

               enc_out <= 1'b1;

           end

           else begin

               enc_out <= 1'b0;

           end

       else

           enc_out <=1'b0;  

end


endmodule



5、 解码模块


解码模块也采用状态机实现,当检测到dec_en为高时,状态机才执行,判断clk_b的值,当clk_b为0时,在S1上等待,当clk_b为1时,判断enc_out的值,为1时跳转到S2状态,并将dec_out赋值为。S2状态无条件跳转到S1状态。为0时,跳转到S3状态并将dec_out赋值为0。S3状态无条件跳转到S1状态。 

状态转移图如下:

null


解码模块代码

module manchester_dec(clk_f, clk_b, rst_n, dec_en, enc_out, dec_out);


   input clk_f, clk_b, rst_n;

   input dec_en;

   input enc_out;

   output reg dec_out;

   

   reg [2:0] state_c, state_n;

   

   localparam S1 = 3'b001;

   localparam S2 = 3'b010;

   localparam S3 = 3'b100;

   

   wire S12S2_start  ;

   wire S12S3_start  ;

   wire S22S1_start  ;

   wire S33S1_start  ;

   

   always@(posedge clk_f or negedge rst_n)begin

       if(!rst_n)begin

           state_c <= S1;

       end

       else begin

           state_c <= state_n;

       end

   end


//第二段:组合逻辑always模块,描述状态转移条件判斍

always@(*)begin

   if(dec_en)

       case(state_c)

           S1:begin

               if(S12S2_start)begin

                   state_n = S2;

               end

               else if(S12S3_start)begin

                   state_n = S3;

               end

               else begin

                   state_n = state_c;

               end

           end

           S2:begin

               if(S22S1_start)begin

                   state_n = S1;

               end

               else begin

                   state_n = state_c;

               end

           end

           S3:begin

               if(S33S1_start)begin

                   state_n = S1;

               end

               else begin

                   state_n = state_c;

               end

           end

           default:begin

               state_n = S1;

           end

       endcase

   else

       state_n = S1;

   end

//第三段:设计转移条件

assign S12S2_start   = state_c==S1    && (!clk_b) && enc_out;

assign S12S3_start   = state_c==S1    && (!clk_b) && (!enc_out);

assign S22S1_start   = state_c==S2    && 1;

assign S33S1_start   = state_c==S3    && 1;


//第四段:同步时序always模块,格式化描述寄存器输出(可有多个输出-

   always @(posedge clk_f or negedge rst_n)begin

        if(!rst_n)begin

            dec_out <=1'b0;      //初始匍

       end

       else if(dec_en)

           if(state_c==S1 && (!clk_b) && enc_out)begin

               dec_out <= 1'b1;

           end

           else if((state_c==S1 && (!clk_b) && (!enc_out)))begin

               dec_out <= 1'b0;

           end

           else begin

               dec_out <= dec_out;

           end

       else

           dec_out <=1'b0;

   end


endmodule



6、仿真验证


tb文件参考工程文件夹中的sim文件夹


输入的数据流enc_in为1011,对应的曼彻斯特码应为10011010

null


我们看到输入到编码模块的enc_in与解码模块的dec_out的输出是一样的


再来看编码之后的数据流

null

enc_out为10011010与结果一致


解码模块图形

null


   拓展阅读