UART协议及其Verilog实现

概述

Uart是个缩写,全称是通用异步收发传输器(Universal Asynchronous Receiver/Transmitter)。单向传输只需要单线。异步传输的意思是没有同步时钟来同步发送端和接受端的数据,所以在数据之前添加起始位,之后添加结束位,以此来判断传输过程的开始和结束。当接收端检测到开始位,即开始以特定的频率来接收输入的bit位,这个特定的频率称为波特率。发送端和接收端要在大致相同的波特率下工作,才可以保证传输的正确性(最多相差10%)。

数据包的构成

Uart协议的传输数据被整合成数据包,每个数据包包含1位起始位,5-9位的数据位(具体决定于需求等因素),1位可选的奇偶校验位和1-2位的停止位。如下图所示:

Uart数据包的构成

起始位(start bit)

数据传输线空闲的时候保持低电平,当开始传输时,拉低一个时钟周期,这就是起始位。当接受端检测到数据线由高到低的变化时便开始以约定的波特率来接收上述的数据包。

数据帧(data frame)

这是实际需要传输的数据。如果使用奇偶校验功能的话,可以传输5-8位的数据;如果不使用奇偶校验功能,则可以传输9位。一般由最低位开始传输。

奇偶校验位(parity)

用于接收端判断接收到的数据的正误。当接受端接收到数据帧后,计算其中1的个数是奇数个还是偶数个。如果奇偶校验位是0(偶校验),那么数据帧中1的个数应该是一个偶数。如果奇偶校验位是1(奇校验),那么数据帧中1的个数应该是奇数。当奇偶校验位与数据匹配时,传输没有错误。但是如果奇偶校验位是0,但1的个数是奇数或者奇偶校验位是1,个数却是偶数,则数据传输过程中发生了变化。奇偶校验只有粗略判断正误的功能,没有改正的能力。

停止位(stop bits)

高电平保持1-2个时钟周期表示1-2位停止位,即停止位为高电平。

以上参考:BASICS OF UART COMMUNICATION

波特率

波特率和比特率

比特率:每秒钟传输的二进制位数(bit),表示有效数据的传输速率,单位是b/s 、bit/s、比特/秒,读作:比特每秒。

波特率:波特率可以被理解为单位时间内传输符号的个数(传符号率),通过不同的调制方法可以在一个符号上负载多个比特信息。

比特率和波特率在数值上有如下关系:

\[ I=S \cdot \log _{2} N \]

其中I 为传信率(比特率),S 为波特率,N 为每个符号负载的信息量,而\(\log _{2} N\)以比特为单位。

以RS232为例,假设目前“波特率”为 9600, 则此RS232的比特率计算为
\[ I=S \cdot \log _{2} N=9600 \cdot \log _{2} 2=9600 b i t / s \]
常有人把RS232之N 误以为是每个“符号”(symbol)所夹带的讯息量为\(2^8\),但实际上每一个“位元”(bit)即为一个“符号”(symbol)。

计算机通信中,波特率与比特率虽在数值上相等,但是它们的意义并不相同。

以上参考:波特率

常见波特率

9600、19200 、38400 、57600 、115200、230400、460800、921600

时钟与波特率的计算

FPGA 主频如果为50M,则时钟周期就是20ns。若数据发送速率为9600bps,则一位数据需要的时间为1000000000/9600=104167ns,则FPGA 传送一位需要翻转104167/20=5208个周期才可传送一位,所以程序中需计数5208才可满足9600bps。

简单一点就是时钟频率除以波特率就是需要的计数。

Verilog模块详解

全部rtl和tb

参考链接,建议固定位宽和不需要奇偶校验,使用此博文中的简洁描述

tx_clk_gen.v

发送波特率生成模块,在tx_starttx_done两信号有效的间隙生成选择的波特率时钟信号。思路如上一节所述!

支持的波特率:9600、19200 、38400 、57600 、115200、230400、460800、921600,可由参数配置。

相应Verilog描述:

`timescale 1ns / 1ps
module tx_clk_gen
#(
    parameter   CLK_FREQUENCE   = 50_000_000,       //hz
                BAUD_RATE       = 9600              //9600、19200 、38400 、57600 、115200、230400、460800、921600
)
(
    input                   clk         ,   //system_clk
    input                   rst_n       ,   //system_reset
    input                   tx_done     ,   //once_tx_done
    input                   tx_start    ,   //once_tx_start
    output  reg             bps_clk         //baud_rate_clk
);

localparam  BPS_CNT =   CLK_FREQUENCE/BAUD_RATE-1,
            BPS_WD  =   log2(BPS_CNT);

reg [BPS_WD-1:0] count;
reg c_state;
reg n_state;
//FSM-1         1'b0:IDLE   1'b1:send_data
always @(posedge clk or negedge rst_n) begin
    if (!rst_n)
        c_state <= 1'b0;
    else
        c_state <= n_state;
end
//FSM-2
always @(*) begin
    case (c_state)
        1'b0: n_state = tx_start ? 1'b1 : 1'b0;
        
  • 14
    点赞
  • 105
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值