并行数据流转化为一种特殊串行数据流模块的设计

       设计两个可综合的电路模块:第一个模块(M1)接受四位并行数据,并将其转化为简化I2C传输格式。sclk为输入主钟,data[3:0]为输入的四位数据,ack为请求发送数据信号(请求后才有数据发送到data[3:0]),数据流用scl和sda两条线传输。第二个模块(M2)接收以简化I2C协议通过scl和sda传输来的数据,并转化为相应16条信号线上的高电平,若数据为1,则第一条线路为高电平,数据为n,则第N条线路为高电平。模块如下图所示。

        本文引用自https://blog.csdn.net/llxxyy507/article/details/81046981


       简化的I2C通信协议如下:scl为时钟信号,当scl为高电平的时候,sda从高电平变为低电平,表示串行数据流开始传输;当scl为高电平,sda从低电平变为高电平的时候,表示串行数据流结束。sda信号只能在scl为低电平的时候变化,在scl为高电平期间应该维持稳定。


       上图中,sda信号在scl为高时从高变低,为数据流的开始。在scl为低电平时传输第一位数据(MSB),并在整个scl为高的期间都维持信号的稳定,接着传递剩下的数据。sda信号在scl为高时从低变高,表示数据流的结束。

       模块M1的verilog代码(ptosda.v)如下:

module ptosda(sclk,rst,data,ack,scl,sda);
input sclk,rst,data;
wire [3:0]data;

output scl,sda,ack;
reg scl,ack,link_sda,sdabuf;
reg [3:0]databuf;
reg [7:0]state;

out16hi m2(.scl(scl), .sda(sda), .outhigh() );    //调用M2模块

assign  sda = link_sda ? sdabuf : 1'b0;        //link_sda控制sdabuf输出到串行总线上

parameter  ready  =  8'b0000_0000,
           start  =  8'b0000_0001,
           bit1   =  8'b0000_0010,
           bit2   =  8'b0000_0100,
           bit3   =  8'b0000_1000,
           bit4   =  8'b0001_0000,
           bit5   =  8'b0010_0000,
           stop   =  8'b0100_0000,
           IDLE   =  8'b1000_0000;

always @(posedge sclk or negedge rst)         //主钟sclk产生串行输出时钟clk
       begin
              if (!rst)
                scl <= 1;
              else
                scl <= ~scl;
       end

always @(posedge ack)
       databuf <= data;

always @(negedge sclk or negedge rst)
       if (!rst)
           begin
                 link_sda <= 0;
                 state <= ready;
                 sdabuf <= 1;
                 ack <= 0;
           end
        else  
           begin
              case(state)
              ready : if(ack) 
                        begin 
                           link_sda <= 1;
                           state <= start;
                        end
                      else
                        begin
                           link_sda <= 0;
                           state <= ready;
                           ack <= 1;
                        end
               
               start : if(scl && ack)
                         begin 
                            sdabuf <= 0;
                            state <= bit1;
                         end
                       else
                         state <= start;

                bit1  : if(!scl)
                          begin
                             sdabuf <= databuf[3];
                             state <= bit2;
                             ack <= 0;
                          end
                         else
                          state <= bit1;
                            
                bit2  : if(!scl)
                          begin
                             sdabuf <= databuf[2];
                             state <= bit3;
                          end
                         else
                          state <= bit2;
                            
                bit3  : if(!scl)
                          begin
                             sdabuf <= databuf[1];
                             state <= bit4;
                          end
                         else
                          state <= bit3;
                            
                bit4  : if(!scl)
                          begin
                             sdabuf <= databuf[0];
                             state <= bit5;
                          end
                         else
                          state <= bit4;
                            
                bit5  : if(!scl)
                          begin
                             sdabuf <= 0;
                             state <= stop;
                          end
                         else
                          state <= bit5;
                            
                stop  : if(scl)
                          begin
                             sdabuf <= 1;
                             state <= IDLE;
                          end
                         else
                          state <= stop;
                            
                IDLE  :  begin
                             link_sda <= 0;
                             state <= ready;
                          end
                            
               default  : begin
                             link_sda <= 0;
                             sdabuf <= 1;
                            state <= ready;
                          end
             endcase
          end
