纯手打 uart协议

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

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

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

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

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
  

  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值