Uart串口通信的理解

      串口通信广义的概念有很多,我们这里主要讲RS232这一类型,首先RS232使用的电平是负逻辑电平,所以首先必须采取电平转换芯片,一般采用MAX3232这种芯片,具体的硬件连接图如图所示

再来看串口传输的协议格式:


另外讲解一些串口传输的基础知识:

1.波特率:每秒传输码元符号的个数,假设每秒传输1200个码元,然后每个码元由8bit组成,那么波特率就是1200*8=9600bps,所以我们一般定义的波特率有9600波特,19200波特之类的。本文中我们采用9600波特率,它代表每秒传输9600bit,所以每bit大概传输时间为1000000000/9600=104166ns,按照我们的频率50M来计算,那么传输一个bit的时间大概需要5208这么多个时钟周期,这里我们利用上升沿接收数据,即(当计数记到2603的时候,我们接收数据),这里可用计数器实现。具体代码如下:

module posedge_bps(
                                       clk,
      rst_n,
     bps_start,
     clk_bps_posedge_data
                                  );
input           clk;
input           rst_n;
input          bps_start;
   
       output  reg    clk_bps_posedge_data;

reg [12:0] bps_posedge_cnt;
always@(posedge clk or negedge rst_n)
   if(!rst_n)
        begin
        bps_posedge_cnt<=13'd0;
        clk_bps_posedge_data<=0;
        end
   else
