01 波特率是什么
从宏观理解,波特率表征了串口的 传输速度 。
从微观上,波特率是指在系统中 单位时间内传输的码元个数 。对于UART而言,码元是二进制的,都是用高低电平传输,所以波特率和比特率在数值上是相等的。例如,当波特率为115200时,实质就是UART串口每秒传输115200个bit的数据量,传输一个bit的时间等于1/115200秒。常见的UART串口波特率为300、600、1200、4800、9600、19200、34800等。
串口传输中一个bit数据的周期即传输一个bit的时间,即可以表示为:
在串口传输中,一帧数据由起始位(1bit)、数据位(典型8bit)、校验位(1bit)和停止位(1bit)组成,在通常情况下一帧数据有11bit。那么可以算出1帧数据传输所需的时间为11x1/bps。
串口通信的双方需要设置相同的波特率 ,由波特率约定数据传输的周期。决定了应该多久读取一次电平值。
02 模块接口与描述
- 26MHz功能时钟主要用于波特率的产生与计算,由外部输入。
- 接收波特率使能信号由接收数据模块中产生,UART_RX线检测到起始位后使能接收波特率。
- 发送波特率使能信号由发送数据模块中产生,需要发送数据时即可使能。
- 波特率分频系数是配置模块产生,由APB总线配置。
- 接收和发送波特率时钟根据配置由26MHz时钟产生的用接收和发送数据的信号。
03 功能时钟与波特率设计
本项目使用的功能时钟为26MHz,波特率可通过波特率分频系数BAUD_DIV进行配置。波特率分频系数BAUD_DIV与波特率之间的关系为:
为了方便计算和设计,我们将N固定为16,只配置BAUD_DIV来调整波特率,波特率可配置如下:
波特率计算公式中,分母即为一个数据周期所需要计26MHz时钟的个数。已知波特率和功能时钟频率,即可计算一个波特率周期所需的功能时钟数。公式中的乘N操作使用左移实现(默认波特率为9600)。
always@(posedge clk26m ornegedge rst26m_) begin
if(!rst26m_) begin
cnt_value <= 10'd169 < < 4;
end
elsebegin
cnt_value <= (baud_div + 1'b1) < < 4;
end
end
在产生接收数据的波特率时钟时,需要注意,接收模块是根据所产生的这个波特率时钟来进行数据接收,数据采集如果都在“ 每位数据的中间 ”,那么采样出的数据是最稳定的。
接收数据采样
所以在产生波特率时钟时,RX波特率计数器累加到一半时就应使产生接收波特率时钟。而发送数据时则不必这样,只需保证波特率正确即可。
波特率模块实现如下:
`timescale 1ns/1ps
module UART_BAUD(
// inputs
clk26m,
rst26m_,
tx_bps_en,
rx_bps_en,
baud_div,
// outputs
rx_bpsclk,
tx_bpsclk
);
input clk26m; // 26M function clock
input rst26m_; // function clk's rst_
input rx_bps_en; // baud enable signal
input tx_bps_en;
input [9:0] baud_div; // baud frequency divide factor
output rx_bpsclk; // receive bps clk
output tx_bpsclk; // send bps clk
reg [13:0] cnt_value; // bps count value
reg [13:0] cnt_baud_rx; // receive baud counter
reg [13:0] cnt_baud_tx; // send baud counter
// produce receive bpsclk
always@(posedge clk26m ornegedge rst26m_) begin
if(!rst26m_) begin
cnt_baud_rx <= 14'd0;
end
elsebegin
if(rx_bps_en) begin
if(cnt_baud_rx > cnt_value - 1'b1) begin
cnt_baud_rx <= 14'd0;
end
elsebegin
cnt_baud_rx <= cnt_baud_rx + 1'b1;
end
end
elsebegin
cnt_baud_rx <= 14'd0;
end
end
end
assign rx_bpsclk = (cnt_baud_rx == (cnt_value >>1))? 1'b1:1'b0;
// produce send bpsclk
always@(posedge clk26m ornegedge rst26m_) begin
if(!rst26m_) begin
cnt_baud_tx <= 14'd0;
end
elsebegin
if(tx_bps_en) begin
if(cnt_baud_tx > cnt_value - 1'b1) begin
cnt_baud_tx <= 14'd0;
end
elsebegin
cnt_baud_tx <= cnt_baud_tx + 1'b1;
end
end
elsebegin
cnt_baud_tx <= 14'd0;
end
end
end
assign tx_bpsclk = (cnt_baud_tx == (cnt_value >>1))? 1'b1:1'b0;
always@(posedge clk26m ornegedge rst26m_) begin
if(!rst26m_) begin
cnt_value <= 10'd169 < < 4;
end
elsebegin
cnt_value <= (baud_div + 1'b1) < < 4;
end
end
endmodule