明德扬论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

微信扫一扫,快捷登录!

查看: 1584|回复: 0

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

[复制链接]
发表于 2020-3-25 10:33:37 | 显示全部楼层 |阅读模式

马上注册,看完整文章,学更多FPGA知识。

您需要 登录 才可以下载或查看,没有帐号?立即注册

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

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


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


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



1.3时序图


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


1.4 FPGA实现

1.4.1 顶层架构
2.PNG

信号说明

信号
功能
说明
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。状态转移图如下。
3.PNG

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



1.3.3 解码模块

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

解码模块代码

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



仿真验证
    tb文件参考工程文件夹中的sim文件夹

  输入的数据流enc_in1011,对应的曼彻斯特码应为10011010
5.png


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

    再来看编码之后的数据流
6.png

    enc_out10011010 与结果一致

    解码模块图形
7.png












上一篇:【原创】基于FPGA的密码锁设计(附工程源码altera版)
下一篇:【技巧分享】阻塞赋值与非阻塞赋值
FPGA视频课程  培训班 FPGA学习资料
吴老师 18022857217(微信同号) Q1241003385
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则


QQ|手机版|小黑屋|MDYBBS ( 粤ICP备16061416号-1

GMT+8, 2021-3-1 14:54 , Processed in 0.528520 second(s), 15 queries , File On.

Powered by Discuz! X3.4

本论坛由广州健飞通信有限公司所有

© 2001-2019 Comsenz Inc.

快速回复 返回顶部 返回列表