并行数据流转换成一种特殊串行数据流模块设计

Verilog数字系统设计

例15.2

M0模块:接收M1产生的新数据使能信号,产生测试数据,如系统时钟、复位信号和需要传输的4位并行数据

M1模块:将4位并行数据转换成串行数据,并且按照协议将串行数据输送到M2模块

M2模块:将串行数据复原为4位并行数据,并且根据并行数据的值,输出相应的高电平,即若数据为1,则第一条线路为0;

通信协议:scl为不断输出的时钟信号。在scl为高电平的前提下,sda由高变低,串行数据流准备传输;在scl为高电平的前提下,sda由低变高,串行数据流传输结束。sda所传输的数据必须在scl为低电平时变化。

信号表示:data为待传输4位并行数据,sclk为系统时钟,ack(en)为产生新数据使能信号,scl为根据sclk分频得到的时钟,sda为串行数据,outhigh高电平结果。

心得

  1. M0模块实际上就是一个tb,运用了模块化的思想,输入为en,输出为sclk、rst_n、data;当新数据使能信号到来时,产生新数据。
  2. M1模块使用三段式状态机,分为IDLE、START、BIT1、BIT2、BIT3、BIT4、READY、STOP 8个状态。为了满足“在scl为高电平的前提下.......sda所传输的数据必须在scl为低电平时变化”这一协议要求,状态机是在sclk下降沿触发。

3、en信号拉高,新数据产生,此时状态机切换到START状态,此状态下将sda由高拉低,表示可以传输数据了;传完4bit之后,状态切换到READY,将sda变化为0,为由低拉高sda作准备;STOP状态时,将sda拉高,表示数据传输结束。

4、在BIT1状态时,将flag_start信号拉高,告诉M2模块:我要传输第一个bit了,你可以接收第一个bit了;在READY状态,将flag_start信号拉低,告诉M2模块:4bit数据已经传输完了,你可以停止接收了。

5、M2模块使用计数器(简单),不使用状态机。在scl上升沿且falg_start为1时,开始计数,表示此时传输bit了;在scl下降沿且falg_start为1时,将sda存入缓冲器;在flag_start下降沿且计数器为4时,将缓冲器里的4bit数据赋值给DATA。

M0模块:

//**************************************************************************************************
//****************************************模块功能***************************************************
//****************************************本模块产生测试信号,不能综合成电路***************************
//**************************************************************************************************

