01UART基礎(chǔ)知識(shí)
通用異步收發(fā)傳輸器(Universal Asynchronous Receiver/Transmitter),通常稱(chēng)作UART。它將要傳輸?shù)?a href="http://www.wenjunhu.com/soft/special/" target="_blank">資料在串行通信與并行通信之間加以轉(zhuǎn)換。作為把并行輸入信號(hào)轉(zhuǎn)成串行輸出信號(hào)的芯片,UART通常被集成于其他通訊接口的連結(jié)上。
具體實(shí)物表現(xiàn)為獨(dú)立的模塊化芯片,或作為集成于微處理器中的周邊設(shè)備。一般是RS-232C規(guī)格的,與類(lèi)似Maxim的MAX232之類(lèi)的標(biāo)準(zhǔn)信號(hào)幅度變換芯片進(jìn)行搭配,作為連接外部設(shè)備的接口。在UART上追加同步方式的序列信號(hào)變換電路的產(chǎn)品,被稱(chēng)為USART(Universal Synchronous Asynchronous Receiver Transmitter)。
1.1 早期串行通訊設(shè)備
早期的電報(bào)機(jī)器使用長(zhǎng)度可變的脈沖信號(hào)(摩斯電碼)進(jìn)行數(shù)據(jù)傳輸,后來(lái)出現(xiàn)的電傳打印機(jī)(teleprinters )使用5、6、7或8個(gè)數(shù)據(jù)位來(lái)表示各種字符編碼。隨著電傳打印機(jī)的普及,最終發(fā)展成為計(jì)算機(jī)外圍設(shè)備。
?
由于歷史的發(fā)展原因,早期在Unix終端是一個(gè)名字為ASR33的電傳打字機(jī),而電傳打字機(jī)的英文單詞為T(mén)eletype(或Teletypewritter),縮寫(xiě)為T(mén)TY。因此,終端設(shè)備也被稱(chēng)為tty設(shè)備。這就是TTY這個(gè)名稱(chēng)的來(lái)源。
1.2 早期的芯片級(jí)UART
DEC(Digital Equipment Corporation)公司的Gordon Bell 為該公司的PDP系列計(jì)算機(jī)設(shè)計(jì)了第一個(gè)UART,不過(guò)體積龐大,UART的線路占據(jù)了整個(gè)電路板;后來(lái)DEC將串行線路單元的設(shè)計(jì)濃縮為早期的UART單芯片,以方便自己使用。西部數(shù)據(jù)(Western Digital)公司在1971年左右將其開(kāi)發(fā)為第一個(gè)廣泛可用的UART單芯片 WD1402A。這是中型集成電路的早期產(chǎn)品。
DEC是美國(guó)一家計(jì)算機(jī)公司;Western Digital是美國(guó)計(jì)算機(jī)硬盤(pán)驅(qū)動(dòng)器制造商和數(shù)據(jù)存儲(chǔ)公司。
1.3 現(xiàn)代串行通訊設(shè)備
2000年開(kāi)始,大多數(shù)IBM或者相關(guān)的計(jì)算機(jī)都刪除了其外部RS232的COM端口,將其替換為帶寬性能更加出色的USB端口;對(duì)于仍然需要RS-232串行COM端口的用戶,現(xiàn)在通常使用外部USB轉(zhuǎn)UART轉(zhuǎn)換器,常見(jiàn)的有CH340,Silicon Labs 210x的驅(qū)動(dòng)程序,現(xiàn)在很多處理器和芯片都內(nèi)置了UART。
?
02UART傳輸協(xié)議
2.1 UART協(xié)議
在串口通信中,數(shù)據(jù)在1位寬的單條線路上進(jìn)行傳輸,一個(gè)字節(jié)的數(shù)據(jù)要分為8次,由低位到高位按順序一位一位的進(jìn)行傳送,這個(gè)過(guò)程稱(chēng)為數(shù)據(jù)的"串行化(serialized)"過(guò)程。由于串口通信是一種異步通信協(xié)議,并沒(méi)有時(shí)鐘信號(hào)隨著數(shù)據(jù)一起傳輸,而且空閑狀態(tài)(沒(méi)有數(shù)據(jù)傳輸?shù)臓顟B(tài))的時(shí)候,串行傳輸線為高電平1,所以發(fā)送方發(fā)送一個(gè)字節(jié)數(shù)據(jù)之前會(huì)先發(fā)送一個(gè)低電平0,接收方收到這個(gè)低電平0以后就知道有數(shù)據(jù)要來(lái)了,準(zhǔn)備開(kāi)始接收數(shù)據(jù)從而實(shí)現(xiàn)一次通信。串口通信的時(shí)序如下圖所示:
串口通信的規(guī)范如下:
1. 空閑狀態(tài)(沒(méi)有數(shù)據(jù)傳輸?shù)臓顟B(tài))下,串行傳輸線上為高電平1;
2. 發(fā)送方發(fā)送低電平0表示數(shù)據(jù)傳輸開(kāi)始,這個(gè)低電平表示傳輸?shù)钠鹗嘉唬?/p>
3. 8-bit的數(shù)據(jù)位(1 Byte)是從最低位開(kāi)始發(fā)送,最高位最后發(fā)送;
4. 數(shù)據(jù)位的最高位發(fā)送完畢以后的下一位是奇偶校驗(yàn)位,這一位可以省略不要,同時(shí),當(dāng)不發(fā)送奇偶校驗(yàn)位的時(shí)候接收方也相應(yīng)的不接收校驗(yàn)位;
5. 最后一位是停止位,用高電平1表示停止位。
下面以發(fā)送字節(jié)0x55為例來(lái)說(shuō)明整個(gè)的發(fā)送過(guò)程:
先把0x55轉(zhuǎn)化成二進(jìn)制為:01010101。顯然0x55的最低位bit 0是1,次低位bit 1是0,……..,最高位bit 7是0,由于串口是從最低位開(kāi)始發(fā)送一個(gè)字節(jié),所以0x55各個(gè)位的發(fā)送順序是1-0-1-0-1-0-1-0,波形如下圖所示:
下面在給出一個(gè)波形,根據(jù)上面的規(guī)則也可以很容易判斷這是發(fā)送字節(jié)0x13的波形:
2.1.1 起始位
UART數(shù)據(jù)傳輸時(shí)在不傳輸數(shù)據(jù)時(shí)保持在高電平,當(dāng)開(kāi)始傳輸數(shù)據(jù)時(shí),先發(fā)出1bit位寬的低電平,表示數(shù)據(jù)開(kāi)始傳輸,即為起始位。
2.1.2 數(shù)據(jù)位
數(shù)據(jù)位包含正在傳輸?shù)膶?shí)際數(shù)據(jù),位寬可以為4bit到10bit,大多數(shù)情況下,數(shù)據(jù)首先從低有效位發(fā)送。
2.1.3 校驗(yàn)位
串口通信中的一種交錯(cuò)方式,通常有偶校驗(yàn)、奇校驗(yàn)、高校驗(yàn)和低校驗(yàn)四種檢錯(cuò)方式,沒(méi)有校驗(yàn)位也是可以的。
偶校驗(yàn):數(shù)據(jù)位加上校驗(yàn)位后,“1”的位數(shù)應(yīng)為偶數(shù);
奇校驗(yàn):數(shù)據(jù)位加上校驗(yàn)位后,“1”的位數(shù)應(yīng)為奇數(shù);
2.1.4 停止位
在數(shù)據(jù)發(fā)送結(jié)束后發(fā)送一位高電平用于停止標(biāo)識(shí)。
由于數(shù)據(jù)是在傳輸線上定時(shí)的,并且每一個(gè)設(shè)備有其自己的時(shí)鐘,很可能在通信中兩臺(tái)設(shè)備間出現(xiàn)了小小的不同步。因此停止位不僅僅是表示傳輸?shù)慕Y(jié)束,并且提供計(jì)算機(jī)校正時(shí)鐘同步的機(jī)會(huì)。適用于停止位的位數(shù)越多,不同時(shí)鐘同步的容錯(cuò)性越好,但是數(shù)據(jù)傳輸率同時(shí)也越慢。
3.1.5 波特率
串口數(shù)據(jù)的傳輸速度用波特率(bit/s)進(jìn)行衡量,常見(jiàn)的波特率有:9600、19200、38400、57600、115200。假設(shè)UART配置為1bit起始位,8bit數(shù)據(jù)位,沒(méi)有校驗(yàn)位,1bit停止位,那么9600bit/s的波特率可得出每一位數(shù)據(jù)的時(shí)間寬度為:T=1/9600*10=1.04ms,即每個(gè)字節(jié)(10bit數(shù)據(jù))傳輸需要1.04ms。同理可得各個(gè)波特率下數(shù)據(jù)位傳輸時(shí)間寬度。
2.2 UART傳輸過(guò)程
1. 發(fā)送端數(shù)據(jù)總線將數(shù)據(jù)包并行傳輸給發(fā)送端UART;
2. 發(fā)送端UART將起始位、奇偶校驗(yàn)位和停止位添加到數(shù)據(jù)包中;
3. 接收端UART解析數(shù)據(jù)包數(shù)據(jù);
4. 接收端UART將所解析的數(shù)據(jù)傳輸給接收端數(shù)據(jù)總線。
03UART代碼實(shí)現(xiàn)
3.1 UART目標(biāo)實(shí)現(xiàn)功能
設(shè)計(jì)一個(gè)UART發(fā)送模塊和接收模塊,具體要求如下:
1. 設(shè)計(jì)一個(gè)UART發(fā)送模塊,該模塊接收一個(gè)8位輸入數(shù)據(jù)并采用UART協(xié)議發(fā)送,UART 采用10位傳輸協(xié)議,即一位起始位,8位數(shù)據(jù)位,一位終止位。發(fā)送數(shù)據(jù)時(shí)先發(fā)低位數(shù)據(jù),最后發(fā)高位數(shù)據(jù)。要求波特率為1K。模塊的定義如下:
module uart_tx (?
clk_40k,? ????//clock signal, 40kHz
rst_n, ????????//reset signal, active low
din,????????//the input data which will be sent by the UART module, 8 bit width
send_start,//the start enable signal, active high, the width is one clock period
bit_out????????//the serial output data?
);?
2. 設(shè)計(jì)一個(gè)UART接收模塊,模塊的定義如下:
module uart_rx (?
clk_40k,? ?//clock signal, 40kHz
rst_n,? ? ? ?//reset signal, active low
bit_in,????//the input serial bit,
dout_vld,//the output valid signal, active high,the dout is valid when this signal is high.
dout??????//received data, 8 bit width?
);?
3. 設(shè)計(jì)一個(gè)testbench,對(duì)發(fā)送模塊和接收模塊進(jìn)行測(cè)試,測(cè)試過(guò)程如下,testbench產(chǎn)生一個(gè)隨機(jī)數(shù),然后啟動(dòng)uart_tx模塊發(fā)送至uart_rx模塊,當(dāng)uart_rx模塊接收到有效數(shù)據(jù)后,自動(dòng)判斷接收的數(shù)據(jù)是否正確。
3.2 Verilog代碼
1. 發(fā)送模塊 (uart_tx):
module uart_tx (?
clk_40k,//clock signal, 40kHz
rst_n,?//reset signal, active low
din,//the input data which will be sent by the UART module, 8 bit width
send_start,//the start enable signal, active high, the width is one clock period
bit_out//the serial output data?
);?
input [7:0] din;
input clk_40k;
input rst_n;
input send_start;
output bit_out;
reg flag;
reg tx_flag;
reg [6:0] cnt;
reg [5:0] tx_cnt;
reg [9:0] din_temp;
//flag: 發(fā)送過(guò)程flag始終拉高
always @ (posedge clk_40k)
begin
if(~rst_n)
????flag <= 1'b0;
else if(send_start == 1'b1)
????flag <= 1'b1;
else if(tx_flag == 1'b1)
????flag <= 1'b0;
end
//tx_flag: 發(fā)送結(jié)束tx_flag拉高
always @ (posedge clk_40k)
begin
if(~rst_n)
????tx_flag <= 1'b0;
else if(flag == 1'b1 && din_temp[0] == 1'b0)
????tx_flag <= 1'b1;
else if(tx_cnt == 7'd10)
????tx_flag <= 1'b0;
end
//cnt: 發(fā)送數(shù)據(jù)計(jì)數(shù),clk_40k分頻至1k波特率對(duì)傳輸數(shù)據(jù)進(jìn)行計(jì)數(shù)
always @ (posedge clk_40k)
begin
if(~rst_n)
????cnt <= 7'b0;
else if(tx_flag == 1'b1 && cnt != 7'd39)
????cnt <= cnt + 1'b1;
else?
????cnt <= 7'b0;
end
always @ (posedge clk_40k)
begin
if(~rst_n)
????tx_cnt <= 6'b0;
else if(tx_flag == 1'b1 && cnt == 7'd39)
????tx_cnt <= tx_cnt + 1'b1;
else if(tx_flag == 1'b0)
????tx_cnt <= 6'b0;
end
//din_temp:?8bit數(shù)據(jù)移位操作,串行輸出
always @ (posedge clk_40k)
begin
if(~rst_n)
????din_temp <= 10'b1111111111;
else if(flag == 1'b1 || send_start == 1'b1)
????din_temp <= {1'b1,din,1'b0};
else if(tx_flag == 1'b1 && cnt == 7'd39)
????din_temp <= {1'b1,din_temp[9:1]};
end
assign bit_out = din_temp[0];
endmodule
2. 接收模塊 (uart_rx):
module uart_rx (?
clk_40k,? ?//clock signal, 40kHz
rst_n,? ? ? ?//reset signal, active low
bit_in,????//the input serial bit,
dout_vld,//the output valid signal, active high,the dout is valid when this signal is high.
dout??????//received data, 8 bit width?
);?
input bit_in;
input clk_40k;
input rst_n;
output reg dout_vld;
output reg [7:0] dout;
reg rx_flag;
reg [6:0] cnt;
reg [5:0] rx_cnt;
reg [7:0] dout_temp;
//rx_flag:?接收過(guò)程rx_flag始終拉高
always @ (posedge clk_40k)
begin
if(~rst_n)
????rx_flag <= 1'b0;
else if(bit_in == 1'b0)
????rx_flag <= 1'b1;
else if(rx_cnt == 6'd9)
????rx_flag <= 1'b0;
end
//cnt: 接收數(shù)據(jù)計(jì)數(shù),clk_40k分頻至1k波特率對(duì)接收數(shù)據(jù)進(jìn)行計(jì)數(shù)
always @ (posedge clk_40k)
begin
if(~rst_n)
????cnt <= 7'b0;
else if(rx_flag == 1'b1 && cnt != 7'd39)
????cnt <= cnt + 1'b1;
else if(rx_flag == 1'b0 || cnt == 7'd39)
????cnt <= 7'b0;
end
always @ (posedge clk_40k)
begin
if(~rst_n)
????rx_cnt <= 6'b0;
else if(rx_flag == 1'b1 && cnt == 7'd39)
????rx_cnt <= rx_cnt + 1'b1;
else if(rx_flag == 1'b0)
????rx_cnt <= 6'b0;
end
//dout_temp:?將串行接收數(shù)據(jù)轉(zhuǎn)換還原為8bit數(shù)據(jù)
always @ (posedge clk_40k)
begin
if(~rst_n)
????dout_temp <= 8'b0;
else if(rx_flag == 1'b1 && cnt == 7'd39)
begin
????dout_temp[7] <= bit_in;
????dout_temp[6:0] <= dout_temp[7:1];
end
end
//dout_vld: 傳輸完成標(biāo)識(shí),8bit數(shù)據(jù)傳輸結(jié)束拉高
always @ (posedge clk_40k)
begin
if(~rst_n)
????dout_vld <= 1'b0;
else if(rx_cnt == 6'd9 && cnt == 7'b0)
begin
????dout <= dout_temp;
????dout_vld <= 1'b1;
end
else?
????dout_vld <= 1'b0;
end
endmodule
3. Testbench(tb):
`timescale 1us/1us
module tb();
reg clk_40k;
reg rst_n;
reg [7:0] din;
reg send_start;
wire bit_out;
wire bit_in;
wire dout_vld;
wire [7:0] dout;
assign bit_in = bit_out;
uart_tx i_uart_tx(
.clk_40k? ? ? ? ? (clk_40k? ?),
.rst_n? ? ? ? ? ? ? (rst_n? ? ?),
.din? ? ? ? ? ? ? ? ?(din? ? ? ?),
.send_start? ? ?(send_start),
.bit_out? ? ? ? ? ?(bit_out? ?)
);
uart_rx i_uart_rx(
.clk_40k? ? ? ? ? (clk_40k? ?),
.rst_n? ? ? ? ? ? ? (rst_n? ? ?),
.bit_in? ? ? ? ? ? ?(bit_in? ? ? ?),
.dout_vld? ? ? ? (dout_vld? ? ?),
.dout? ? ? ? ? ? ? ?(dout? ? ??)
);
initial?
begin
????rst_n = 1'b0;
????#10
????rst_n = 1'b1;
end
initial
begin
????clk_40k = 1'b0;
????forever
????#1
????clk_40k = ~clk_40k;
end
initial?
begin
????send_start = 1'b0;
????din = 8'd0;
????forever
????begin
????????#1000
????????din = $random()%256;
????????send_start = 1'b1;
????????#2
????????send_start = 1'b0;
????end
end
endmodule
4. 仿真結(jié)果 :
按照testbench對(duì)UART收發(fā)端進(jìn)行仿真,仿真結(jié)果如圖:
1. 系統(tǒng)時(shí)鐘和傳輸速率通常不一致,clk_40k為高頻系統(tǒng)時(shí)鐘,利用計(jì)數(shù)器分頻實(shí)現(xiàn)1k波特率;
2. 復(fù)位信號(hào)rst_n低電平有效,正常傳輸時(shí)始終處于高電平。
3. 開(kāi)始傳輸時(shí)send_start信號(hào)拉高,傳輸結(jié)束時(shí)dout_vld信號(hào)拉高;
4. 輸入數(shù)據(jù)din在傳輸結(jié)束后在輸出數(shù)據(jù)dout體現(xiàn)出來(lái),傳輸時(shí)延為1個(gè)數(shù)據(jù)長(zhǎng)度。
04UART的優(yōu)缺點(diǎn)
4.1 UART協(xié)議優(yōu)點(diǎn)
1. 通信只需要兩條數(shù)據(jù)線;
2. 無(wú)需時(shí)鐘信號(hào);
3. 有奇偶校驗(yàn)位,方便通信的差錯(cuò)檢查;
4. 只需要接收端和發(fā)送端設(shè)置好數(shù)據(jù)包結(jié)構(gòu),即可穩(wěn)定通信。
4.2 UART協(xié)議缺點(diǎn)
1. 數(shù)據(jù)幀最大支持9位數(shù)據(jù);
2. 不支持多主機(jī)或多從機(jī)的主從系統(tǒng)。
? 審核編輯:湯梓紅
評(píng)論
查看更多