UART 通信逻辑协议设计(2)

5 . 各模块详细设计
1)波特率发生器模块:假定系统时钟为50M,波特率为115200,则传输每一位所需的时间为8.6805us,而将其分频至波特率的16倍则需计数则在系统时钟下当计数值为27时则将Baud16Tick置为1,其他时间都为0。要得到波特率脉冲时则在Baud16Tick节拍下计数至16时将BaudTick置为1,其他值时为0。程序如下:

  always @(posedge clk )    
  begin
      if (rst)
        begin
                OverSampleCnt <=8'b0;
                Baud16Tick <= 1'b0;
         end
      elseif(OverSampleCnt== OverSampleCntnum)
        OverSampleCnt <= 1'b0;
      else 
        OverSampleCnt <=OverSampleCnt+1;
      case(OverSampleCnt== OverSampleCntnum/2)  
        OverSampleCntnum/2:Baud16Tick <= 1'b1;
        default:Baud16Tick <= 1'b0;
  endcase   
  End
 always @(posedge clk or negedge rst)
begin
  if (rst)
    begin
        BaudTick <= 1'b0;
         BaudTickCnt <= 4'b0000 ;
    end
  else if (Baud16Tick&&BaudTick_EN)
  BaudTickCnt = BaudTickCnt +1 ;
  elseif((BaudTickCnt== 4’b1111)
  BaudTickCnt <= 4'b0000 ;  
  case(BaudTickCnt) 
  4'b1000:BaudTick <= 1'b1;
  default:BaudTick <= 1'b0;
   endcase
end

2)数据发送器模块:在Baud16Tick的节拍下捕捉TXD_start的下降沿,之后将din8的数据存入缓冲器tbr中,再启动BaudTick脉冲并计数,在计数为4’b0000时发送停止位0,在4’b0001至4’b1000时发送数据位,并在之后两位发送奇偶校验位和停止位。没有发送是则发送空闲位1。校验每发一位就将parity进行异或数据位得到其值并发送。当发送停止位后,即将发送完成标志位TXD_done置1.程序如下:

always@(posedge clk)
    begin
        if(rst)
            begin
                {TxD_start0,TxD_start1} <= {1'b0,1'b0};
            end
        else 
            TxD_start0 <= TxD_start;
            TxD_start1 <= TxD_start0;   
    end
assign start = TxD_start1&!TxD_start0;
always@(posedge clk or posedge rst)
    begin 
        if(rst) 
            tbr<= 8'b0;
        else if(BaudTick_EN&&BaudTick)
            tbr <= TxD_data;
    end 