`timescale 1ns/1ns


module sigdata (
    input ask_data,
    output reg rst_n,
    output reg[3:0] data,
    output reg sclk
);

parameter halfperiod = 50;

initial begin
    rst_n = 0;

    #100 rst_n = 1;
end


initial begin
    sclk = 0;
    data = 0;
    #(halfperiod*1000) $stop;
end

always begin #(halfperiod) sclk = ~sclk; end

always @(posedge ask_data) begin
    #(halfperiod*2+3) data = data + 1;
end
    
endmodule

M1模块 

//**************************************************************************************************
//****************************************模块功能***************************************************
//*********把4位并行数据转换为符合协议的串行数据流,数据流用scl、sda两条线传输,sclk为输入的时钟信号*******
//**************************************************************************************************

module ptosda (
    input sclk,
    input rst_n,
    output reg en,                                   //the signal that allows new data to export
    input [3:0]data,                            //data which needs to be exported
    output reg scl,                             //clk that generated by sclk
    output reg flag_start,                           //the signal which tells out16hi.v that it can recieve the bits
    //output flag_end,                            //the signal which tells out16hi.v that it can refuse recieving  the bits
    output sda                                  //Serial data that fits agreements, take out: inout!
);
    
reg buffer_sda;                            
reg [3:0]buffer_data; 
reg link_sda;                      
reg [7:0]cstate;         
reg [7:0]nstate;

parameter [7:0]
          IDLE = 8'b0000_0001,
          READY = 8'b0000_0010,
          START = 8'b0000_0100,
          BIT1 = 8'b0000_1000,                       
          BIT2 = 8'b0001_0000,
          BIT3 = 8'b0010_0000,
          BIT4 = 8'b0100_0000,
          STOP = 8'b1000_0000;


//the generation of scl
always @(posedge sclk, negedge rst_n) begin
    if(~rst_n) begin
        scl <= 0;
    end
    else begin
        scl <= ~scl; 
    end 
end

//deposit new data in buffer
always @(negedge sclk ) begin
    if(en) begin
        buffer_data <= data;
    end

    else begin
        buffer_data <= buffer_data;
    end
end

assign sda = link_sda? buffer_sda : 0;


//1st state transition
always @(negedge sclk, negedge rst_n) begin
    if(~rst_n) begin
        cstate <= IDLE;
    end
    else begin 
        cstate <= nstate;
    end
end

//2nd condition judgement
always @* begin
    nstate = 8'bx;
    case(cstate) 
        IDLE:   begin
                    if(en==1) nstate = START;
                    else      nstate = IDLE;
                end

        START:   begin
                    if(scl==0) nstate = BIT1;
                    else      nstate = START;
                end
        BIT1:   begin
                    if(scl==0) begin nstate = BIT2; flag_start = 1; end
                    else      nstate = BIT1;
                end
        BIT2:   begin
                    if(scl==0) nstate = BIT3;
                    else      nstate = BIT2;
                end
        BIT3:   begin
                    if(scl==0) nstate = BIT4;
                    else      nstate = BIT3;
                end
        BIT4:   begin
                    if(scl==0) nstate = READY;
                    else      nstate = BIT4;
                end
        READY:   begin     
                    if(scl==1) begin nstate = STOP;   flag_start = 0; end
                    else      nstate = READY;
                end
        STOP:   begin     
                    if(scl==1) nstate = IDLE;
                    else      nstate = STOP;
                end
        default: nstate <= IDLE;
    endcase
end

//3rd output
always @(negedge sclk, negedge ~rst_n) begin
    if(~rst_n) begin
        cstate <= IDLE;
        link_sda <= 0;
        buffer_sda <= 1;
        en <= 0;
        flag_start <= 0;
        //flag_end <= 0;
    end

    else begin
        case(nstate)
        IDLE:   begin
                    link_sda <= 1;
                    en <= 1;
                    buffer_sda <= 1;
                end

        START:  if(scl) begin
                    buffer_sda <= 0;
                end
                else begin
                    buffer_sda <= buffer_sda;
                end

        BIT1:   if(!scl) begin    
                    buffer_sda <= buffer_data[3];
                    en <= 0;
                end

        BIT2:   if(!scl) begin
                    buffer_sda <= buffer_data[2];
                end

        BIT3:   if(!scl) begin
                    buffer_sda <= buffer_data[1];
                end

        BIT4:   if(!scl) begin
                    buffer_sda <= buffer_data[0];
                end

        READY:  if(!scl) begin
                    buffer_sda <= 0;                       //结束传输预准备
                end

        STOP:   if(scl) begin  
                    buffer_sda <= 1;
                end
        endcase
    end
end


endmodule

M2模块:

//*************************************************************************************
//************************************模块功能******************************************
//******************按照协议接收串行数据,进行处理,并按要求输出相应的高电平*****************
//**************************************************************************************

module out16hi (
    input scl,
    input rst_n,
    input flag_start,
    input sda,
    output reg[15:0]high
);
    

reg [3:0] DATA;                      //initial data
reg [3:0] buffer_data;
reg [3:0] cnt;



//counter for 4 bits
always @(posedge scl, negedge rst_n) begin
    if(~rst_n) begin
      cnt <= 4'd0;
    end

    else if(flag_start) begin
        if(cnt != 4'd4) begin
            cnt <= cnt + 4'd1; 
        end
        else begin 
            cnt <= 4'd0;
        end
    end

    else begin 
        cnt <= 4'd0;
    end
end

//buffer_data
always @(negedge scl, negedge rst_n) begin
    if(~rst_n) begin
      buffer_data <= 4'dx;
    end

    else if(flag_start) begin
        buffer_data[4-cnt] <= sda;
    end

    else begin
        buffer_data <= 0;
    end
end

//DATA
always @(negedge flag_start) begin
    if(cnt == 4) begin
        DATA <= buffer_data;
    end

    else begin
        DATA <= 0;
    end
end

//highlight
always @(*) begin
    if(cnt == 0) begin
        case (DATA)
            4'b0000: high = 16'b0000_0000_0000_0000;
            4'b0001: high = 16'b0000_0000_0000_0001;
            4'b0010: high = 16'b0000_0000_0000_0010;
            4'b0011: high = 16'b0000_0000_0000_0100;
            4'b0100: high = 16'b0000_0000_0000_1000;
            4'b0101: high = 16'b0000_0000_0001_0000;
            4'b0110: high = 16'b0000_0000_0010_0000;
            4'b0111: high = 16'b0000_0000_0100_0000;
            4'b1000: high = 16'b0000_0000_1000_0000;
            4'b1001: high = 16'b0000_0001_0000_0000;
            4'b1010: high = 16'b0000_0010_0000_0000;
            4'b1011: high = 16'b0000_0100_0000_0000;
            4'b1100: high = 16'b0000_1000_0000_0000;
            4'b1101: high = 16'b0001_0000_0000_0000;
            4'b1110: high = 16'b0010_0000_0000_0000;
            4'b1111: high = 16'b0100_0000_0000_0000;
            default: high = 16'b0000_0000_0000_0000;
        endcase
    end
    
    else begin 
        high = high;
    end
end

endmodule

top模块

`timescale 1ns/1ns


module  top;
wire rst_n;
wire sclk;
wire [3:0] data;
wire scl;
wire en;
wire flag_start;
wire sda;
wire [15:0]high;

ptosda t1(
    .sclk(sclk),
    .rst_n(rst_n),
    .en(en),
    .data(data),
    .flag_start(flag_start),
    .scl(scl),
    .sda(sda)
);

out16hi t2(
    .scl(scl),
    .rst_n(rst_n),
    .sda(sda),
    .flag_start(flag_start),
    .high(high)
);

sigdata t3(
    .ask_data(en),
    .rst_n(rst_n),
    .data(data),
    .sclk(sclk)
);

endmodule

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值