01 波特率是什么
從宏觀理解,波特率表征了串口的 傳輸速度 。
從微觀上,波特率是指在系統(tǒng)中 單位時間內(nèi)傳輸?shù)拇a元個數(shù) 。對于UART而言,碼元是二進制的,都是用高低電平傳輸,所以波特率和比特率在數(shù)值上是相等的。例如,當波特率為115200時,實質(zhì)就是UART串口每秒傳輸115200個bit的數(shù)據(jù)量,傳輸一個bit的時間等于1/115200秒。常見的UART串口波特率為300、600、1200、4800、9600、19200、34800等。
串口傳輸中一個bit數(shù)據(jù)的周期即傳輸一個bit的時間,即可以表示為:
在串口傳輸中,一幀數(shù)據(jù)由起始位(1bit)、數(shù)據(jù)位(典型8bit)、校驗位(1bit)和停止位(1bit)組成,在通常情況下一幀數(shù)據(jù)有11bit。那么可以算出1幀數(shù)據(jù)傳輸所需的時間為11x1/bps。
串口通信的雙方需要設(shè)置相同的波特率 ,由波特率約定數(shù)據(jù)傳輸?shù)闹芷?。決定了應(yīng)該多久讀取一次電平值。
02 模塊接口與描述
- 26MHz功能時鐘主要用于波特率的產(chǎn)生與計算,由外部輸入。
- 接收波特率使能信號由接收數(shù)據(jù)模塊中產(chǎn)生,UART_RX線檢測到起始位后使能接收波特率。
- 發(fā)送波特率使能信號由發(fā)送數(shù)據(jù)模塊中產(chǎn)生,需要發(fā)送數(shù)據(jù)時即可使能。
- 波特率分頻系數(shù)是配置模塊產(chǎn)生,由APB總線配置。
- 接收和發(fā)送波特率時鐘根據(jù)配置由26MHz時鐘產(chǎn)生的用接收和發(fā)送數(shù)據(jù)的信號。
03 功能時鐘與波特率設(shè)計
本項目使用的功能時鐘為26MHz,波特率可通過波特率分頻系數(shù)BAUD_DIV進行配置。波特率分頻系數(shù)BAUD_DIV與波特率之間的關(guān)系為:
為了方便計算和設(shè)計,我們將N固定為16,只配置BAUD_DIV來調(diào)整波特率,波特率可配置如下:
波特率計算公式中,分母即為一個數(shù)據(jù)周期所需要計26MHz時鐘的個數(shù)。已知波特率和功能時鐘頻率,即可計算一個波特率周期所需的功能時鐘數(shù)。公式中的乘N操作使用左移實現(xià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
在產(chǎn)生接收數(shù)據(jù)的波特率時鐘時,需要注意,接收模塊是根據(jù)所產(chǎn)生的這個波特率時鐘來進行數(shù)據(jù)接收,數(shù)據(jù)采集如果都在“ 每位數(shù)據(jù)的中間 ”,那么采樣出的數(shù)據(jù)是最穩(wěn)定的。
接收數(shù)據(jù)采樣
所以在產(chǎn)生波特率時鐘時,RX波特率計數(shù)器累加到一半時就應(yīng)使產(chǎn)生接收波特率時鐘。而發(fā)送數(shù)據(jù)時則不必這樣,只需保證波特率正確即可。
波特率模塊實現(xiàn)如下:
`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