明德扬吴老师 发表于 2020-3-25 10:33:37

至简案例系列基于FPGA的曼彻斯特编码解码设计

至简案例系列基于FPGA的曼彻斯特编码解码设计实验简述
      将输入的数据流经过曼彻斯特编码器编码后经过解码器恢复为原来的输入序列。

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

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


1.3时序图

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

1.4 FPGA实现

1.4.1 顶层架构

信号说明

信号功能说明
clk_b基带时钟,作为同步信号使用外部输入
clk_f频带时钟,系统工作时钟外部输入
rst_n系统复位外部输入
enc_in输入数据流外部输入
enc_en编码使能外部输入
enc_out数据流经编码后的输出,输入到解码模块编码输出,解码输入
dec_en解码使能外部输入
dec_out解码输出输出


顶层代码

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


1.3.2 编码模块

       采用状态机来实现编码模块。
    当检测到编码使能为高时,状态机开始执行,判断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。状态转移图如下。
file:///C:\Users\27657\AppData\Local\Temp\ksohtml4580\wps18.png   说明:圆圈代表状态,代表转移,转移下面的文本框代表转移时的动作。以后文章的状态转移图均按此绘制。

编码模块代码

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 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



1.3.3 解码模块

      解码模块也采用状态机实现,当检测到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状态。 状态转移图如下,
解码模块代码

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 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



仿真验证
    tb文件参考工程文件夹中的sim文件夹
输入的数据流enc_in为1011,对应的曼彻斯特码应为10011010

我们看到输入到编码模块的enc_in与解码模块的dec_out的输出是一样的
    再来看编码之后的数据流
    enc_out为10011010 与结果一致
    解码模块图形







页: [1]
查看完整版本: 至简案例系列基于FPGA的曼彻斯特编码解码设计