10.1 串口通信基礎知識
前面講解的都是單片機自身的一些功能,并未涉及單片機與其它單片機或者計算機之間通信。那么單片機與其它設備之間又是怎么通信的呢?通常來講有兩種通信方式,即并行通信與串行通信。
兩個單片機之間的并口通信,以 8 位為例,直接將單片機 1 的 8 位 I/O 口 P0 與單片機 2 的 P1 相連接,在同步時鐘信號的作用進行數據的傳輸。以單片機 1 向單片機 2 傳輸數據 0x7B 為例,單片機 1 只需將數據 0x7B 輸出到 P0 口上,單片機 2 在同步時鐘信號的步調下將 0x7B 直接讀取。此時同步時鐘信號的周期長短將決定數據傳輸的速度,周期越短,速度越快。并口通信的最大優點為速度快,一個時鐘周期內可以傳播一個字節,甚至多個字節,缺點為需要占用大量的 I/O 口資源,對于大多數資源緊張的應用場合來說,這種方法是不可取的,而串行通信有效的解決了資源問題。
STC89C52 系列單片機配置了串行方式通信接口,對應單片機的管腳 P3.0/RxD,串行數據接收引腳、P3.1/TxD,串行數據發送引腳。如上圖所示,單片機 1 的串行發送引腳 TxD 與單片機 2 的串行數據接收引腳 RxD 相連接,形成了一條單片機 1 發送、單片機 2 接收的數據通信鏈路。單片機 2 的 TxD 與單片機 1 的 RxD 連接,形成了一條單片機 2 發送、單片機 1 接收數據的通信鏈路。單片機 1 的 GND 與單片機 2 的 GND 相連接確保了兩個單片機在同一電源基準下工作。接下來講解單片機串行通信的工作原理。
同樣以單片機 1 向單片機 2 發送數據 0x7B 為例,二進制表示為 01111011,單片機依次 01111011 的最低位‘1’到最高位‘0’依次發送出去。發送 1 的時候為將 TxD 拉高’一段時間’,發送 0 的時候為將 TxD 拉低‘一段時間’,即發送數據的時候后,每發送一位都持續‘一段時間’,發送 0x7B 的從低位到高位的順序為:1->1->0->1->1->1->1->0。“一段時間”的長短決定了單片機的串口傳輸的速度,時間越短,傳輸速度越快。那么在同樣位傳輸速率的情況下,并行通信速度為串行通信的 8 倍,顯然串行通信以犧牲速度的方式換取了更多的資源,這就是時間換資源的概念。
10.2 波特率概念
上面講解的“一段時間”實際上為單片機串口傳輸 1 位數據所耗費的時間,在應用中我們常常把 1 秒傳輸多少位來衡量單片機串口傳輸速率,這就是波特率的概念。例如通信雙方約定波特率為:9600bps,即每秒傳輸 9600 位(bps:bit per second)。波特率在單片串口通信中為非常重要的參數指標,通信雙方只有在約定共同的波特率下才能保證數據的正確傳輸。
在單片機串口通信中,并沒有同步時鐘信號來統一數據發送和接收,通過雙方約定的波特率來保證數據的通信。以單片機 1 向單片機 2 發送數據為例,假設雙方設定的波特率為 9600bps,那么單片機 2 是怎么知道單片機 1 什么時候給它發送數據,又是什么時候結束的呢?
這里我們引入兩個重要的概念,起始位和停止位。單片機在沒有進行串口通信的情況下,數據發送引腳 TxD 為高電平,當單片機 1 需要發送數據時,首先通過 TXD 發送一位“0”,即把單片機 TxD 從高電平拉低,當單片機 2 檢測到數據接收引腳 RxD 的低電平后便開始接收數據了。那么這里單片機 1 發送的第一位“0”稱為起止位。緊接著單片機 1 將 8 位數據依次發送出去,當 8 位數據發送完后,單片機發送一位“1”,單片機 2 接收完 8 位數據后,又接收到一位“1”,便知道停止發送數據了,至此便完成了一次數據的傳輸。這里單片機 1 發送的最后一位“1”稱之為停止位。根據上面的步驟,完成一次數據的傳輸,包括起始位、8 位數據、停止位,總共 10 位數據,如下圖所示。這里的 10 位數據稱之為一幀數據。
10.3 單片機串口通信
下面講解一下單片機串口的工作原理。STC89C52系列單片機串口內部模塊有兩個獨立的串行口緩沖寄存器(SBUF),兩個寄存器均為8位,一個為發送SBUF,只能往里寫數據、另一個為接收SBUF、只能讀取數據。當單片機要通過串口往外發送數據時,只需要將待發送的數據寫入發送SBUF中,通過TxD引腳將數據發送出去。當一幀數據發送完成后,內部硬件自動置位TI,即TI=1,請求中斷處理。前面講過串口中斷是單片機中斷源的一種,產生中斷后,程序進入串口中斷函數。同樣,當單片機接收到一幀數據后,內部硬件自動置位RI,即RI=1,請求串口中斷處理,進入串口中斷函數。讀取接收SBUF可獲得通過串口接收到的數據。
在單片機內部編程中兩個寄存器共用 SBUF 這個名字,那么怎么區分是對發送還是接收 SBUF 進行操作呢?由于這兩個寄存器一個只能讀、另一個只能寫。當程序中往 SBUF 中寫入數據時,則代表操作發送 SBUF,當程序中讀取 SBUF 的數據時,則代表操作接收 SBUF。
通過上面的介紹,無論是接收到一幀數據,還是發送完一幀數據,程序都會產生串口中斷,那么在串口中斷程序中是怎么區分來的是接收中斷還是發送中斷呢?在單片機串口中斷程序開始的地方通過查詢中斷標志位 TI、RI 哪個為 1 來判斷串口中斷的類型。
10.4 串口通信控制寄存器
和單片機的其它功能的實現一樣,通過配置相應的特殊功能寄存器來實現串口通信的功能。與 STC89C52 系列單片機串口通信相關的寄存器如下表所示:
熟練掌握上述特殊功能寄存器的應用便能掌握 STC89C52 系列單片機的串口功能應用。
10.4.1 串行口控制寄存器 SCON 和 PCON
STC89C52 系列單片機共設有兩個控制寄存器:串行口控制寄存器 SCON 和波特率選擇特殊功能寄存器 PCON。SCON 用于設置串口的工作方式和某些控制功能,寄存器格式如下表所示:
其中,SM0、SM1 共同組合確定串口的工作方式:
如上所示,單片機共有 4 種工作方式,各工作方式的主要區別為數據的位數以及波特率的不同。方式 0、1 均為 8 位數據模式,方式 2,3 為 9 位數據模式。方式 0,2 為固定波特率模式,方式 1,3 為波特率可變模式。根據應用場合的不同可以選擇相應的工作模式。方式 1,3 最為常用。
SM2:為方式 2 或方式 3 多機通信控制位。
REN:允許/禁止串行接收控制位。有軟件置位,當 REN=1 時,允許接收 RxD 引腳數據,當 REN=0 時,禁止接收串行數據。
TB8:在方式 2 或方式 3,它為要發送的第 9 位數據,按需要進行置位或清零。例如可作為數據的校驗位。
RB8:在方式 2 或方式 3,是接收到的第 9 位數據。
TI:發送中斷請求標志位。在發送完數據后,由內部硬件自動置位,即 TI=1,向主機請求中斷,響應中斷后必須用軟件復位,即 TI=0。
RI:接收中斷請求標志位。在發送完數據后,由內部硬件自動置位,即 RI=1,向主機請求中斷,響應中斷后必須用軟件復位,即 RI=0。
在中斷請求 TI 或 RI 響應完串口中斷函數后,必須由軟件進行復位,否則將程序將多次進入中斷函數。
PCON 為串口波特率選擇特殊功能寄存器,格式如下:
SMOD:波特率選擇位。當軟件置位 SMOD,即 SMOD=1,則使串口工作方式 1,2,3 的波特率加倍,當軟件清零 SMOD,即 SMOD=0,波特率不加倍。
中斷允許寄存器 IE 的 ES 位為串行口中斷允許位,ES=1,允許串行口中斷,ES=0,屏蔽串行口中斷。
根據上面介紹,我們大致可分析出單片機在進行通信之前要對上述寄存器進行設置。通過設置寄存器 SCON 選擇串口工作方式,允許串口接收數據。設置 PCON 寄存器是否波特率加倍,設置中斷控制寄存器 IE 允許串口中斷。
10.4.2 波特率的計算
由表 10-4 所示,STC89C52 系列單片機工作在方式 1,3 時,波特率不僅與 SMOD 值有關,還與定時器 1 的溢出率有關。
方式 1,3 波特率 =2SMOD/32x(定時器 1 的溢出率)
- 當單片機工作在 12T 模式下,定時器 1 的溢出率 =SYSclk/12/(256-TH1)
- 當單片機共工作在 6T 模式下,定時器 1 的溢出率 =SYSclk/6/(256-TH1)
其中,SYSclk 為系統時鐘頻率,在 RY-51 單片機系統時鐘為晶振時鐘頻率 11.0592MHz。
其中,TH1 為定時器工作在模式 2 的初始值,當定時器工作在模式 2 時為 8 位自動重裝模式,當定時器產生溢出時,系統會自動把 TL1 的值自動重載到 TH1 中開始重新定時,因此,在單片機編程過程中只需在初始化時將初始值同時賦值給 TH1,TL1 保證波特率正常的產生。
由上面公式計算可得,當單片機工作在 12T 模式下,定時器 1 初始值:
TH1 =TL1=256- SYSclk x2SMOD/32 /12/波特率
當單片機工作在 6T 模式下,定時器 1 初始值:
TH1 =TL1=256- SYSclk x2SMOD/32 /6/波特率
10.4.3 串口轉 USB
單片機與單片之間通可以采用串口直接相連的方式進行,而計算機一般并沒有配置與單片機接口一致的的串行通信接口,但一般計算機都配備了 USB 接口。在我們前面經常使用到的通過 USB 將程序下載到單片機,實際上是在計算機 USB 與單片機之間增加了一個串口轉 USB 模塊。在 RY-51 單片機開發板是配置了串口轉 USB 芯片 CH340G,硬件原理圖如下所示:
如圖所示,USB+、USB-分別連接到計算機 USB 接口的數據正負端,USB_RX、USB_TX 分別連接到單片機的 P3.0(RxD)、P3.1(TxD)引腳。在計算機安裝好串口轉 USB 驅動后,便可實現計算機與單片機之間的通信。我們經常使用串口調試助手來實現單片機與計算機專家的通信,串口調試助手軟件主界面如下圖所示:
如上圖所示,串口調試助手界面主要包含三大塊,首先為通信方式選擇區,根據通信雙方的約定選擇合適的參數,數據發送區,將數據輸入到這個區域,點擊發送可將數據發送到單片機,接收數據顯示區,顧名思義計算機接收到單片機發來的數據將顯示到該區域。
10.5 串口功能應用
前面介紹了單片機串口工作原理,這節我們結合上面內容舉例說明串口的實際應用。程序實現的功能為:首先由計算機通過串口調試助手往單片機發送一個數據,當單片機接收到數據后翻轉 led0 小燈,并將接收到的數據加 1 發送給計算機,發送完數據后翻轉 led1。串口應用程序編寫順序如下:
- 配置串口工作方式 1,并允許接收串口數據
- 初始化 SMOD
- 配置定時器位工作模式 2,8 位自動重裝模式
- 初始化 TH1,TL1
- 啟動定時器,并禁止定時器中斷
- 允許串口中斷,允許總中斷
- 編寫串口中斷程序
串口應用程序代碼如下:
/*----------------------------------------------------
** 串口應用程序
** 串口工作方式1,定時器1工作模式2
** 將接收到的數據加1發送回去,收到數據時翻轉led0
** 發送完數據時翻轉led1
**
----------------------------------------------------*/
#include< reg52.h >
#define uchar unsigned char
#define uint unsigned int
#define FOSC 11059200 //單片機晶振頻率
#define BAUD 9600 //波特率設置為9600
sbit led0 = P1^0; //led0位聲明
sbit led1 = P1^1; //led1位聲明
void main()
{
SCON = 0x50;//串口配置為工作方式1
PCON = 0; //波特率不加倍
TMOD = 0x20;//設置定時器1為8位自動重裝模式
TH1=TL1= 256- FOSC/32/12/BAUD;//定時器1賦初始值
ET1 = 0;//禁止定時器1中斷
TR1 = 1;//啟動定時器1
ES = 1;//允許串口中斷
EA = 1;//開總中斷
while(1);
}
//串口中斷函數
void Uart_r(void) interrupt 4
{
if(RI)
{
RI = 0; //清零接收中斷
SBUF = SBUF+1; //讀取接收到的數據加1并發送出去
led0 = ~led0; //翻轉led0
}
if(TI)
{
TI = 0; //清零發送中斷
led1 = ~led1; //翻轉led1
}
}
將上述代碼編譯后,下載到開發板進行測試,打開串口調試助手軟件,設置后下圖中紅框中參數,點擊打開串口,如果打開串口成功,軟件左上角紅色指示燈燈會點亮。
在數據發送區輸入 16 進制數“EF”,點擊“手動發送”按鈕將數據“EF”發送給單片機,此時觀察到串口調試助手數據接受區接收到 “F0”,接收到的值正好為發送的數值加 1,與我們預期的結果相同。同時觀察 RY-51 開發 led0,led1 小燈也發生了翻轉。
上面的程序只是發送單個字節的程序,下面舉例說明字符串的發送方法。功能為當 RY-51 開發板上電后向計算機發送指定的字符串。為了程序的可讀性,我們將定時器的初始化放到初始化函數 Uart_int()。代碼如下所示:
/*----------------------------------------------------
** 串口應用程序
** 串口工作方式1,定時器1工作模式2
** 將接收到的數據加1發送回去,收到數據時翻轉led0
** 發送完數據時翻轉led1
** 上電后向單片機發送指定字符串
**
----------------------------------------------------*/
#include< reg52.h >
#define uchar unsigned char
#define uint unsigned int
#define FOSC 11059200 //單片機晶振頻率
#define BAUD 9600 //波特率設置為9600
sbit led0 = P1^0; //led0位聲明
sbit led1 = P1^1; //led1位聲明
sbit dir485 = P3^7;
uchar busy = 0;//發送完一幀數據標志位
void Uart_init(void);//串口初始化函數聲明
void Send_String(char *s);//字符串發送函聲明
void main()
{
Uart_init(); // 串口初始化
EA = 1; //開總中斷
Send_String("RY-51 STC89C52 Uart test!n"); //發送字符串
while(1);
}
//串口中斷函數
void Uart_r(void) interrupt 4
{
if(RI)
{
RI = 0; //清零接收中斷
dir485=1;
SBUF = SBUF+1; //讀取接收到的數據加1并發送出去
// led0 = ~led0; //翻轉led0
}
if(TI)
{ dir485=0;
TI = 0; //清零發送中斷
led1 = ~led1; //翻轉led1
busy = 0; //發送完數據,清除發送完標志位
}
}
//串口初始化函數
void Uart_init(void)
{
SCON = 0x50;//串口配置為工作方式1
PCON = 0; //波特率不加倍
TMOD = 0x20;//設置定時器1為8位自動重裝模式
TH1=TL1= 256- FOSC/32/12/BAUD;//定時器1賦初始值
ET1 = 0;//禁止定時器1中斷
TR1 = 1;//啟動定時器1
ES = 1;//允許串口中斷
}
//字符串發送函
void Send_String(char *s)
{
while(*s) //檢查字符串是否到了結尾
{
while(busy); //等待上一幀數據發送完畢
busy = 1;
dir485=1;
SBUF = *s++; //發送當前字符,并將字符指針移到下一個字符
}
dir485=0;
}
將程序編譯后,下載到 RY-51 開發板,設置后串口調試助手,并不選中“十六進制顯示”,給開發板重新加電,收到的指定字符串如下圖所示:
10.6 本章小結
本章介紹了51單片機串口通信的基本原理。
-
單片機
+關注
關注
6032文章
44525瀏覽量
633260 -
定時器
+關注
關注
23文章
3241瀏覽量
114516 -
串行通信
+關注
關注
4文章
569瀏覽量
35299 -
串口通信
+關注
關注
34文章
1620瀏覽量
55428 -
并行通信
+關注
關注
1文章
31瀏覽量
10814
發布評論請先 登錄
相關推薦
評論