• 帧结构的串行数据接收器——Verilog实现


    用Verilog 实现一个帧结构的串行数据接收器;

    1. 串行数据输入为:NRZ数据加位时钟(BCL)格式,高位在前
      帧结构为:8位构成一个字,64字构成一个帧。每帧的第一个字为同步字。
    2. 同步字图案存储在可由CPU读写的同步字寄存器(端口地址00H)中
      串行接受器在连续检测到3个同步图案后,开始接受数据,并向CPU中传送数据。串行数据接收器每接收到一个字,先送到数据寄存器中, CPU以I/O读方式,从数据寄存器中读取数据(端口地址为01H)
    3. 若数据寄存器已满,再有数据写入时,则覆盖原有的数据。在数据寄存器为空时,CPU从数据寄存器中读到的数据将是同步字寄存器的内容。
      在接收数据过程中,若任何一帧的同步字不匹配,则进入到头步状态,停止数据接收。失步后,必须重新同步(连续检测到3个同步图案),然后开始新的数据接收。
    4. 寄存器的读写采用和8031类似的控制方式,有关信号包括:双向数据(DATA[7:0])、I/O地址(ADDR[7:0])、I/O写(IOW)、和I/O读(IOR),其中IOW和IOR都是低电平有效
    5. 设计者可以根据需要增加其它的输入输出信号

    设计分析

    • 端口
      在这里插入图片描述

    • 输入数据和时钟之间的关系
      在这里插入图片描述

    • 帧结构
      8位构成一个字,64字构成一个帧。每帧的第一个字为同步字。
      连续检测到三个同步,即连续三个同步头和同步图案一样的帧,才开始进行数据接收

    • 详细设计-工作阶段非常明显

      • 失步阶段:检测同步头,根据情况确定是否转入同步状态
      • 同步阶段:检测同步头,如果匹配则接收数据,仍然处于同步阶段;否则转入失步状态。
      • 注意:是失步态下检测的一个同步字时需要每个时钟周期都要进行比较
    • 实现思路:采用状态机进行实现

      • 状态转换的控制
        • 计数器:接收位计数–>字,字计数–>数据帧
        • 比较器:接收数据与同步字的比较
    • 两个状态
      在这里插入图片描述
      状态转换关系从功能需求很容易得出
      难点:需要检测三个连续的同步帧才能从失步态到同步态
      控制不清晰

    • 四状态划分
      在这里插入图片描述
      实现难点:每个帧持续8*64个时钟周期,其中第8个时钟周期结束需要同步头比较,后面的504个时钟周期接收数据(同步态)或空等(失步态)

    • 8个状态
      在这里插入图片描述

      • 在每个状态,省略了自身状态转移的情况
      • 每个R_Headx状态持续八个周期(Read_Head1)除外
      • 每个R_Datax状态持续504个周期
      • 需要设计一个记8和一个记504的计数器辅助进行控制
    • 代码部分
      完整代码

    `timescale 1ns / 1ps
    
    module S2P (
        reset,clk,serial_in,ior,iow,address,data,cnt
    );
        input           reset;
        input           clk;
        input           serial_in;
        input           ior;
        input           iow;
        input   [7:0]   address;
        inout   [7:0]   data;
        output          cnt;
        reg     [7:0]   Data;
        reg             counter8_en,counter504_en,counter8_clr,counter504_clr;
        reg     [2:0]   counter8;
        reg     [8:0]   counter504;
        reg     [7:0]   shifter,data_reg,sync_word;
        reg     [2:0]   pres_state,next_state;
        reg             cnt;
    
        parameter R_Head1 = 3'b000,R_Data1 = 3'b001,R_Head2 = 3'b010,R_Data2 = 3'b011,R_Head3 = 3'b100,R_Data3 = 3'b101,R_Head = 3'b110,R_Data = 3'b111;   
        //状态机
        always @(posedge reset or posedge clk) begin
            if (reset) 
                pres_state = R_Head1;
            else 
                pres_state = next_state;
        end
    
        always @(pres_state,shifter,counter8,counter504) begin
            case(pres_state)
                R_Head1: if (shifter == sync_word) next_state = R_Data1;
                        else next_state = R_Head1;
                R_Data1: if (counter504 == 9'b0) next_state = R_Head2;
                        else next_state = R_Data1;
                R_Head2: if (counter8 == 3'b0) begin
                            if (shifter == sync_word) next_state = R_Data2;
                            else next_state = R_Head1;
                        end else next_state = R_Head2;
                R_Data2: if (counter504 == 9'b0) next_state = R_Head3;
                        else next_state = R_Data2;
                R_Head3: if (counter8 == 3'b0) begin
                            if (shifter == sync_word) next_state = R_Data3;
                            else next_state = R_Head1;
                        end else next_state = R_Head3; 
                R_Data3: if (counter504 == 9'b0) next_state = R_Head;
                        else next_state = R_Data3;
                R_Head: if (counter8 == 3'b0) begin
                            if (shifter == sync_word) next_state = R_Data;
                            else next_state = R_Head1;
                        end else next_state = R_Head;
                R_Data: if (counter504 == 9'b0) next_state = R_Head;
                        else  next_state = R_Data;
                default: next_state = R_Head1;
            endcase
        end
            
        always @(next_state,pres_state) begin
            if (pres_state == R_Data) 
                cnt = 1'b1;
            else cnt = 1'b0;
        end 
    
        // 移位器和计数器
        always @(posedge reset or posedge clk) begin
            if (reset) 
                shifter = 8'b0;
            else 
                shifter = {serial_in,shifter[7:1]};
        end
    
        always @(posedge clk  or posedge reset) begin
            if (reset) counter8 = 3'b111;
            else begin
                if (counter8_clr) counter8 = 3'b111;
                else if (counter8_en)
                    counter8 = counter8 - 1; 
            end
        end
    
        always @(posedge clk  or posedge reset) begin
            if (reset) counter504 = 9'b1_1111_0111;
            else begin
                if (counter504_clr) counter504= 9'b1_1111_0111;
                else if (counter504_en)
                    counter504 = counter504 - 1; 
            end
        end
        // 计数器计数使能和清零信号生成
        always @(pres_state) begin
            if (pres_state == R_Data1 || pres_state == R_Data2 || pres_state == R_Data3 || pres_state == R_Data)
                counter8_clr = 1'b1;
            else 
                counter8_clr = 1'b0;
        end
    
        always @(pres_state) begin
            if (pres_state == R_Head2 || pres_state == R_Head3 || pres_state == R_Head) 
                counter8_en = 1'b1;
            else 
                counter8_en = 1'b0;
        end
    
        always @(pres_state) begin
            if (pres_state == R_Head1 || pres_state == R_Head2 || pres_state == R_Head3 || pres_state == R_Head) 
                counter504_clr = 1'b1;
            else 
                counter504_clr = 1'b0;
        end
    
        always @(pres_state) begin
            if (pres_state == R_Data1 || pres_state == R_Data2 || pres_state == R_Data3 || pres_state == R_Data) 
                counter504_en = 1'b1;
            else 
                counter504_en = 1'b0;
        end
        //数据寄存器读写和同步字寄存器的写入
        always @(posedge reset or posedge clk)
            if (reset) data_reg = 8'b0;
            else if (counter504_en == 1'b1 && counter504[2:0] == 3'b0) 
                data_reg = shifter;
        
        always @(posedge reset or posedge clk) begin
            if (reset) 
                sync_word = 8'b0000_0001;
            else if (iow == 1'b0 && address == 8'b0) 
                sync_word = data;
        end
        
        always @(ior or address or data_reg) 
            if (ior == 1'b0 && address == 8'b1) 
                Data = data_reg;
            else Data = 8'bz;
    
        assign data = Data;
    
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • Testbench
    `timescale 1ns / 1ps
    module tb_S2P;
      reg       reset;
      reg       clk;
      reg       serial_in;
      reg       ior;
      reg       iow;
      reg [7:0] address;
      wire[7:0] data;
      wire       cnt;
      S2P s2p (
        .reset(reset),
        .clk(clk),
        .serial_in(serial_in),
        .ior(ior),
        .iow(iow),
        .address(address),
        .data(data),
        .cnt(cnt)
      );
        reg [7:0] d;
        assign data = (ior == 1'b1)?d:8'bz;
        //assign data = (ior == 1'b0 &&address == 8'b1)?d:8'bz;
        
        always begin
            #10 clk = ~clk; 
        end
        integer i;
        initial begin
            serial_in = 1'bZ;
            #10 ; 
            while (1) begin
                ior = 1'b1;
                #20; serial_in = 1'b0;
                #20; serial_in = 1'b1;
                #20; serial_in = 1'b1;
                #20; serial_in = 1'b1;
                #20; serial_in = 1'b1;
                #20; serial_in = 1'b1;
                #20; serial_in = 1'b1;
                #20; serial_in = 1'b0;
                for (i = 1;i <= 63*8;i = i + 1)
                    #20 serial_in = {$random}%2;
                
            end  
        end
    
    
        initial begin
            clk = 0;
            reset = 1'b1;
            #20
            #5 reset = 1'b0;
        end
    
        initial begin
            ior = 1'b1;
            //address = 8'b0;
            //s2p.pres_state = 3'b1;
            iow = 1'b1;
            address = 8'b0;
            d = 8'b01111110;
            #20
            #5;
            iow = 1'b0;
            //address = 8'b0;
            #10;
    
            address = 8'b0000_0001;
            //ior = 1'b0;
            #5 
            iow = 1'b1;
            
        end
        always @(cnt) begin
            
            ior = ~cnt;
        end
        initial begin
            #20
            #101000;
    
            $finish;
        end
    endmodule
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 仿真结果
      在这里插入图片描述
  • 相关阅读:
    PMP备考大全:经典题库(6月第4周)
    Vue2面试题100问
    一站式数据可观测性平台 Datavines 正式开源啦
    iMazing2023永久免费版苹果iOS设备管理软件
    内网服务器无法访问外网下载时,制作本地清华镜像源,搭建中转服务器(rinted)
    什么是媒体邀约?邀请媒体的流程
    【etcd】编译与安装
    前端HTML5 +CSS3 2. HTML标签学习
    玩转MySQL:你知道什么是表分区吗
    方圆的秒杀系统优化方案实战,(六)分布式缓存
  • 原文地址:https://blog.csdn.net/qq_46264636/article/details/132869188