///当检测到bps_start为低电平或者bps_podedge_cnt==5207(即还没有开始传输初始状态,或者计数计满了的时候清零),bps_start由串口数据帧格式控制,当检测到数据位由1变为0的时候表示,bps_start启动了。   当计数记到2603,即一半的时候,正好在数据位的中间,那么就将这几个数据采下来。
 begin
        if((!bps_start)||(bps_posedge_cnt==13'd5207))  
       begin
       bps_posedge_cnt<=13'd0;
       clk_bps_posedge_data<=0;
       end
        else
 begin
 bps_posedge_cnt<=bps_posedge_cnt+1;
   if(bps_posedge_cnt==13'd2603)
    clk_bps_posedge_data<=1;
   else
    clk_bps_posedge_data<=0;
 end
  end

endmodule 


2.接收数据代码如下:

  从串口传输数据帧格式中我们可以看到,当检测到数据位由1变为0的时候(脉冲边沿检测可以搞定),这就是数据开始传输的标志,第一位是起始位,在数据中间采样点的时候(2603),我们不用采下来,后面紧接着8位数据位,我们可以采,然后结束位,不管。在采数据的过程中,我们可以设置一个标志位(receiver_data_flag),再采数据过程中一直保持高点平,当数据接收完毕的时候,将它拉低,所以在发送数据的时候,一旦检测到这个标志位由高变低,则表示接收数据结束,可以发送数据了。

module uart_receiver(
                     //////////////global input interface
clk,
rst_n,

/////////////Uart input interface
clk_bps_posedge,
uart_data_in,

////////////Uart output interface
receiver_data,
                                        receiver_data_start_flag,
                                        bps_start
                     );


input         clk;
input         rst_n;  
input         clk_bps_posedge;  
input         uart_data_in ;  


output  reg [7:0] receiver_data;  
output        receiver_data_start_flag;  
output        bps_start;  
//////////////////////////闂佸憡鑹鹃張顒勵敆閻愮儤鐓傚┑鐘插暞閺夊綊鏌ㄥ☉妯垮缂佽鲸鎸搁~銏ゅΨ閵夘喗些婵 
/*reg  rst_n1,rst_n2;
wire true_rst_n;
always@(posedge clk or negedge rst_n)
  if(!rst_n)
   begin
     rst_n1<=0;
     rst_n2<=0;  
   
   end
 else
   begin
rst_n1<=1;
rst_n2<=rst_n1;
   end


assign true_rst_n=rst_n2;
*/
/////////////////////////////////////////////////闂佽桨鑳舵晶妤€鐣垫担鍦枖閻庯綆鍠楅鏍ㄧ箾鐏炴儳顕滄い銉ユ噹闇
reg uart_data_in1,uart_data_in2;
always@(posedge clk or negedge rst_n)
 if(!rst_n)
 begin
 uart_data_in1<=0;
 uart_data_in2<=0;
 end
  else
  begin
  uart_data_in1<=uart_data_in;
  uart_data_in2<=uart_data_in1;
  end  
 
 assign uart_negedge_data=((~uart_data_in1)&(uart_data_in2))?1'b1:1'b0;
 
 ////////////
 reg clk_bps_posedge1,clk_bps_posedge2;
always@(posedge clk or negedge rst_n)
 if(!rst_n)
 begin
  clk_bps_posedge1<=0;
  clk_bps_posedge2<=0;
 end
 else
  begin
  clk_bps_posedge1<=clk_bps_posedge;
  clk_bps_posedge2<=clk_bps_posedge1;
 end
 
 assign clk_bps_posedge_true=clk_bps_posedge2;
 
 /////////////////////////////////
reg bps_start_r;
reg receiver_data_start_flag_r;
reg [3:0] receiver_data_cnt;
 always@(posedge clk or negedge rst_n)
 if(!rst_n)
     begin
     bps_start_r<=0;
     receiver_data_start_flag_r<=0;
     end
 else
 if(uart_negedge_data)
     begin
      bps_start_r<=1;
      receiver_data_start_flag_r<=1;
     end   
 else
 if(receiver_data_cnt==4'd10)
     begin
      receiver_data_start_flag_r<=0;
 bps_start_r<=0;
end
 
 assign bps_start=bps_start_r;
 assign receiver_data_start_flag=receiver_data_start_flag_r;
 
////////////////////////
reg [7:0] receiver_data_r;
always@(posedge clk or negedge rst_n)
 if(!rst_n)
 begin
 receiver_data_r<=0;
 receiver_data_cnt<=0;
 end  
   else
if(receiver_data_start_flag)
begin
 if((clk_bps_posedge_true)&&(receiver_data_cnt<=9))
  begin
         receiver_data_cnt<=receiver_data_cnt+1;
         case(receiver_data_cnt)
  0:                                                     ;
  1:receiver_data_r[0]<=uart_data_in;
                   2:receiver_data_r[1]<=uart_data_in;
  3:receiver_data_r[2]<=uart_data_in;
  4:receiver_data_r[3]<=uart_data_in;
  5:receiver_data_r[4]<=uart_data_in;
  6:receiver_data_r[5]<=uart_data_in;
  7:receiver_data_r[6]<=uart_data_in;
  8:receiver_data_r[7]<=uart_data_in;
                   9:                                                     ;
  default:;
     endcase
end
else
 begin
          receiver_data<=receiver_data_r;
       //   receiver_data_cnt<=0;
  end
         end
else
        begin
         receiver_data<=receiver_data;
         receiver_data_cnt<=0;
        end   

endmodule 

3.发送数据代码如下:

   一旦检测到接收的数据标志位由高变低,表示接收数据完成,可以发送数据了,也在上升沿发送(2603)。

module uart_trans(
                                  clk,
 rst_n,
 trans_data_start,
 trans_data,
 
 uart_data_out,
 bps_start2,
 clk_bps_trans

                              );
input       clk;
input       rst_n;
input       trans_data_start;  
input [7:0] trans_data;  
input       clk_bps_trans;  
output   uart_data_out;
output    reg      bps_start2;
 
////////////////////////////////////////
 
/*reg  rst_n3,rst_n4;
wire true_rst_n;
always@(posedge clk or negedge rst_n)
  if(!rst_n)
   begin
     rst_n3<=0;
     rst_n4<=0;  
   
   end
 else
   begin
rst_n3<=1;
rst_n4<=rst_n3;
   end


assign true_rst_n=rst_n4;  
*/  
////////////////////////
reg trans_data_start1,trans_data_start2;
always@(posedge clk or negedge rst_n)
  if(!rst_n)
  begin
  trans_data_start1<=0;
  trans_data_start2<=0;
  end
  else
  begin
  trans_data_start1<=trans_data_start;
  trans_data_start2<=trans_data_start1;
  
  end

assign trans_data_negedge_start=((~trans_data_start1)&(trans_data_start2))?1'b1:1'b0;

/////////////////////////////////
reg trans_data_en;
reg [3:0] trans_data_cnt;
always@(posedge clk or negedge rst_n)
  if(!rst_n)
  begin
  bps_start2<=0;
  trans_data_en<=0;
  end
 else
     if(trans_data_negedge_start)
 begin
 trans_data_en<=1;
 bps_start2<=1;
 end
 else
     if(trans_data_cnt==4'd10)
 begin
 trans_data_en<=0;
       bps_start2<=0;
end
  
reg uart_data_out;
always@(posedge clk or negedge rst_n)
if(!rst_n)
begin
trans_data_cnt<=0;
uart_data_out<=0;
     end
else
   if(trans_data_en)
   begin
     if((clk_bps_trans)&(trans_data_cnt<=9))
      trans_data_cnt<=trans_data_cnt+1;
case(trans_data_cnt)
        0:uart_data_out<=1;
1:uart_data_out<=trans_data[0] ;
                2:uart_data_out<=trans_data[1] ;
3:uart_data_out<=trans_data[2] ;
4:uart_data_out<=trans_data[3] ;
                5:uart_data_out<=trans_data[4] ;
6:uart_data_out<=trans_data[5] ;
7:uart_data_out<=trans_data[6] ;
                8:uart_data_out<=trans_data[7] ;
9:uart_data_out<=1;
  default:;
  endcase
 if(trans_data_cnt==10)   
trans_data_cnt<=0;
end   

endmodule 

4.采用同步释放,异步复位电路,防止亚稳态的产生,具体代码如下:

module sys(
                clk,
rst_n,
true_rst_n
          );
 
input rst_n,clk;
output true_rst_n;
reg  rst_n1,rst_n2;
wire true_rst_n;
always@(posedge clk  )
  if(!rst_n)
   begin
     rst_n1<=0;
     rst_n2<=0;  
   
   end
 else
   begin
rst_n1<=1;
rst_n2<=rst_n1;
   end
assign true_rst_n=rst_n2;
endmodule 

5.顶层模块例化,分层写有利于后期维护和修改,具体如下:

///////////
module uart(
                       clk,
rst_n,
uart_data_in,
uart_data_out
            );
input clk;
input rst_n;
input uart_data_in;
output uart_data_out;


wire bps_start;
wire clk_bps_posedge_data;
wire [7:0] receiver_data;
wire receiver_data_start_flag;
wire bps_start2 ;     
wire clk_bps_posedge1;
wire true_rst_n;




posedge_bps     U1(
                                       .clk                     (clk                  ),
      .rst_n                   (true_rst_n           ),
      .bps_start               (bps_start            ),
      .clk_bps_posedge_data    (clk_bps_posedge_data )
                             );

uart_receiver    U2 (
                                               .clk                                   (clk)                 ,
     .rst_n                                (true_rst_n)          ,
     .clk_bps_posedge            (clk_bps_posedge_data),
     .uart_data_in                    (uart_data_in)        ,
     .receiver_data                  (receiver_data)       ,
                                              .receiver_data_start_flag (receiver_data_start_flag) ,
                                             .bps_start                         (bps_start)
                     );


posedge_bps     U3( 
                                       .clk                                    (clk                  ),
      .rst_n                                (true_rst_n           ),
      .bps_start                         (bps_start2           ),
      .clk_bps_posedge_data   (clk_bps_posedge1 )
                    );


uart_trans       U4( 
                                         .clk                           (clk                      )         ,
         .rst_n                      (true_rst_n               )         ,
         .trans_data_start    (receiver_data_start_flag )         ,
         .trans_data             (receiver_data            )         ,
                                
         .uart_data_out       (uart_data_out            )         ,
         .bps_start2            (bps_start2              )         ,
  .clk_bps_trans       (clk_bps_posedge1         )
                 
                           );
 

 sys               U5 (
                               .clk(clk),
               .rst_n(rst_n),
               .true_rst_n(true_rst_n)
                       );

endmodule

6.仿真代码:

`timescale 1 ns/ 1 ns
module uart_vlg_tst();
// constants                                           
// general purpose registers
reg eachvec;
// test vector input registers
reg clk;
reg rst_n;
reg uart_data_in;
// wires                                               
wire uart_data_out;


// assign statements (if any)                          
uart i1 (
// port map - connection between master ports and signals/registers   
.clk(clk),
.rst_n(rst_n),
.uart_data_in(uart_data_in),
.uart_data_out(uart_data_out)
);
initial                                                
begin                                                  
clk=0;
forever #10 clk=~clk;                                            
end                  


initial begin
rst_n=0;
#8000 ;
rst_n=1;
end

initial begin
uart_data_in=1;
end
 
task task_data_in;
input [7:0] uart_data;
begin
#200000;
uart_data_in<=0;
#104166;
uart_data_in<=uart_data[0];
#104166;
uart_data_in<=uart_data[1];
#104166;
uart_data_in<=uart_data[2];
#104166;
uart_data_in<=uart_data[3];
#104166;
uart_data_in<=uart_data[4];
#104166;
uart_data_in<=uart_data[5];
#104166;
uart_data_in<=uart_data[6];
#104166;
uart_data_in<=uart_data[7];
#104166;
uart_data_in<=1;
#200000;
end
endtask
initial begin
#200;
task_data_in(8'hcb);
#200;
task_data_in(8'h0a);
#200;
task_data_in(8'h09);
#200;
task_data_in(8'h0f);

end

endmodule

7.RTL示图和仿真结果:

1).RTL



2).仿真结果




记住:调试的售后可用串口调试助手等等,波特率需保持一致。

























猜你喜欢

转载自blog.csdn.net/qaaz12322/article/details/75751631