endmodule

        模块M2(out16hi.v)verilog代码如下:

module out16hi(scl,sda,outhigh);
input scl,sda;
output [15:0]outhigh;

reg [4:0]mstate;
reg [3:0]pdata,pdatabuf;
reg [15:0]outhigh;
reg StartFlag,EndFlag;              //串行数据开始和结束标志

always @(negedge sda)
     begin
       if (scl)
           StartFlag <= 1;
       else if (EndFlag)
           StartFlag <= 0;
     end

always @(posedge sda)
       if (scl)
          begin
            EndFlag <= 1;
				pdatabuf <= pdata;
          end
       else
            EndFlag <= 0;
       
parameter sbit0 = 5'b0_0001,
          sbit1 = 5'b0_0010,
          sbit2 = 5'b0_0100,
          sbit3 = 5'b0_1000,
          sbit4 = 5'b1_0000;

always @(pdatabuf)                              //接受到的数据转化为相应的输出位的高电平
       begin
         case(pdatabuf)
             4'b0001: outhigh = 16'b0000_0000_0000_0001; 
             4'b0010: outhigh = 16'b0000_0000_0000_0010; 
             4'b0011: outhigh = 16'b0000_0000_0000_0100; 
             4'b0100: outhigh = 16'b0000_0000_0000_1000; 
             4'b0101: outhigh = 16'b0000_0000_0001_0000; 
             4'b0110: outhigh = 16'b0000_0000_0010_0000; 
             4'b0111: outhigh = 16'b0000_0000_0100_0000; 
             4'b1000: outhigh = 16'b0000_0000_1000_0000; 
             4'b1001: outhigh = 16'b0000_0001_0000_0000; 
             4'b1010: outhigh = 16'b0000_0010_0000_0000; 
             4'b1011: outhigh = 16'b0000_0100_0000_0000; 
             4'b1100: outhigh = 16'b0000_1000_0000_0000; 
             4'b1101: outhigh = 16'b0001_0000_0000_0000; 
             4'b1110: outhigh = 16'b0010_0000_0000_0000; 
             4'b1111: outhigh = 16'b0100_0000_0000_0000; 
             4'b0000: outhigh = 16'b1000_0000_0000_0000; 
          endcase
         end

always @(posedge scl)
       if (StartFlag)
          case(mstate)
              sbit0 : begin
                        mstate <= sbit1;
                        pdata[3] <= sda;
                      end

              sbit1 : begin
                        mstate <= sbit2;
                        pdata[2] <= sda;
                      end

              sbit2 : begin
                        mstate <= sbit3;
                        pdata[1] <= sda;
                      end

              sbit3 : begin
                        mstate <= sbit4;
                        pdata[0] <= sda;
                      end

              sbit4 : begin
                        mstate <= sbit0;
                      end
 
              default : mstate <= sbit0;

           endcase
      else   mstate <= sbit0;
endmodule

testbench文件(sigdata_test.v)内容如下:

`timescale 1ns/1ns
`define halfperiod 50

module sigdata_test(rst,sclk,data,ack_for_data,sda,scl,outhigh);
output rst;
output [3:0]data;
output sclk;
input ack_for_data;
reg rst,sclk;
reg [3:0]data;

output sda,scl,outhigh;
wire sda;
wire scl;
wire [15:0]outhigh;

ptosda m1(.sclk(sclk), .rst(rst), .data(data), .ack(ack_for_data), .scl(scl), .sda(sda) );
out16hi m2(scl,sda,outhigh);

initial
      begin
          rst = 1;
        #10 rst = 0;
        #(`halfperiod*2+3) rst = 1;
      end

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

always #(`halfperiod) sclk = ~sclk;

always @(posedge ack_for_data)
       begin
          #(`halfperiod/2 + 3) data = data + 1;
       end

endmodule

        仿真的结果如下:


        加入中间变量查看结果得到如下,可以看出data[3:0]数据准确的传入到了pdatabuf[3:0],并通过outhigh准确输出了对应信号线的高电平。


  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值