纯手打 uart协议

      最后更新:2022-02-17 13:40:19 手机定位技术交流文章

      自己借鉴网上写的,自我觉得这种方法挺好,每个信号分给一个时序描述。分享给大家

      串口通信一般呢,两种方式:同步和异步。

      同步:通信双方在同一时钟的控制下,同步传输数据;

      异步:通信双方使用各自的时钟控制数据的发送和接受;

      UART 是一种采用异步串行通信方式的通用异步收发传输器( universal asynchronous receiver
      transmitter ),它在发送数据时将并行数据转换成串行数据来传输,在接收数据时将接收到的串行数据转换成并行数据。
      UART 在发送 或接收过程中的一帧数据由 4 部分组成, 起始位 数据位 奇偶校验位 停止位;
      起始位:标志着一帧数据的开始,1位,一般起始位为0;
      数据位:可以选择为5、6、7、8位,常用8位;
      奇偶检验位:可选奇检验、偶检验,或者无检验位;
      停止位:默认一位,可选1.5、2位。

      串口通信的速率用波特率表示,表示每秒传输比特位的位数,单位bps,常用有9600、115200;在设置好数据格式及传输速率之后,UART 负责完成数据的串并转换,而信号的传输则由外部驱动电 路实现。电信号的传输过程有着不同的电平标准和接口规范,针对异步串行通信的接口标准有 RS232 、 RS422、 RS485 等,它们定义了接口不同的电气特性,如 RS-232 是单端输入输出,而 RS-422/485 为差分输入输出等。

      我们选用9600,50MHZ时钟,根据这些我们可以得到发送一比特位需要5208个计数,为了便于仿真,我们这才用28个计数。

      简单介绍这些,下来我们根据时序图来写uart协议。

      首先我们来写一下发送端口的协议。

      module uart(
      input clk,
      input rst_n,
      input start,       //起始信号
      input [7:0] data,        //传输的数据

      output reg rs232_tx,  //串口传输端口
      output reg done       //结束信号
      );

      reg state;         //传送状态
      reg [7:0] r_data;   //寄存器保存数据,防止数据变化引起不必要的错误
      reg [12:0] baud_cnt;//一比特计数
      reg bit_flag;      //一比特计数发送标志
      reg [3:0] bit_cnt;  //发送的第几比特位

      //=============data===============//
      //功能:寄存器保存所要发送的数据
      always@(posedge clk or negedge rst_n)begin
      if(!rst_n)
      r_data <= 8'b0;
      else if(start)
      r_data <= data;
      else
      r_data <= r_data;
      end

      //============state==============//
      //功能:发送状态的变化
      always@(posedge clk or negedge rst_n)begin
      if(!rst_n)
      state <= 1'b0;
      else if(start)
      state <= 1'b1;
      else if(done)
      state <= 1'b0;
      else
      state<=state;
      end

      //=============baud_cnt=========//
      //发送一比特计数器
      always@(posedge clk or negedge rst_n)begin
      if(!rst_n)
      baud_cnt <= 1'b0;
      else if(state)begin
      if(baud_cnt == 13'd28)
      baud_cnt <= 13'd0;
      else
      baud_cnt <= baud_cnt + 1'b1;
      end
      else
      baud_cnt <= 13'd0;
      end

      //===============bit_flag=======//发送比特标志位
      always@(posedge clk or negedge rst_n)begin
      if(!rst_n)
      bit_flag <= 1'b0;
      else if(baud_cnt == 13'd1)
      bit_flag <= 1'b1;
      else
      bit_flag <= 1'b0;
      end

      //===============bit_cnt========//发送的第几个比特
      always@(posedge clk or negedge rst_n)begin
      if(!rst_n)
      bit_cnt <= 4'b0;
      else if(bit_flag)begin
      if(bit_cnt == 4'd10)
      bit_cnt <= 4'd0;
      else
      bit_cnt <= bit_cnt + 1'b1;
      end
      else
      bit_cnt <= bit_cnt;
      end

      //==============rs232_tx=======//
      always@(posedge clk or negedge rst_n)begin
      if(!rst_n)
      rs232_tx <= 1'b1;
      else if(state)begin
      if(bit_flag)begin
      case(bit_cnt)
      4'd0:rs232_tx <= 4'd0;
      4'd1:rs232_tx <= r_data[0];
      4'd2:rs232_tx <= r_data[1];
      4'd3:rs232_tx <= r_data[2];
      4'd4:rs232_tx <= r_data[3];
      4'd5:rs232_tx <= r_data[4];
      4'd6:rs232_tx <= r_data[5];
      4'd7:rs232_tx <= r_data[6];
      4'd8:rs232_tx <= r_data[7];
      4'd9:rs232_tx <= 4'd1;
      default:rs232_tx <= 4'd1;
      endcase
      end
      else ;
      end
      else rs232_tx <= 4'd1;
      end

      //=============done=========//
      //功能:发送结束信号
      always@(posedge clk or negedge rst_n)begin
      if(!rst_n)
      done <= 1'b0;
      else if(bit_flag && bit_cnt == 4'd10)
      done <= 1'd1;
      else
      done <= 1'd0;
      end

      endmodule

      然后接收端口的协议

      module uart_rx(
      input clk,
      input rst_n,
      input rs232,  //接受端口

      output reg [7:0]rx_data,  //接受的数据
      output reg done
      );

      reg rs232_t,rs232_t1,rs232_t2;
      reg [12:0] baud_cnt;
      reg [3:0]  bit_cnt;
      reg state;
      reg bit_flag;
      wire en_flag;

      assign en_flag=(!rs232_t1)&&(rs232_t2);

      //==============消除亚稳态==============
      always@(posedge clk or negedge rst_n)begin
      if(!rst_n)begin
      rs232_t <= 1'b1;
      rs232_t1 <= 1'b1;
      rs232_t2 <= 1'b1;
      end
      else begin
      rs232_t <= rs232;
      rs232_t1 <= rs232_t;
      rs232_t2 <= rs232_t1;
      end
      end

      //==============state==============
      always@(posedge clk or negedge rst_n)begin
      if(!rst_n)
      state <= 1'b0;
      else if(en_flag)
      state <= 1'b1;
      else if(done)
      state <= 1'b0;
      else
      state <= state;
      end

      //=============baud_cnt=========//
      //接受一比特计数器
      always@(posedge clk or negedge rst_n)begin
      if(!rst_n)
      baud_cnt <= 1'b0;
      else if(state)begin
      if(baud_cnt == 13'd28)
      baud_cnt <= 13'd0;
      else
      baud_cnt <= baud_cnt + 1'b1;
      end
      else
      baud_cnt <= 13'd0;
      end

      //===============bit_flag=======//接受比特标志位
      always@(posedge clk or negedge rst_n)begin
      if(!rst_n)
      bit_flag <= 1'b0;
      else if(baud_cnt == 13'd14)
      bit_flag <= 1'b1;
      else
      bit_flag <= 1'b0;
      end

      //===============bit_cnt========//接受的第几个比特
      always@(posedge clk or negedge rst_n)begin
      if(!rst_n)
      bit_cnt <= 4'b0;
      else if(bit_flag)begin
      if(bit_cnt == 4'd10)
      bit_cnt <= 4'd0;
      else
      bit_cnt <= bit_cnt + 1'b1;
      end
      else
      bit_cnt <= bit_cnt;
      end
      //==============rs232_tx=======//
      always@(posedge clk or negedge rst_n)begin
      if(!rst_n)
      rx_data <= 1'b0;
      else if(state)begin
      if(bit_flag)begin
      case(bit_cnt)
      4'd1:rx_data[0] <= rs232_t2;
      4'd2:rx_data[1] <= rs232_t2;
      4'd3:rx_data[2] <= rs232_t2;
      4'd4:rx_data[3] <= rs232_t2;
      4'd5:rx_data[4] <= rs232_t2;
      4'd6:rx_data[5] <= rs232_t2;
      4'd7:rx_data[6] <= rs232_t2;
      4'd8:rx_data[7] <= rs232_t2;
      default:rx_data <= rx_data;
      endcase
      end
      else ;
      end
      else rx_data <= 'd0;
      end

      //=============done=========//
      //功能:接受结束信号
      always@(posedge clk or negedge rst_n)begin
      if(!rst_n)
      done <= 1'b0;
      else if(bit_flag && bit_cnt == 4'd10)
      done <= 1'd1;
      else
      done <= 1'd0;
      end

      endmodule

      最后的仿真代码;

      `timescale 1ns/1ps

      module tb_uart();
      reg clk;
      reg rst_n;
      reg start;
      reg [7:0]data;

      wire rs232_tx;
      wire done;
      wire [7:0] rx_data;

      uart  t_uart(
      .clk(clk),
      .rst_n(rst_n),
      .start(start),       //????
      .data(data),        //?????

      .rs232_tx(rs232_tx),  //??????
      .done()       //??????
      );
      uart_rx t_uart_rx(
      .clk(clk),
      .rst_n(rst_n),
      .rs232(rs232_tx),  //接受端口

      .rx_data(rx_data),  //接受的数据
      .done()
      );


      initial clk = 1'b1;
      always #10 clk = ~clk;
      initial begin
      rst_n = 1'b0;
      start = 1'b0;
      data = 8'd0;

      #100;
      rst_n = 1'b1;
      #200;

      data = 8'h55;
      #20;
      start = 1'd1;
      #20;
      start = 1'b0;
      #20000;

      data = 8'h58;
      #20;
      start = 1'd1;
      #20;
      start = 1'b0;
      #20000;

      data = 8'h66;
      #20;
      start = 1'd1;
      #20;
      start = 1'b0;
      #20000;


      $stop;
      end
      endmodule























      本文由 在线网速测试 整理编辑,转载请注明出处,原文链接:https://www.wangsu123.cn/news/18526.html

          热门文章

          文章分类