实验简述
将输入的数据流经过曼彻斯特编码器编码后经过解码器恢复为原来的输入序列。
一、曼彻斯特码简介
曼彻斯特码(Manchester code),又称数字双向码、分相码或相位编码(PE),是一种常用的二源码线路编码方式之一,被物理层使用来编码一个同步位流的时钟和数据。在通信技术中,用来表示所要发送比特流中的数据宇定时信号所结合起来的代码。常用在以太网通信,列车总线控制,工业总线等领域。
二、编码规则
有两个输入时钟,一个是基带时钟(起同步信号作用),一个是频带时钟。输入的数据流是基带时钟域信号,经过编码后变成频带时钟域信号输出。曼彻斯特编码是将输入为1的变成输出前半拍为1,后半拍为0,输入为0的变成前半拍为0,后半拍为1的频带信号。
三、时序图
输入序列以101为例,经过编码后应为100110
四、FPGA实现
1、顶层架构
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。
状态转移图如下:
说明:圆圈代表状态,→ 代表转移,转移下面的文本框代表转移时的动作。以后文章的状态转移图均按此绘制。
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状态。
状态转移图如下:
解码模块代码
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
我们看到输入到编码模块的enc_in与解码模块的dec_out的输出是一样的
再来看编码之后的数据流
enc_out为10011010与结果一致
解码模块图形