zoukankan      html  css  js  c++  java
  • RS232串口通信

    RS232串口经常使用在PC机与FPGA通信中,用于两者之间的数据传输,因为UART协议简单、易实现,故经常使用。

    DB9接口只需要使用3根线,RXD(2)、TXD(3)和GND(5),如下图所示。而用FPGA实现控制器时只需要利用RXD和TXD两根线即可完成串口通信。

    UART的异步通信协议如下所示:

    1. 首先接受双方提前定义好通信的速度和格式等信息;

    2. 如果是空闲状态,发送器一直将数据线拉高;

    3. 开始通信时,发送器将数据线拉低,从而接收器能知道数据字节即将过来;

    4. 数据位通常是8位,低位先发送,高位后发送;

    5. 停止通信时,发送器将数据线再次拉高。

    控制器包括3部分:波特率发生器、发送器和接收器,本设计发送器和接收器都带有异步FIFO缓存数据。本设计完成如下功能;串口助手发送数据字节给FPGA,FPGA将数据返回给串口助手。波特率采用11520bps,数据格式1位开始位、8位数据位和1位停止位,无校验位。

    image

    1. 波特率发生器

    波特率发生器需要对主时钟进行分频生成发送器和接收器的工作时钟。发送器的时钟就等于波特率,而接收器的时钟频率是波特率的8倍或者16倍,即对发送器发过来的数据进行过采样以获得准确的数据。下面是接收器和发送器的分频系数。

    parameter   Div_rcv     = Clk_freq/Bandrate/16-1;  //8倍
    parameter   Div_trans   = Clk_freq/Bandrate/2-1;

    发送完一个数据字节后,等待FIFO_T非空或者FIFO_R非空。

     1 module clk_generater(clk_rcv,clk_trans,clk_in,reset);
     2 
     3  parameter   Clk_freq    = 50000000;
     4  parameter   Bandrate    = 115200;
     5  parameter   Div_rcv     = Clk_freq/Bandrate/16-1;
     6  parameter   Div_trans   = Clk_freq/Bandrate/2-1;
     7 
     8  output      clk_rcv,clk_trans;
     9  input       clk_in,reset;
    10  
    11  reg         clk_rcv,clk_trans;
    12  reg [15:0]  counter_rcv;
    13  reg [15:0]  counter_trans;
    14 
    15  always @ ( posedge clk_in )
    16   if(reset == 1) begin
    17     clk_rcv   <= 0;
    18     clk_trans <= 0;
    19     counter_rcv  <= 0;
    20     counter_trans  <= 0;
    21   end else begin
    22     if( counter_rcv == Div_rcv )begin 
    23       clk_rcv  <= ~clk_rcv;
    24       counter_rcv <= 0;
    25     end else counter_rcv <= counter_rcv + 1'b1;
    26     
    27     if( counter_trans == Div_trans )begin 
    28       clk_trans  <= ~clk_trans;
    29       counter_trans <= 0;
    30     end else counter_trans <= counter_trans + 1'b1;
    31  end
    32 endmodule 
    View Code

    2. 发送器

    发送器发送的数据从FIFO_T中读取,而FIFO_T数据是从FIFO_R获得。如果FIFO_T非空,读取一个数据字节并在末尾添加数据位0(开始通信位,拉低数据线),下一步进行9次右移操作,串行输出数据位。

    XMT_shftreg <= { 1'b1,XMT_shftreg[word_size:1]};

    assign Serial_out = XMT_shftreg[0];

      1 module UART_Transmitter(              //UART transmitter with 16Byte transmit FIFO
      2 output                  Serial_out,       //serial output to data channel
      3 output                  Busy,             //used to indicate FIFO is full
      4 output reg              Done,             //used to indicate FIFO is empty
      5 input [word_size - 1:0] Data_Bus,         //host data bus
      6 input                   Load_XMT_datareg, //used by host to load data to FIFO
      7 input                   clk_trans,
      8 input                   Clk,              //clk input
      9 input                   reset            //reset input
     10 );
     11 parameter  word_size = 8;                 //size of data word
     12 parameter  one_hot_count = 3;             //number of one-hot states
     13 parameter  state_count = one_hot_count;   //munber of bits in state register
     14 parameter  size_bit_count = 3;            //size of the bit counter
     15                                           //must count to word_size + 1
     16 
     17 parameter  idle = 3'b001;                 //one-hot state encoding
     18 parameter  waiting = 3'b010;
     19 parameter  sending = 3'b100;
     20 parameter  all_ones = 9'b1_1111_1111;     //word+1 extra bit 
     21 
     22 reg [word_size:0]       XMT_shftreg;      //transmit shift register
     23 reg                     Load_XMT_shftreg; //flag to load XMT_shftreg
     24 reg [state_count - 1:0] state,next_state; //state machine controller
     25 reg [size_bit_count:0]  bit_count;        //counts the bits that are transmitting
     26 reg                     clear;            //clears bit_count after last bit is sent 
     27 reg                     shift;            //causes shift of data in XMT_shftreg
     28 reg                     start;            //signals start of transmission
     29 
     30 wire[word_size - 1:0]   FIFO_Data_Bus;    //output of FIFO
     31 wire                    empty;            //indicates the FIFO is empty
     32 wire                    Byte_ready;       
     33 
     34 fifo_receiver FIFO_TRS(   
     35     .aclr(reset),                      //Dual clock FIFO generated by Altera megafunction wizard
     36     .data(Data_Bus),//
     37     .rdclk(clk_trans),//
     38     .rdreq(Load_XMT_shftreg),//
     39     .wrclk(Clk),//
     40     .wrreq(Load_XMT_datareg),//
     41     .q(FIFO_Data_Bus),//
     42     .rdempty(empty),//
     43     .wrfull(Busy));//
     44 
     45 assign Serial_out = XMT_shftreg[0];
     46 assign Byte_ready = ~empty;
     47 
     48 always@(state or Byte_ready or bit_count )begin:Output_and_next_state
     49  Load_XMT_shftreg = 0;
     50  clear = 0;
     51  shift = 0;
     52  start = 0;
     53  Done  = 0;
     54  next_state = state;
     55  case(state)
     56   idle:          if(Byte_ready == 1)begin
     57                    Load_XMT_shftreg = 1;
     58                    next_state = waiting;
     59                  end 
     60                                  
     61   waiting:       begin
     62                    start = 1;
     63                    next_state = sending;
     64                  end
     65                 
     66   sending:       if(bit_count != word_size + 1)
     67                     shift = 1;
     68                  else if(Byte_ready == 1)begin
     69                     clear = 1;
     70                     Load_XMT_shftreg = 1;
     71                     next_state = waiting;
     72                  end else begin
     73                     clear = 1;
     74                     Done  = 1;
     75                     next_state = idle;
     76                  end
     77                  
     78   default:       next_state = idle;
     79  endcase
     80 end
     81 
     82 always@(posedge clk_trans or posedge reset)begin:State_Transitions
     83   if(reset == 1)state <= idle; else state <= next_state; end
     84   
     85 always@(posedge clk_trans or posedge reset)begin:Register_Transfers
     86   if(reset == 1)begin
     87     XMT_shftreg <= all_ones;
     88     bit_count <= 0;
     89   end else begin   
     90      
     91     if(start == 1)                               //starts the transmission
     92         XMT_shftreg <= {FIFO_Data_Bus,1'b0};     //添加一位起始位0
     93       
     94     if(clear == 1) bit_count <= 0;               
     95     else if(shift == 1)bit_count <= bit_count + 1'b1;
     96     
     97     if(shift == 1)
     98       XMT_shftreg <= { 1'b1,XMT_shftreg[word_size:1]}; //Shift riht, fill with 1's
     99   end
    100 end
    101 
    102 endmodule 
    View Code

    3. 接收器

    本设计采样时钟频率是波特率的8倍,数据有效的中间时刻采样数据,即在第4个采样时钟获取数据。先采样到起始数据0之后,通过一个计数器计满8个时钟采样下一个有效数据。当采样获得8位数据后将8位数据写入FIFO_R,从而产生非空信号准备供发送器FIFO_T读取。

    RCV_shftreg <= {Serial_in,RCV_shftreg[word_size - 1:1]};

      1 // ============================================================
      2 // File Name: UART_Receiver.v
      3 // Module Name(s):
      4 //             UART Receiver with FIFO(8x256)
      5 //
      6 // Version: V1.0
      7 // Date: 08/11/2014 
      8 // Author: Wang Zhongwei
      9 // Copyright (C) 1896-2009 Beijing Jiao Tong University
     10 // ************************************************************
     11 // CAUTION:
     12 //   This module can only be used in Altera Quarus II environment.
     13 //   Use megafuncton wizard to generate a dual clock FIFO 
     14 //   called "fifo_receiver" before synthesis this module.
     15 // =============================================================
     16 module UART_Receiver(
     17 output      [word_size - 1:0]      Data_bus_out,
     18 //output      [word_size - 1:0]      RCV_datareg;
     19 output                             empty,
     20 //                                   Error1,Error2;//Error1:asserts if host is not ready to receive data after last bit
     21                                                  //Error2:asserts if the stop-bit is missing
     22 input       Serial_in,Sample_clk,clk_in,reset,read
     23 );
     24 //(Data_bus_out,RCV_datareg,empty,Error1,Error2,Serial_in,read,Sample_clk,clk_in,reset);
     25 //Samlpe _clk is 8x Bit_clk
     26 
     27 parameter   word_size              = 8;
     28 parameter   half_word              = word_size/2;
     29 parameter   Num_counter_bits       = 4;
     30 parameter   Num_state_bits         = 3;
     31 parameter   idle                   = 3'b001;
     32 parameter   starting               = 3'b010;
     33 parameter   receiving              = 3'b100;
     34 
     35 //reg         [word_size - 1:0]      Data_bus_out;            
     36 //reg         [word_size - 1:0]      RCV_datareg;
     37 reg         [word_size - 1:0]      RCV_shftreg;
     38 reg         [Num_counter_bits-1:0] Sample_counter;
     39 reg         [Num_counter_bits:0]   Bit_counter;
     40 reg         [Num_state_bits-1:0]   state,next_state;
     41 reg                                inc_Bit_counter,clr_Bit_counter;
     42 reg                                inc_Sample_counter,clr_Sample_counter;
     43 reg                                shift,load;
     44 //reg                                Error1,Error2;
     45 
     46 //wire                               read_not_ready_in;
     47 //instance of receive FIFO
     48 fifo_receiver FIFO_RCV(
     49     .aclr(reset),
     50     .data(RCV_shftreg),
     51     .rdclk(clk_in),
     52     .rdreq(read),
     53     .wrclk(Sample_clk),
     54     .wrreq(load),
     55     .q(Data_bus_out),
     56     .rdempty(empty),
     57     .wrfull());  //read_not_ready_in
     58 
     59 //we can also use the clk_50M as the clock,while Sample_clk is the enable signal
     60 
     61 reg[3:0] RXD_reg = 4'b1111;
     62 //synchronize the Serial_in(RX),
     63 always @ (posedge Sample_clk or posedge reset)
     64   if(reset) RXD_reg <= 4'b1111;
     65   else RXD_reg <= {RXD_reg[2:0],Serial_in};
     66 
     67 always @ (posedge Sample_clk or posedge reset)
     68   if(reset) state <= idle; else state <= next_state;
     69     
     70 //Combinational logic for next state and conditional outputs
     71 always @ (*) begin
     72   clr_Sample_counter = 1'b0;
     73   clr_Bit_counter = 1'b0;
     74   inc_Sample_counter = 1'b0;
     75   inc_Bit_counter = 1'b0;
     76   shift = 1'b0;
     77 //  Error1 = 1'b0;
     78 //  Error2 = 1'b0;
     79   load = 1'b0;
     80   next_state = state;
     81   
     82   case(state)
     83    idle:         if(RXD_reg == 0) begin next_state = receiving; end  //register 4 seria_in datas to capture the middle sample point of the data
     84                  
     85     receiving:    if(Sample_counter < word_size - 1) inc_Sample_counter = 1'b1;
     86                   else begin
     87                         clr_Sample_counter = 1'b1;
     88                    if(Bit_counter != word_size)begin
     89                      shift = 1'b1;
     90                      inc_Bit_counter = 1'b1;
     91                    end
     92                    else begin
     93                      next_state = idle;
     94                      clr_Bit_counter = 1'b1;
     95                             load = 1'b1;
     96                             //read_not_ready_out = 1'b1;
     97 //                     if(read_not_ready_in == 1'b1) Error1'b1 = 1'b1;
     98 //                     else if(Serial_in == 0) Error2 = 1'b1;
     99 //                     else load = 1'b1;
    100                     end
    101                  end
    102    default:       next_state = idle;
    103    
    104   endcase
    105 end
    106 
    107 always @ (posedge Sample_clk or posedge reset)begin
    108   if(reset)begin
    109     Sample_counter <= 3'd0;
    110     Bit_counter <= 4'd0;
    111 //    RCV_datareg <= 0;
    112     RCV_shftreg <= 8'd0;
    113   end
    114   else begin
    115     if(clr_Sample_counter) Sample_counter <= 3'd0;
    116     else if(inc_Sample_counter) Sample_counter <= Sample_counter + 1'b1;
    117     
    118     if(clr_Bit_counter)Bit_counter <= 4'd0;
    119     else if(inc_Bit_counter) Bit_counter <= Bit_counter + 1'b1;
    120     
    121     if(shift) RCV_shftreg <= {Serial_in,RCV_shftreg[word_size - 1:1]};  //RXD_reg[2] RXD_reg[1] RXD_reg[0] Serial_in are all ok
    122     
    123    // if(load == 1) RCV_datareg <= RCV_shftreg;
    124   end
    125 end
    126 endmodule
    127      
    View Code
    4. 实验结果

    在实验板测试UART通信,接收数据个数等于发送数据个数,能满足一般的通信要求。如果想提高准确度,可提高采样频率、增加校验位或者增加停止位个数(1.5或2)。

    此外,3个模块可以共使用一个系统时钟clk。接收器和发送器工作时钟可以作为clk的时钟使能信号,这样这个设计就只使用了一个时钟。

  • 相关阅读:
    Keil MDK中单个c文件生成LIB文件
    STM32标准外设库、 HAL库、LL库
    STM32CubeMX介绍、下载与安装
    static关键字的总结
    Qt中 QString 转 char*
    字符串(string)与整型(int)、浮点型(float)等之间的转换
    RF相关知识
    Qt4问题集锦
    Qt4程序在windows平台下打包发布
    (81)Client、Server通信模式和P2P通信模式的区别
  • 原文地址:https://www.cnblogs.com/aikimi7/p/3904133.html
Copyright © 2011-2022 走看看