串行数据发送器

框图

在这里插入图片描述

  • THR:发送保持寄存器

    • 定义了两种状态:空,满
    • 数据写入端口地址:00H
    • 状态读出端口地址:00H
    • 当THR不满时,可以向THR写入数据
  • TSR:发送移位寄存器

    • 一旦TSR空而THR中有数据时,THR中的数据就送到TSR
    • RSR中的数据以串行方式从TxD段发送,高位在前,低位在后
    • 在TxD端的bit流中,若连续出现5个’1‘,则在第5个’1‘之后自动插入一个’0’。注意:相邻两个字节之间也会出现5个连续的‘1’
      - yi
      在这里插入图片描述
  • 发送时许
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

  • 代码
module p2s_transmitter (
   RST,CLK2M,CS,FS,WR,RD,A0,D,TxD
);
   input       RST,CLK2M,CS,WR,RD,FS;
   input       A0;
   inout [7:0] D;
   output      TxD;
   reg         TxD;
   wire  [7:0] D;
   reg   [7:0] THR_Status,THR,TSR,R_Shifter;
   // R_Shifter 最低为TxD_1;
   reg   [2:0] Count8;
   reg   [2:0] Count5;
   reg   [4:0] Count32;
   reg         TSR_Shift_EN;
   reg         Mux_Sel1,Mux_Sel2;
   reg         TxD_2;
   reg         Load_EN;
   reg         THR_Read;
   // 移位寄存器,load操作为:每当移完一个字节的数据并且THR不空时,
   // 就从THR加载一个数据
   // 在TSR_Shift_EN信号有效时,TSR做移位操作
   always @(posedge RST or posedge CLK2M) begin
      if (RST) 
         TSR <= 8'b00000000;
      else if (Count8 ==3'b000&&THR_Status[0] == 1) begin
         TSR <= THR;
      end else if (TSR_Shift_EN == 1'b1) 
         TSR <= {TSR[6:0],1'b0};
   end
   //连续5个‘1’的检测及插‘0’。
   always @(posedge RST or posedge CLK2M) begin
      if (RST) 
         Count5 = 3'b100;
      else if (TSR[7] == 1'b0) 
         Count5 = 3'b100;
      else 
         Count5 = Count5 - 1;
   end

   always @(TSR or Mux_Sel1) begin
      if (Mux_Sel1) 
         TxD_2 = 1'b0;
      else 
         TxD_2 = TSR[7];
   end

   always @(Count5) begin
      if (Count5 == 3'b000) 
         Mux_Sel1 = 1'b1;
      else 
         Mux_Sel1 = 1'b0;
   end
   //在发送5个连续的‘1’之后要插入一个‘0’,此时TSR不移位。
   // always @(Count5) begin
   //    if (Count5 == 3'b000) 
   //       TSR_Shift_EN = 1'b0;
   //    else 
   //       TSR_Shift_EN = 1'b1;
   // end 等价于
   always @(Mux_Sel1) begin
      TSR_Shift_EN = ~Mux_Sel1;
   end
   //正常数据与发送7EH的处理
   always @(Mux_Sel1 or TxD or R_Shifter) begin
      if (Mux_Sel2) 
         TxD = R_Shifter[7];
      else 
         TxD = TxD_2;
   end

   always @(posedge RST or posedge CLK2M) begin
      if (RST) 
         R_Shifter = 8'b01111110;
      else if (Load_EN) 
         R_Shifter = 8'b01111110;//7EH
      else 
         R_Shifter = {R_Shifter[6:0],R_Shifter[7]};
   end
   
   always @(posedge RST or posedge CLK2M) begin
      if (RST)
         Count32 = 5'b11111;
      else if (~FS) 
         Count32 = 5'b11111;
      else if (TSR_Shift_EN) 
         Count32 = Count32 - 1;
   end
   // 对TSR移位32次,即进入空闲态,因此Count32对TSR_Shift_EN进行计数
   always @(Count32) begin
      if (Count32 == 5'b00000)
         Load_EN = 1'b1;
      else 
         Load_EN = 1'b0;
   end

   always @(Load_EN) begin
      Mux_Sel2 = Load_EN;
   end

   always @(posedge RST or posedge CLK2M) begin
      if (RST)
         THR = 8'b00000000;
      else if (CS == 1'b0&&WR == 1'b0&&A0 == 1'b0) 
         THR = D;
   end
   //THR_Status是一个状态信号,由于该状态最终可以被处理器通过总线读取,因此可以将它设置为
   //8bits,当THR中有数据时为00000001,否则为00000000;
   // 该信号应该是寄存器信号,无论THR中是否有数据,只要TSR发出一个读信号,那么在
   // 读信号有效的下一个时钟沿,该信号为空
   always @(posedge RST or posedge CLK2M) begin
      if (RST) 
         THR_Status = 8'b00000000;
      else if (WR == 1'b0 && THR_Read == 1'b1 &&A0 == 1'b0) 
         THR_Status = 8'b00000001;
      else if (WR == 1'b1 && THR_Read == 1'b0) 
         THR_Status = 8'b00000000;
   end

   always @(Count8) begin
      if (Count8 == 3'b000) 
         THR_Read = 1'b0;
      else 
         THR_Read = 1'b1;
   end

   always @(posedge RST or posedge CLK2M) begin
      if (RST) 
         Count8 = 3'b000;
      else if (~FS) 
         Count8 = 3'b111;
      else if (TSR_Shift_EN)
         Count8 = Count8 - 1;
   end

   assign D = (RD == 1'b0 &&A0 == 1'b0)?THR_Status:8'bzzzzzzzz;

endmodule

更新Design Source文件
判断是否插‘0’以及循环移位寄存器使能信号的产生;使用Count5和时钟上升沿配合完成Mux_Sel1信号的置一。因为THR_Read信号的变化预示着一个字节传输的完成,所以当该信号上升沿出现时,将Count5置为3’b100。

always @(posedge CLK2M) begin
      if (Count5 == 3'b111) 
         Mux_Sel1 = 1'b1;
      else 
         Mux_Sel1 = 1'b0;
end

由于Count5作为一个重要的信号,在笔者处理仿真过程中发现,如果能够改成如下代码,才能正确实现笔者所编写Design source的功能,即使用时钟上升沿和THR_Read上升沿触发,而且在Count53’b111时才暂停数据的传输,此时也将移位使能置零,然后在该时钟周期插入‘0’,所以需要当Count50,减一之后为3’b111,此时需要置为3’b100。

always @(posedge RST or posedge CLK2M or posedge THR_Read) begin
      if (RST) 
         Count5 = 3'b000;
      else if (TSR[7] == 1'b0||Count5 == 3'b111||THR_Read == 1'b0) 
         Count5 = 3'b100;
      else 
         Count5 = Count5 - 1;
   end
	always @(TSR or Mux_Sel1) begin
      if (Mux_Sel1) 
         TxD_2 = 1'b0; 
      else 
         TxD_2 = TSR[7];
   end
	always @(Mux_Sel1) begin
         TSR_Shift_EN = ~Mux_Sel1;
   end

完整代码

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2023/09/12 18:18:24
// Design Name: 
// Module Name: p2s_transmitter
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//
module p2s_transmitter (
   RST,CLK2M,CS,FS,WR,RD,A0,D,TxD
);
   input       RST,CLK2M,CS,WR,RD,FS;
   input       A0;
   inout [7:0] D;
   output      TxD;
   reg         TxD;
   wire  [7:0] D;
   reg   [7:0] THR_Status,THR,TSR,R_Shifter;
   // R_Shifter 最低为TxD_1;
   reg   [2:0] Count8;
   reg   [2:0] Count5;
   reg   [4:0] Count32;
   reg         TSR_Shift_EN;
   reg         Mux_Sel1,Mux_Sel2;
   reg         TxD_2;
   reg         Load_EN;
   reg         THR_Read;
   reg         state;
   // 移位寄存器,load操作为:每当移完一个字节的数据并且THR不空时,
   // 就从THR加载一个数据
   // 在TSR_Shift_EN信号有效时,TSR做移位操作
   always @(posedge RST or posedge CLK2M) begin
      if (RST) 
         TSR <= 8'b00000000;
      else if ((Count8 == 3'b000&&THR_Status[0] == 1'b1)) begin
         TSR <= THR;
      end else if (TSR_Shift_EN == 1'b1) 
         TSR <= {TSR[6:0],1'b0};
   end
   //连续5个‘1’的检测及插‘0’。
   always @(posedge RST or posedge CLK2M or posedge THR_Read) begin
      if (RST) 
         Count5 = 3'b000;
      else if (TSR[7] == 1'b0||Count5 == 3'b111||THR_Read == 1'b0) 
         Count5 = 3'b100;
      else 
         Count5 = Count5 - 1;
   end

   always @(TSR or Mux_Sel1) begin
      if (Mux_Sel1) 
         TxD_2 = 1'b0; 
      else 
         TxD_2 = TSR[7];
   end

   always @(posedge CLK2M) begin
      if (Count5 == 3'b111) 
         Mux_Sel1 = 1'b1;
      else 
         Mux_Sel1 = 1'b0;
   end
   //在发送5个连续的‘1’之后要插入一个‘0’,此时TSR不移位。
   // always @(Count5) begin
   //    if (Count5 == 3'b000) 
   //       TSR_Shift_EN = 1'b0;
   //    else 
   //       TSR_Shift_EN = 1'b1;
   // end 等价于
   always @(Mux_Sel1) begin
         TSR_Shift_EN = ~Mux_Sel1;
   end
   //正常数据与发送7EH的处理
   always @(TxD or R_Shifter or TSR) begin
      if (Mux_Sel2) 
         TxD = R_Shifter[7];
      else 
         TxD = TxD_2;
   end

   always @(posedge RST or posedge CLK2M) begin
      if (RST) 
         R_Shifter = 8'b01111110;
      else if (Load_EN) 
         R_Shifter = 8'b01111110;//7EH
      else 
         R_Shifter = {R_Shifter[6:0],R_Shifter[7]};
   end
   
   always @(posedge RST or posedge CLK2M) begin
      if (RST)
         Count32 = 5'b11111;
      else if (~FS) 
         Count32 = 5'b11111;
      else if (TSR_Shift_EN) 
         Count32 = Count32 - 1;
   end
   // 对TSR移位32次,即进入空闲态,因此Count32对TSR_Shift_EN进行计数
   always @(Count32) begin
      if (Count32 == 5'b00000)
         Load_EN = 1'b1;
      else 
         Load_EN = 1'b0;
   end

   always @(state) begin
      Mux_Sel2 = state;
   end
   //
   always @(posedge RST or FS or negedge CLK2M) begin
      if (RST)
         state = 1'b0;
      else if (FS == 1'b0) 
         state = 1'b0;
      else if (Count32 == 5'b00000) 
         state = 1'b1;
   end
   //
   // always @(Load_EN) begin
   //    Mux_Sel2 = Load_EN;
   // end

   always @(posedge RST or posedge CLK2M) begin
      if (RST)
         THR = 8'b00000000;
      else if ((CS == 1'b0&&WR == 1'b0&&A0 == 1'b0)) 
         THR = D;
   end
   //THR_Status是一个状态信号,由于该状态最终可以被处理器通过总线读取,因此可以将它设置为
   //8bits,当THR中有数据时为00000001,否则为00000000;
   // 该信号应该是寄存器信号,无论THR中是否有数据,只要TSR发出一个读信号,那么在
   // 读信号有效的下一个时钟沿,该信号为空
   always @(posedge RST or posedge CLK2M) begin
      if (RST) 
         THR_Status = 8'b00000001;
      else if (WR == 1'b0 && THR_Read == 1'b1 &&A0 == 1'b0) 
         THR_Status = 8'b00000001;
      else if (WR == 1'b1 && THR_Read == 1'b0) 
         THR_Status = 8'b00000000;
   end

   always @(Count8) begin
      if (Count8 == 3'b000) 
         THR_Read = 1'b0;//THR_Read 0 有效
      else 
         THR_Read = 1'b1;
   end

   always @(posedge RST or posedge CLK2M) begin
      if (RST) 
         Count8 = 3'b000;
      else if (~FS) 
         Count8 = 3'b111;
      else if (TSR_Shift_EN)
         Count8 = Count8 - 1;
   end

   assign D = (RD == 1'b0 && A0 == 1'b0)?THR_Status:8'bzzzzzzzz;

endmodule


  • 仿真文件
`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2023/09/12 18:19:03
// Design Name: 
// Module Name: tb_p2s
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//
module tb_p2s;

    // Inputs
    reg RST, CLK2M, CS, WR, RD, FS, A0;
    wire [7:0] D;
    // Outputs
    wire TxD;
    // Instantiate the module
    p2s_transmitter p2s_inst (
        .RST(RST),
        .CLK2M(CLK2M),
        .CS(CS),
        .WR(WR),
        .RD(RD),
        .FS(FS),
        .A0(A0),
        .D(D),
        .TxD(TxD)
    );
    reg [7:0] d;
    // Clock generation
   
    parameter CLK2M_period = 244; // 2.048MHz clock
        
    always begin
        #CLK2M_period CLK2M = ~CLK2M;
    end

    initial begin
        #122;
        #488;
        FS = 1'b0;
        //CS = 1'b0;
        #244;
        FS = 1'b1;
        //CS = 1'b1;
        //#12256;
        #20000;
        #500;
        #244;
        FS = 1'b0;
        #244;
        FS = 1'b1;
        #20000;
    end
    //assign D = (RD == 1'b0)?d:8'bz;、
    assign D = d;
    initial begin
        d = 8'b1100_1100;
        # 732;//244+488
        # 2928;//488*8
        //CS = 1'b0;
        d = 8'b1111_1000;
        # 3904;//488*8
        d = 8'b1111_1011;
        # 3904;//488*8
        d = 8'b1110_1000;

        # 3904;//488*8
        d = 8'b1110_1110;
        
        # 732;//244+488
        # 2928;//488*8
        //CS = 1'b0;
        d = 8'b1111_1000;
        # 3904;//488*8
        d = 8'b1111_1011;
        # 3904;//488*8
        d = 8'b1110_1000;
        # 3904;//488*8
        d = 8'b1110_1110;
    end
    initial begin
        CS = 1'b1;
        #122;
        CS = 1'b0;
        #244;
        CS = 1'b1;
        RD = 1'b0;
        #3660;
        CS = 1'b0;
        RD = 1'b1;
        #244;
        CS = 1'b1;
        RD = 1'b0;
        while (1) begin
            #4148;
            CS = 1'b0;
            RD = 1'b1;
            #244;
            CS = 1'b1;
            RD = 1'b0;
        end
        
    end
    // Testbench stimulus
    initial begin
        // Initialize inputs
        RST = 1'b0;
        //CS = 1'b1;
        WR = 1'b0;
        RD = 1'b1;
        FS = 1'b1;
        CLK2M = 1'b0;
        A0 = 1'b0;
        
        #22;
        RST = 1'b1;
        #50;
        RST = 1'b0;
        #10;
        //CS = 1'b0;
       
        #244 ;

        //CS = 1'b1;
        #2440;
        #24400;
        WR = 1'b1;
        d = 8'b1111_1000;
        #24400;
        WR = 1'b0;
        #20000;

        // End simulation
        $finish;
    end
   

endmodule
  • 仿真成功图:
    在这里插入图片描述

图 1 初始化仿真图
因为THR中的数据是由CS,RD和A0信号等待时钟上升沿控制,而将THR中的数据打入TSR中也需要时钟上升沿,故延迟一个时钟周期才将FS置零。
在这里插入图片描述

图 2 四个字节成功传输概览图
在这里插入图片描述

图 3五个连续‘1’之后插入‘0’
在这里插入图片描述

图 4相邻两个字节满足五个连续的‘1’并没有插入‘0’
在这里插入图片描述

图 5成功进入空闲状态,并成功传输7EH
在这里插入图片描述

图 6成功退出空闲状态,进入下一个阶段的传输

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

疯狂的码泰君

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值