UART串口通信浅谈之(一)--基础概述
通信按照傳統的理解就是信息的傳輸與交換。UART(Universal Asynchronous Receiver/Transmitter,即通用異步收發器)串行通信是單片機最常用的一種通信技術,通常用于單片機和電腦之間以及單片機和單片機之間的通信。
以下我們以STC98C52單片機為例子,簡單講述串行通信。
1.1?串行通信的初步認識
通信按照基本類型可以分為并行通信和串行通信。并行通信時數據的各個位同時傳送,可以實現字節為單位通信,但是因為通信線多占用資源多,成本高。比如使用STC89C52的P0口設置為P0 = 0xfe;一次給P0的8個IO口分別賦值,同時進行信號輸出,類似于有8個車道同時可以過去8輛車一樣,這種形式就是并行的,我們習慣上還稱P0、P1、P2和P3為51單片機的4組并行總線。
而串行通信,就如同一條車道,一次只能一輛車過去,如果一個0xfe這樣一個字節的數據要傳輸過去的話,假如低位在前高位在后,那發送方式就是0-1-1-1-1-1-1-1-1,一位一位的發送出去的,要發送8次才能發送完一個字節。
在我們的STC89C52上,有兩個引腳,是專門用來做UART串口通信的,一個是P3.0一個是P3.1,還分別有另外的名字叫做RXD和TXD,這兩個引腳是專門用來進行UART通信的,如果我們兩個單片機進行UART串口通信的話,那基本的演示圖如圖1-1所示。
圖1-1?單片機之間UART通信示意圖
圖中,GND表示單片機系統電源的參考地,TXD是串行發送引腳,RXD是串行接收引腳。兩個單片機之間要通信,首先電源基準得一樣,所以我們要把兩個單片機的GND相互連起來,然后單片機1的TXD引腳接到單片機2的RXD引腳上,即此路為單片機1發送而單片機2接收的通道,單片機1的RXD引腳接到單片機2的TXD引腳上,即此路為單片機2發送而單片機2接收的通道。這個示意圖就體現了兩個單片機各自收發信息的過程。
當單片機1想給單片機2發送數據時,比如發送一個0xE4這個數據,用二進制形式表示就是0b11100100,在UART通信過程中,是低位先發,高位后發的原則,那么就讓TXD首先拉低電平,持續一段時間,發送一位0,然后繼續拉低,再持續一段時間,又發送了一位0,然后拉高電平,持續一段時間,發了一位1......一直到把8位二進制數字0b11100100全部發送完畢。這里就牽扯到了一個問題,就是持續的這“一段時間”到底是多久?從這里引入我們通信中的另外重要概念——波特率,也叫做比特率。
波特率就是發送一位二進制數據的速率,習慣上用baud表示,即我們發送一位數據的持續時間=1/baud。在通信之前,單片機1和單片機2首先都要明確的約定好他們之間的通信波特率,必須保持一致,收發雙方才能正常實現通信,這一點大家一定要記清楚。
約定好速度后,我們還要考慮第二個問題,數據什么時候是起始,什么時候是結束呢?不管是提前接收還是延遲接收,數據都會接收錯誤。在UART串行通信的時候,一個字節是8位,規定當沒有通信信號發生時,通信線路保持高電平,當要發送數據之前,先發一位0表示起始位,然后發送8位數據位,數據位是先低后高的順序,數據位發完后再發一位1表示停止位。這樣本來要發送一個字節8位數據,而實際上我們一共發送了10位,多出來的兩位其中一位起始位,一位停止位。而接收方呢,原本一直保持的高電平,一旦檢測到來了一位低電平,那就知道了要開始準備接收數據了,接收到8位數據位后,然后檢測到停止位,再準備下一個數據的接收了。我們圖示看一下,如圖1-2所示。
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
圖1-2?串口數據發送示意圖
? ? 如圖1-2串口數據發送示意圖,實際上是一個時域示意圖,就是信號隨著時間變化的對應關系。比如在單片機的發送引腳上,左邊的是先發生的,右邊的是后發生的,數據位的切換時間就是波特率分之一秒,如果能夠理解時域的概念,后邊很多通信的時序圖就很容易理解了。
1.2?USB轉串口通信
隨著技術的發展,工業上還有RS232串口通信的大量使用,但是商業技術的應用上,已經慢慢的使用USB轉UART技術取代了RS232串口,絕大多數筆記本電腦已經沒有串口這個東西了,那我們要實現單片機和電腦之間的通信該如何辦呢?
我們只需要在我們電路上添加一個USB轉串口芯片,就可以成功實現USB通信協議和標準UART串行通信協議的轉換,在我們的開發板上,我們使用的是CH340G這個芯片,如圖1-3所示。
? ? ? ??
圖1-3 USB轉串口電路
CH340G這個電路很簡單,把電源電路,晶振電路接好后,6腳和7腳的UD+和UD-分別接USB口的2個數據引腳上去,3腳和4腳接到了我們單片機的TXD和RXD上去。
CH340G的電路里2腳位置加了個4148的二極管,是一個小技巧。因為我們的STC89C52RC這個單片機下載程序需要冷啟動,就是先點下載后上電,上電瞬間單片機會先檢測需要不需要下載程序。雖然單片機的VCC是由開關來控制,但是由于CH340G的2腳是輸出引腳,如果沒有此二極管,開關后級單片機在斷電的情況下,CH340G的2腳和單片機的P3.0(即RXD)引腳連在一起,有電流會通過這個引腳流入后級電路并且給后級的電容充電,造成后級有一定幅度的電壓,這個電壓值雖然只有兩三伏左右,但是可能會影響到我們的冷啟動。加了二極管后,一方面不影響通信,另外一個方面還可以消除這種問題。這個地方可以暫時作為了解,大家如果自己做這塊電路,可以參考一下。
1.3?IO口模擬UART串口通信
為了讓大家充分理解UART串口通信的原理,我們先用P3.0和P3.1這兩個當做IO口來進行模擬實際串口通信的過程,原理搞懂后,我們再使用寄存器配置實現串口通信過程。
對于UART串口波特率,常用的值是1200、2400、4800、9600、14400、19200、28800、38400、57600、115200、128000、256000等速率。IO口模擬UART串行通信程序是一個簡單的演示程序,我們使用串口調試助手下發一個數據,數據加1后,再自動返回。波特率是我們程序設定好的選擇,我們程序中讓一個數據位持續時間是1/9600秒,那這個地方選擇波特率就是選9600,校驗位選N,數據位8,停止位1。
? ? ? ? ? ? ? ? ? ??
串口調試助手的實質就是我們利用電腦上的UART通信接口,通過這個UART接口發送數據給我們的單片機,也可以把我們的單片機發送的數據接收到這個調試助手界面上。
因為初次接觸通信方面的技術,所以我對這個程序進行一下解釋,大家可以邊看我的解釋邊看程序,把底層原理先徹底弄懂。
變量定義部分就不用說了,直接看main主函數。首先是對通信的波特率的設定,在這里我們配置的波特率是9600,那么串口調試助手也得是9600。配置波特率的時候,我們用的是定時器0的模式2。模式2中,不再是TH0代表高8位,TL0代表低8位了,而只有TL0在進行計數了。當TL0溢出后,不僅僅會讓TF0變1,而且還會將TH0中的內容重新自動裝到TL0中。這樣有一個好處,我們可以把我們想要的定時器初值提前存在TH0中,當TL0溢出后,TH0自動把初值就重新送入TL0了,全自動的,不需要程序上再給TL0重新賦值了,配置方式很簡單,大家可以自己看下程序并且計算一下初值。
波特率設置好以后,打開中斷,然后等待接收串口調試助手下發的數據。接收數據的時候,首先要進行低電平檢測 while (PIN_RXD),若沒有低電平則說明沒有數據,一旦檢測到低電平,就進入啟動接收函數StartRXD()。接收函數最開始啟動半個波特率周期,初學可能這里不是很明白。大家回頭看一下我們的圖1-2里邊的串口數據示意圖,信號在數據位電平變化的時候去讀,因為時序上的誤差以及信號穩定性的問題很容易讀錯數據,所以我們希望在信號最穩定的時候去讀數據。除了信號變化的那個沿的位置外,其他位置都很穩定,那么我們現在就約定在信號中間位置去讀取電平狀態,這樣能夠保證我們信號讀的是對的。
一旦讀到了起始信號,我們就把當前狀態設定成接受狀態,并且打開定時器中斷,第一次是半個周期進入中斷后,對起始位進行二次判斷一下,確認一下起始位是低電平,而不是一個干擾信號。以后每經過9600分之一秒進入一次中斷,并且把這個引腳的狀態讀到RxdBuf里邊。等待接收完畢之后,我們再把這個RxdBuf加1,再通過TXD引腳發送出去,同樣需要先發一位起始位,然后發8個數據位,再發結束位,發送完畢后,程序運行到while (PIN_RXD),等待第二輪信號接收的開始。
?
#include <reg52.h>
sbit PIN_RXD = P3^0; //接收引腳定義
sbit PIN_TXD = P3^1; //發送引腳定義
bit RxdOrTxd = 0; //指示當前狀態為接收還是發送
bit RxdEnd = 0; //接收結束標志
bit TxdEnd = 0; //發送結束標志
unsigned char RxdBuf = 0; //接收緩沖器
unsigned char TxdBuf = 0; //發送緩沖器
void ConfigUART(unsigned int baud);
void StartTXD(unsigned char dat);
void StartRXD();
void main ()
{
ConfigUART(9600); //配置波特率為9600
EA = 1; //開總中斷
while(1)
{
while (PIN_RXD); //等待接收引腳出現低電平,即起始位
StartRXD(); //啟動接收
while (!RxdEnd); //等待接收完成
StartTXD(RxdBuf+1); //接收到的數據+1后,發送回去
while (!TxdEnd); //等待發送完成
}
}
void ConfigUART(unsigned int baud) //串口配置函數,baud為波特率
{
TMOD &= 0xF0; //清零T0的控制位
TMOD |= 0x02; //配置T0為模式2
TH0 = 256 - (11059200/12) / baud; //計算T0重載值
}
void StartRXD() //啟動串行接收
{
TL0 = 256 - ((256-TH0) >> 1); //接收啟動時的T0定時為半個波特率周期
ET0 = 1; //使能T0中斷
TR0 = 1; //啟動T0
RxdEnd = 0; //清零接收結束標志
RxdOrTxd = 0; //設置當前狀態為接收
}
void StartTXD(unsigned char dat) //啟動串行發送,dat為待發送字節數據
{
TxdBuf = dat; //待發送數據保存到發送緩沖器
TL0 = TH0; //T0計數初值為重載值
ET0 = 1; //使能T0中斷
TR0 = 1; //啟動T0
PIN_TXD = 0; //發送起始位
TxdEnd = 0; //清零發送結束標志
RxdOrTxd = 1; //設置當前狀態為發送
}
void InterruptTimer0() interrupt 1 //T0中斷服務函數,處理串行發送和接收
{
static unsigned char cnt = 0; //bit計數器,記錄當前正在處理的位
if (RxdOrTxd) //串行發送處理
{
cnt++;
if (cnt <= 8) //低位在先依次發送8bit數據位
{
PIN_TXD = TxdBuf & 0x01;
TxdBuf >>= 1;
}
else if (cnt == 9) //發送停止位
{
PIN_TXD = 1;
}
else //發送結束
{
cnt = 0; //復位bit計數器
TR0 = 0; //關閉T0
TxdEnd = 1; //置發送結束標志
}
}
else //串行接收處理
{
if (cnt == 0) //處理起始位
{
if (!PIN_RXD) //起始位為0時,清零接收緩沖器,準備接收數據位
{
RxdBuf = 0;
cnt++;
}
else //起始位不為0時,中止接收
{
TR0 = 0; //關閉T0
}
}
else if (cnt <= 8) //處理8位數據位
{
RxdBuf >>= 1; //低位在先,所以將之前接收的位向右移
if (PIN_RXD) //接收腳為1時,緩沖器最高位置1;為0時不處理即仍保持移位后的0
{
RxdBuf |= 0x80;
}
cnt++;
}
else //停止位處理
{
cnt = 0; //復位bit計數器
TR0 = 0; //關閉T0
if (PIN_RXD) //停止位為1時,方能認為數據有效
{
RxdEnd = 1; //置接收結束標志
}
}
}
}
?
總結
以上是生活随笔為你收集整理的UART串口通信浅谈之(一)--基础概述的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: HBase 原理
- 下一篇: 三个数比较大小函数调用c语言,C语言函数