前言
人類生存於世,少不了溝通。溝通使人類互相認知,傳遞信息,提升生活品質。但然單片機也需要,不然單單一個機器,無法構成一個系統,發揮更大的力量。只有單片機與外圍設備傳遞信息,互相反饋才會有一個完美的系統。串行口通信就被發明出來,下面來了解串行口通信(uart)。
幾個概念
為了能更好理解串行口通信,在介紹它之前,先來看看幾個概念,補充知識,方便深入明白uart工作原理。
通信方式
通信方式
通信方式有兩種,分別是並行通信和串行通信。
並行通信:並行是指多比特數據同時通過並行線進行傳送,這樣數據傳送速度大大提高,但並行傳送的線路長度受到限制,因為長度增加,干擾就會增加,數據也就容易出錯。
串行通信:串行通信是指 使用一條數據線,將數據一位一位地依次傳輸,每一位數據占據一個固定的時間長度。其只需要少數幾條線就可以在系統間交換信息,特別適用於計算機與計算機、計算機與外設之間的遠距離通信。
拿汽車通道來說,並行通信就是多車道,多輛車一起行駛,而串行通信就是單車道,只能一輛一輛車通過。
串行通信制式
串行通信制式
串行通信制式有單工通信,半雙工通信,雙工通信三種。
單工通信:單工通信信道是單向信道,發送端和接收端的身份是固定的,發送端只能發送信息,不能接收信息;接收端只能接收信息,不能發送信息,數據信號僅從一端傳送到另一端,即信息流是單方向的。
半雙工通信:半雙工數據傳輸指數據可以在一個信號載體的兩個方向上傳輸,但是不能同時傳輸。例如,在一個局域網上使用具有半雙工傳輸的技術,一個工作站可以在線上發送數據,然后立即在線上接收數據,這些數據來自數據剛剛傳輸的方向。像全雙工傳輸一樣,半雙工包含一個雙向線路(線路可以在兩個方向上傳遞數據)。
雙工通信:雙工通信是指在同一時刻信息可以進行雙向傳輸,和打電話一樣,說的同時也能聽,邊說邊聽。這種發射機和接收機分別在兩個不同的頻率上(兩個頻率差有一定要求)能同時進行工作的雙工機也稱為異頻雙工機。
三種通信制式很容易理解,對照上圖看,單工通信不就是單方面通信,只能發出指令或接收指令。半雙工通信就是能接收又能發送,但是不能同時進行。雙工就最厲害,可以同時發送和接收指令。
串行通信分類
串行通信有兩種,一位異步串行通信,二為同步串行通信。
異步串行通信:異步串行通信是指通信雙方以一個字符(包括特定附加位)作為數據傳輸單位且發送方傳送字符的間隔時間不一定,具有不規則數據段傳送特性的串行數據傳輸。
同步串行通信:所謂同步通信是指在約定的通信速率下,發送端和接收端的時鍾信號頻率和相位始終保持一致(同步),這就保證了通信雙方在發送和接收數據時具有完全一致的定時關系。
兩種串行通信不同就只有時間,在發送字符時,異步可以是不同時間間隔發送,但同步只能以固定的時間間隔發送。
波特率
波特率:波特率表示每秒鍾傳送的二進制位數,是衡量數據傳送速率的指標,它用單位時間內載波調制狀態改變的次數來表示。
相互通信的甲乙雙方必須具有相同的波特率,不然無法成功完成串行通信。
概述
52單片機具有一個全雙工串行通信口。一個全雙工UART(通用異步接收發送器)的串行I/O口,用於實現單片機之間或單片機與微機之間的串行通信;片內振盪器和時鍾產生電路,石英晶體和微調電容需要外接。最佳振盪頻率為6M—12M。管腳RXD( P3.0),TXD(P3.1)與串口通信有關。波特率可以設置。
內部結構
串行口內部結構邏輯圖
串行口通信與三個寄存器有關,分別是:
1. PCON寄存器
2. SCON寄存器
3. SBUF特殊功能寄存器
寄存器
PCON電源管理寄存器
電源管理寄存器
SMOD:該位與串口通信有關。
SMOD=0; 串口方式1,2,3時,波特率正常。
SMOD=1; 串口方式1,2,3時,波特率加倍。
LVDF:低電壓檢測標志位,同時也是低電壓檢測中斷請求標志位
GF1,GF0:兩個通用工作標志位,用戶可以自由使用。
PD:掉電模式設定位。
PD=0 單片機處於正常工作狀態。
PD=1 單片機進入掉電(Power Down)模式 ,可由外部中斷或硬件復位模式喚醒,進入掉電模式后,外部晶振停振,CPU、定時器、串行口全部停止工作,只有外部中斷工作。在該模式下,只有硬件復位和上電能夠喚醒單片機。
IDL:空閑模式設定位。
IDL=0 單片機處於正常工作狀態。
IDL=1 單片機進入空閑(Idle)模式,除CPU不工作外,其余仍繼續工作,在空閑模式下可由任一個中斷或硬件復位喚醒。
這個寄存器只有SMOD位與串行口通信有關。系統復位默認為SMOD=0。當為用52單片機的定時器2產生波特率時,波特率不受SMOD影響。用定時器1產生波特率時,不去設置,就默認為0,波特率正常,設置為1時,波特率加倍。
SCON串行口控制寄存器
串行口控制寄存器
SM0,SM1:共同決定串行口工作模式。
SM2:多機通信控制位。在方式0中,SM2一定要等於0。在方式1中,當SM2為1時則只有接收到有效停止位時,RI才置1。在方式2或3中,當SM2為1且接收到的第9位數據RB8為0時,RI才置1。
REN:接收允許控制位。由 軟件置位以允許接收,又由 軟件清零來禁止接收。
TB8:要發送數據的第9位。在方式2或3中,要發送的第9位數據,根據需要由軟件置1或清零軟件置1或清零。例如,可約定作為奇偶校驗位,或在多機通信中作為區別地址幀或數據幀的標志位。(很少用)
RB8:接收到的數據的第9位。在方式0中不使用RB8。在方式1中,若SM2為0,RB8為接收到的停止位。在方式2或3中,RB8為到的第9位數據。(很少用)
TI:發送中斷標志。在方式0中,第8位發送結束時,由 硬件置位。在其它方式的發送停止位前,由 硬件置位。TI置位既表示一幀信息發送結束,同時也向CPU申請中斷。可根據需要,用軟件查詢的方法獲得數據已發送完畢的信息,或用中斷的方式來發送下一個數據。TI必須用 軟件清零。
RI:接收中斷標志位。在方式0中,當接收完第8位數據后,由 硬件置位。在其它方式中,在接收到停止位的中間時刻由硬件置位(例外情況見對SM2的說明)。RI表示一幀數據接收完畢,可用查詢的方法獲知或者用中斷的方法獲知。RI也必須用 軟件清零。串行口工作模式
由於52單片機內部有一個硬件模塊,讓它自動接收數據,接收完了,通知我們一下就可以了,就不需要再手動配置TB8,RB8。只要配置好SCON,內部就自動幫弄好了。
SBUF特殊功能寄存器
特殊功能寄存器
SBUF是指串行口中的兩個緩沖寄存器,一個是發送寄存器,一個是接收寄存器,在物理結構上是完全獨立的,但地址是重疊的。它們都是字節尋址的寄存器,字節地址均為99H。只要在編寫程序時,用不同指令即可操作兩個寄存器。
比如,SBUF=A;這個是指將A的數據移入發送寄存器,然后發送寄存器再把數據發送出去。A=SBUF;則是指將接受寄存器中的數據賦值給A。
串行口方式1
方式1邏輯圖
串行口為10位通用異步接口。發送或接收一幀數據信息為10位,包括1位起始位“0”、8位數據位、1位停止位“1”。發送數據:數據從TXD端口輸出,當數據寫入發送緩沖器SBUF時,就啟動發送器發送。發送完一幀數據后,置中斷標志TI=1,申請中斷,通知CPU可以發送下一個數據了。接收數據:首先使REN=1(允許接收數據),串行口從RXD接收數據,當采樣到1至0跳變時,確認是起始位“0”,就開始接收一幀數據,當接收完一幀數據時,置中斷標志RI=1,申請中斷,通知CPU從SBUF取走接收到的數據 。
計算波特率
方式1波特率計算
溢出速率即溢出頻率,只要算出定時器每溢出一次所需要的時間T,那溢出率就是1/T。計算在沒有波特率加倍(SMOD=0)的情況下,波特率為9600bps時怎樣賦值計數器。這里說明一下,由於波特率是需要很精確的,不然通信會出錯。如果采用定時器工作模式1,采用人工重載,會有較大誤差,因為進入中斷函數也需要時間,累積時間就會出錯。所以這里運用工作模式2,8位自動重裝。計數器自動重裝不需人工干預,減少誤差。
對照上面公式,波特率不加倍,SMOD=0,工作模式2,那n=8,波特率=9600,就可以算出x=253,十六進制為fd。
編寫步驟
- 設置串行口方式
- 設置定時器工作模式
- 計數器寄存器賦值
- 中斷寄存器控制
- 啟動定時器中斷
- 發送函數
- 接收函數
范例1
#include<reg52.h>
unsigned char date; //定義變量數據中斷
bit flag; //定義變量標志
void send (); //聲明發送函數
void receive (); //聲明接收函數
void initialize (); //聲明初始化函數
main()
{
initialize(); //調用初始化函數
while(1)
{
send(); //調用發送函數
receive(); //調用接收函數
}
}
void initialize() //初始化函數
{
SCON=0X50; //0011 0000 串行口工作模式1
TMOD = 0X20; //定時器1工作模式2,8為自動重裝
TH1 = 0xFD; //設定定時初值 波特率為9600
TL1 = 0xFD; //設定定時器重裝值
TR1 = 1; //啟動定時器1
IE=0;
}
void send() //發送函數
{
if(flag==1) //證明已經接收數據
{
SBUF=date; //將接收的數據發送出去
while(!TI); //等待發送中斷
TI=0; //軟件置0
flag=0; //清零
}
}
void receive() //接收函數
{
while(!RI); //等待接收中斷
date=SBUF; //將收到的數據存進接收緩沖寄存器
RI=0; //軟件置0
flag=1; //將標志位置1
}
范例1是將接受的數據原封不動發送出去。采用查詢法,故不需要打開串口中斷,不用中斷函數。只需不斷查詢TI,RI的值,就知道數據接收發送情況。
范例2
#include<reg52.h>
unsigned char date;
bit flag;
main ()
{
SCON=0X50; //初始化
TMOD=0X20;
TH1=0XFD;
TL1=0XFD;
IE=0X90;
TR1=1;
while(1);
}
void interrupt_uart() interrupt 4 //中斷函數
{
if(RI==1) //判斷有無數據接收
{
date=SBUF; //將寄存器的值賦給變量
RI=0; //置0
flag=1; //標志位置1
}
if(flag==1) //已接收數據
{
SBUF=date; //將數據發出
while(!TI);
TI=0;
flag=0;
}
}
與范例1如出一撤,就不詳細注釋。
總結
在串口通信中,方式1是最常用的,要認真理解方式1。串行數據一位一位的已經不用處理了,52單片機已經有一個模塊處理完了。只要知道接收一個數據,產生一次接收中斷,要軟件置0.,發送一個數據會產生一次發送中斷,也要軟件置0。自行置0,處理好數據就OK。下一篇將介紹其他三種方式,歡迎關注。