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