always @(posedge clk or posedge rst)
    begin
        if (rst)
            BaudTick_EN <= 1'b0;
        else if (start)       
            BaudTick_EN <= 1'b1 ;
        else if (no_bits_tran == 4'b1100)
            BaudTick_EN <= 1'b0 ;
  end
always @(posedge clk or negedge rst )
    begin
        if (rst)
            no_bits_tran <= 4'b0000;
        else if (BaudTick&&Baud16Tick)
          no_bits_tran <= no_bits_tran + 1 ;
        else if (no_bits_tran ==4'b1100)
            no_bits_tran <= 4'b0000 ;
   end

always @(posedge clk or negedge rst) 
    if (rst)
       begin
         TxD <= 1'b1; 
         tbr <= 8'b0 ;
         tsr <= 8'b0 ; 
         parity <= 1'b0 ; 
         TxD_done <= 1'b0;
      end 
    else
       begin 
            if(BaudTick)
                begin
                    case (no_bits_tran)
                        4'b0000: begin 
                                    TxD <= 1'b0; 
                                    tsr <= tbr; 
                                    parity <= ^tsr ; 
                                    TxD_done <= 1'b0;
                                end
                        4'b0001: begin TxD <= tsr[0]; end
                        4'b0010: begin TxD <= tsr[1]; end
                        4'b0011: begin TxD <= tsr[2]; end
                        4'b0100: begin TxD <= tsr[3]; end
                        4'b0101: begin TxD <= tsr[4]; end
                        4'b0110: begin TxD <= tsr[5]; end
                        4'b0111: begin TxD <= tsr[6]; end
                        4'b1000: begin TxD <= tsr[7]; end
                        4'b1001: begin TxD <= parity; end
                        4'b1010: begin TxD <= 1'b1; end
                        4'b1011: begin 
                                  TxD_done <= 1'b1;
                                end
                        default: TxD_done <= 1'b0 ;
                    endcase
                end
        end  

3)数据接收器模块:首先利用波特率16的采样脉冲对发送模块发送过来的串行数据进行下降沿采样,若采集到下降沿则开始启动BaudTick,并开启计数使能。在BaudTick的脉冲下进行计数并逐位读取发送端发过来的数据位,奇偶校验在case值为4’b0001至4’b1000时进行,当计数为4’b1001时发送判断校验位和检测停止位,在4’b1010时将奇偶校验和帧检查结果发送到端口中。程序如下所示:

always@(posedge clk or negedge rst)
    begin
        if(rst)
            begin
                {TxD_start0,TxD_start1} <= {1'b0,1'b0};
            end
        else 
            TxD_start0 <= TxD_start;
            TxD_start1 <= TxD_start0;   
    end
assign start = TxD_start1&!TxD_start0;
always @(posedge clk or negedge rst )
    begin
        if (rst)
            no_bits_tran <= 4'b0000;
        else if (BaudTick&&Baud16Tick)
          no_bits_tran <= no_bits_tran + 1 ;
        else if (no_bits_tran ==4'b1100)
            no_bits_tran <= 4'b0000 ;
    End
always@(posedge clk or posedge rst)
    begin 
        if(rst) 
            tbr<= 8'b0;
        else if(BaudTick_EN&&BaudTick)
            tbr <= TxD_data;
    end 
always @(posedge clk or negedge rst )
    begin
        if (rst)
            no_bits_tran <= 4'b0000;
        else if (BaudTick&&Baud16Tick)
            no_bits_tran <= no_bits_tran + 1 ;
        else if (no_bits_tran ==4'b1100)
            no_bits_tran <= 4'b0000 ;
    end
always @(posedge clk or negedge rst) 
    if (rst)
    begin
      TxD <= 1'b1; tbr <= 8'b0 ;
      tsr <= 8'b0 ; parity <= 1'b0 ; 
      TxD_done <= 1'b0;  
    end 
    else
       begin 
            if(BaudTick)
                begin
                    case (no_bits_tran)
                        4'b0000: begin 
                            TxD <= 1'b0; tsr <= tbr; parity <= ^tsr ;TxD_done <= 1'b0;
                                end
                        4'b0001: begin TxD <= tsr[0]; end
                        4'b0010: begin TxD <= tsr[1]; end
                        4'b0011: begin TxD <= tsr[2]; end
                        4'b0100: begin TxD <= tsr[3]; end
                        4'b0101: begin TxD <= tsr[4]; end
                        4'b0110: begin TxD <= tsr[5]; end
                        4'b0111: begin TxD <= tsr[6]; end
                        4'b1000: begin TxD <= tsr[7]; end
                        4'b1001: begin TxD <= parity; end
                        4'b1010: begin TxD <= 1'b1; end
                        4'b1011: begin 
                                 TxD_done <= 1'b1;
                                end
                        default: TxD_done <= 1'b0 ;
                    endcase
                end
        end

3)顶层文件设计:两模块之间用wire类型连接,公共端用分别在两个模块中连接。顶层端口定义最终需要的端口即可。顶层模块如下:

TxD_Module u1(
            .clk(clk_sys),
            .rst(rst_N),
            .TxD_data(din8),
            .TxD_done(TxDdne_rdn),
            .TxD(TxD_RxD),
            .TxD_start(TxD_start_in)
            );

RxD_Module u2 (
            .clk(clk_sys),
            .rst(rst_N),
            .rdn(TxDdne_rdn),
            .RxD(TxD_RxD),
            .RxD_data(dout8),
            .parity_error(parity_err_out),
            .framing_error(frame_err_out),
            .RxD_data_ready(RxD_data_rdy)
            );

6.Modelsim仿真验证
1)测试激励:高电平初始化后进行发送递加的数据,并观察输入输出数据的差异,以及奇偶校验位和帧检查的正确性。

initial 
        begin
            clk_sys = 0;
            rst_N = 1;
            din8 = 0;
            TxD_start_in = 0;
            #100;   
            rst_N = 0;
            repeat(100) begin
            #   86800;
            TxD_start_in = 1;
            # 86800;
            TxD_start_in = 0;
        end
      end
   always #10  clk_sys = ~clk_sys;  
    always @(posedge TxD_start_in)
    begin 
        din8 = din8 + 8'd1;
    end 

2)输入输出结果。激励文件和输出结果如下:UART 通信逻辑协议设计(2)_第1张图片
3) 结果分析:由上图可知
  1 整个联合模块的并行输入与并行输出结果相同,接发送和接收正确。
  2 奇偶校验位发现当数据为01010010时校验的结果为1,当数据为01010011时校验结果为0;由此可知奇偶校验正确
  3 检查帧结果显示一致为0,而发送端的数据均为8位且停止位都为1。所以帧检查结果正确。

你可能感兴趣的:(HDL)