小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

單片機入門培訓(xùn)專題(十四)- UART串行通信(一)

 xvdo 2015-08-26


連載提要:單片機入門培訓(xùn)專題仍在繼續(xù),在平常的單片機系統(tǒng)設(shè)計中,除了一些“單機”類型的應(yīng)用,比如之前講到的LED小燈電路,還有很多電路系統(tǒng)會涉及到多機之間的通信,當(dāng)然,這里所說的通信,可以是單片機與單片機之間的通信,也可以是單片機和其他類型設(shè)備之間的通信,可見,單片機的通信是單片機入門必須掌握的內(nèi)容,那么今天,我們就來說一說單片機的UART串行通信。

通信按照傳統(tǒng)的理解就是信息的傳輸與交換。對于單片機來說,通信則與傳感器、存儲芯片、外圍控制芯片等技術(shù)緊密結(jié)合,成為整個單片機系統(tǒng)的“神經(jīng)中樞”。沒有通信,單片機所實現(xiàn)的功能僅僅局限于單片機本身,就無法通過其他設(shè)備獲得有用信息,也無法將自己產(chǎn)生的信息告訴其它設(shè)備。如果單片機通信沒處理好的話,它和外圍器件的合作程度就受到限制,最終整個系統(tǒng)也無法完成強大的功能,由此可見單片機通信技術(shù)的重要性。UART(Universal Asynchronous Receiver/Transmitter,即通用異步收發(fā)器)串行通信是單片機最常用的一種通信技術(shù),通常用于單片機和電腦之間以及單片機和單片機之間的通信。


14.1串行通信的初步認(rèn)識

  通信按照基本類型可以分為并行通信和串行通信。并行通信時數(shù)據(jù)的各個位同時傳送,可以實現(xiàn)字節(jié)為單位通信,但是因為通信線多占用資源多,成本高。比如我們前邊用到的P0 = 0xfe;一次給P0的8個IO口分別賦值,同時進行信號輸出,類似于有8個車道同時可以過去8輛車一樣,這種形式就是并行的,我們習(xí)慣上還稱P0、P1、P2和P3為51單片機的4組并行總線。

  而串行通信,就如同一條車道,一次只能一輛車過去,如果一個0xfe這樣一個字節(jié)的數(shù)據(jù)要傳輸過去的話,假如低位在前高位在后,那發(fā)送方式就是0-1-1-1-1-1-1-1-1,一位一位的發(fā)送出去的,要發(fā)送8次才能發(fā)送完一個字節(jié)。

  在我們的STC89C52上,有兩個引腳,是專門用來做UART串口通信的,一個是P3.0一個是P3.1,還分別有另外的名字叫做RXD和TXD,這兩個引腳是專門用來進行UART通信的,如果我們兩個單片機進行UART串口通信的話,那基本的演示圖如圖14-1所示。


圖14-1 單片機之間UART通信示意圖

  圖中,GND表示單片機系統(tǒng)電源的參考地,TXD是串行發(fā)送引腳,RXD是串行接收引腳。兩個單片機之間要通信,首先電源基準(zhǔn)得一樣,所以我們要把兩個單片機的GND相互連起來,然后單片機1的TXD引腳接到單片機2的RXD引腳上,即此路為單片機1發(fā)送而單片機2接收的通道,單片機1的RXD引腳接到單片機2的TXD引腳上,即此路為單片機2發(fā)送而單片機2接收的通道。這個示意圖就體現(xiàn)了兩個單片機各自收發(fā)信息的過程。

  當(dāng)單片機1想給單片機2發(fā)送數(shù)據(jù)時,比如發(fā)送一個0xE4這個數(shù)據(jù),用二進制形式表示就是0b11100100,在UART通信過程中,是低位先發(fā),高位后發(fā)的原則,那么就讓TXD首先拉低電平,持續(xù)一段時間,發(fā)送一位0,然后繼續(xù)拉低,再持續(xù)一段時間,又發(fā)送了一位0,然后拉高電平,持續(xù)一段時間,發(fā)了一位1......一直到把8位二進制數(shù)字0b11100100全部發(fā)送完畢。這里就牽扯到了一個問題,就是持續(xù)的這“一段時間”到底是多久?從這里引入我們通信中的另外重要概念——波特率,也叫做比特率。

  波特率就是發(fā)送一位二進制數(shù)據(jù)的速率,習(xí)慣上用baud表示,即我們發(fā)送一位數(shù)據(jù)的持續(xù)時間=1/baud。在通信之前,單片機1和單片機2首先都要明確的約定好他們之間的通信波特率,必須保持一致,收發(fā)雙方才能正常實現(xiàn)通信,這一點大家一定要記清楚。

  約定好速度后,我們還要考慮第二個問題,數(shù)據(jù)什么時候是起始,什么時候是結(jié)束呢?不管是提前接收還是延遲接收,數(shù)據(jù)都會接收錯誤。在UART串行通信的時候,一個字節(jié)是8位,規(guī)定當(dāng)沒有通信信號發(fā)生時,通信線路保持高電平,當(dāng)要發(fā)送數(shù)據(jù)之前,先發(fā)一位0表示起始位,然后發(fā)送8位數(shù)據(jù)位,數(shù)據(jù)位是先低后高的順序,數(shù)據(jù)位發(fā)完后再發(fā)一位1表示停止位。這樣本來要發(fā)送一個字節(jié)8位數(shù)據(jù),而實際上我們一共發(fā)送了10位,多出來的兩位其中一位起始位,一位停止位。而接收方呢,原本一直保持的高電平,一旦檢測到來了一位低電平,那就知道了要開始準(zhǔn)備接收數(shù)據(jù)了,接收到8位數(shù)據(jù)位后,然后檢測到停止位,再準(zhǔn)備下一個數(shù)據(jù)的接收了。我們圖示看一下,如圖14-2所示。


圖14-2 串口數(shù)據(jù)發(fā)送示意圖

   像我們的圖14-2串口數(shù)據(jù)發(fā)送示意圖,實際上是一個時域示意圖,就是信號隨著時間變化的對應(yīng)關(guān)系。比如在單片機的發(fā)送引腳上,左邊的是先發(fā)生的,右邊的是后發(fā)生的,數(shù)據(jù)位的切換時間就是波特率分之一秒,如果能夠理解時域的概念,后邊很多通信的時序圖就很容易理解了。


14.2串行RS232通信接口

  在我們的臺式電腦上,經(jīng)常可以看到一個9針的串行接口,這個串行接口叫做RS232接口,它和UART通信有關(guān)聯(lián),但是由于現(xiàn)在筆記本電腦都不帶這種9針串口了,所以和單片機通信越來越趨向于使用USB虛擬的串口和單片機通信,因此這一節(jié)的內(nèi)容作為了解內(nèi)容,大家知道有這么回事就行。

  我們先來認(rèn)識一下這個標(biāo)準(zhǔn)串口,串口分為9針的和9孔的,習(xí)慣上我們也稱之為公頭和母頭,如圖14-3所示。


圖14-3 RS232通信接口

  RS232接口一共有9個引腳,分別定義是:1、載波檢測(DCD);2、接收數(shù)據(jù)(RXD);3、發(fā)送數(shù)據(jù)(TXD);4、數(shù)據(jù)終端準(zhǔn)備好(DTR);5、信號地線(SG);6、數(shù)據(jù)準(zhǔn)備好(DSR);7、請求發(fā)送(RTS);8、清除發(fā)送(CTS);9、振鈴提示(RI)。我們要讓這個串口和我們單片機進行通信,我們只需要關(guān)心其中的2腳(RXD),3腳(TXD)和5腳(GND)。

  雖然這三個腳的名字和我們單片機上的串口名字一樣,但是卻不能直接和單片機對連直接通信,這是為什么呢?隨著我們了解的內(nèi)容越來越多,我們得慢慢知道,不是所有的電路都是5V代表高電平而0V代表低電平的。對于RS232標(biāo)準(zhǔn)來說,它是個反邏輯,也叫做負邏輯。為何叫負邏輯?它的TXD和RXD的電壓,-3V到-15V代表是1,3-15V之間的電壓代表是0。低電平代表的是1,而高電平代表的是0,所以稱之為負邏輯。因此電腦的9針232串口是不能和單片機直接連接的,需要用一個轉(zhuǎn)換芯片MAX232來完成,如圖14-4所示。


圖14-4 MAX232轉(zhuǎn)接圖

  這個芯片就可以實現(xiàn)把標(biāo)準(zhǔn)RS232串口電平轉(zhuǎn)換成我們單片機能夠識別和承受的UART 0V/5V電平標(biāo)準(zhǔn)。從這里大家似乎慢慢有點明白了,其實RS232串口和UART串口,他們的協(xié)議類型是一樣,只是電平不同而已,而MAX232這個芯片起到的就是中間人的作用,他把UART電平轉(zhuǎn)換成RS232電平,也把RS232電平轉(zhuǎn)換成UART電平,從而實現(xiàn)標(biāo)準(zhǔn)RS232接口和單片機UART之間的通信連接。


14.3USB轉(zhuǎn)串口通信

  隨著技術(shù)的發(fā)展,工業(yè)上還有RS232串口通信的大量使用,但是商業(yè)技術(shù)的應(yīng)用上,已經(jīng)慢慢的使用USB轉(zhuǎn)UART技術(shù)取代了RS232串口,絕大多數(shù)筆記本電腦已經(jīng)沒有串口這個東西了,那我們要實現(xiàn)單片機和電腦之間的通信該如何辦呢?

我們只需要在我們電路上添加一個USB轉(zhuǎn)串口芯片,就可以成功實現(xiàn)USB通信協(xié)議和標(biāo)準(zhǔn)UART串行通信協(xié)議的轉(zhuǎn)換,在我們的開發(fā)板上,我們使用的是CH340T這個芯片,如圖14-5所示。


圖14-5 USB轉(zhuǎn)串口電路

  左側(cè)J2是一組跳線的組合,大家可以在我們板子左下角的跳線位置找到,我們是把3腳和5腳、4腳和6腳通過跳線帽短接到一起。右側(cè)的CH340T這個電路很簡單,把電源電路,晶振電路接好后,6腳和7腳的DP和DM分別接USB口的2個數(shù)據(jù)引腳上去,3腳和4腳通過跳線接到了我們單片機的TXD和RXD上去。

  CH340T的電路里3腳位置加了個4148的二極管,是一個小技巧。因為我們的STC89C52RC這個單片機下載程序需要冷啟動,就是先點下載后上電,上電瞬間單片機會先檢測需要不需要下載程序。雖然單片機的VCC是由開關(guān)來控制,但是由于CH340T的3腳是輸出引腳,如果沒有此二極管,開關(guān)后級單片機在斷電的情況下,CH340T的3腳和單片機的P3.0(即RXD)引腳連在一起,有電流會通過這個引腳流入后級電路并且給后級的電容充電,造成后級有一定幅度的電壓,這個電壓值雖然只有兩三伏左右,但是可能會影響到我們的冷啟動。加了二極管后,一方面不影響通信,另外一個方面還可以消除這種問題。這個地方可以暫時作為了解,大家如果自己做這塊電路,可以參考一下。


14.4IO口模擬UART串口通信

  為了讓大家充分理解UART串口通信的原理,我們先用P3.0和P3.1這兩個當(dāng)做IO口來進行模擬實際串口通信的過程,原理搞懂后,我們再使用寄存器配置實現(xiàn)串口通信過程。

  對于UART串口波特率,常用的值是300、600、1200、2400、4800、9600、14400、19200、28800、38400、57600、115200、128000、256000等速率。IO口模擬UART串行通信程序是一個簡單的演示程序,我們使用串口調(diào)試助手下發(fā)一個數(shù)據(jù),數(shù)據(jù)加1后,再自動返回。串口調(diào)試助手,在我們進行全板子測試視頻的時候,大家已經(jīng)見過,這里我們直接使用STC-ISP軟件自帶的串口調(diào)試助手,先把串口調(diào)試助手使用給大家說一下,如圖14-6所示。第一步要選擇串口助手菜單,第二步選擇十六進制顯示,第三步選擇十六進制發(fā)送,第四步選擇COM口,這個COM口要和自己電腦設(shè)備管理器里的那個COM口一致,波特率是我們程序設(shè)定好的選擇,我們程序中讓一個數(shù)據(jù)位持續(xù)時間是1/9600秒,那這個地方選擇波特率就是選9600,校驗位選N,數(shù)據(jù)位8,停止位1。


圖14-6 串口調(diào)試助手示意圖

  串口調(diào)試助手的實質(zhì)就是我們利用電腦上的UART通信接口,通過這個UART接口發(fā)送數(shù)據(jù)給我們的單片機,也可以把我們的單片機發(fā)送的數(shù)據(jù)接收到這個調(diào)試助手界面上。

  因為初次接觸通信方面的技術(shù),所以我對這個程序進行一下解釋,大家可以邊看我的解釋邊看程序,把底層原理先徹底弄懂。

  變量定義部分就不用說了,直接看main主函數(shù)。首先是對通信的波特率的設(shè)定,在這里我們配置的波特率是9600,那么串口調(diào)試助手也得是9600。配置波特率的時候,我們用的是定時器0的模式2。模式2中,不再是TH0代表高8位,TL0代表低8位了,而只有TL0在進行計數(shù)了。當(dāng)TL0溢出后,不僅僅會讓TF0變1,而且還會將TH0中的內(nèi)容重新自動裝到TL0中。這樣有一個好處,我們可以把我們想要的定時器初值提前存在TH0中,當(dāng)TL0溢出后,TH0自動把初值就重新送入TL0了,全自動的,不需要程序上再給TL0重新賦值了,配置方式很簡單,大家可以自己看下程序并且計算一下初值。

  波特率設(shè)置好以后,打開中斷,然后等待接收串口調(diào)試助手下發(fā)的數(shù)據(jù)。接收數(shù)據(jù)的時候,首先要進行低電平檢測 while (PIN_RXD),若沒有低電平則說明沒有數(shù)據(jù),一旦檢測到低電平,就進入啟動接收函數(shù)StartRXD()。接收函數(shù)最開始啟動半個波特率周期,初學(xué)可能這里不是很明白。大家回頭看一下我們的圖14-2里邊的串口數(shù)據(jù)示意圖,信號在數(shù)據(jù)位電平變化的時候去讀,因為時序上的誤差以及信號穩(wěn)定性的問題很容易讀錯數(shù)據(jù),所以我們希望在信號最穩(wěn)定的時候去讀數(shù)據(jù)。除了信號變化的那個沿的位置外,其他位置都很穩(wěn)定,那么我們現(xiàn)在就約定在信號中間位置去讀取電平狀態(tài),這樣能夠保證我們信號讀的是對的。

  一旦讀到了起始信號,我們就把當(dāng)前狀態(tài)設(shè)定成接受狀態(tài),并且打開定時器中斷,第一次是半個周期進入中斷后,對起始位進行二次判斷一下,確認(rèn)一下起始位是低電平,而不是一個干擾信號。以后每經(jīng)過9600分之一秒進入一次中斷,并且把這個引腳的狀態(tài)讀到RxdBuf里邊。等待接收完畢之后,我們再把這個RxdBuf加1,再通過TXD引腳發(fā)送出去,同樣需要先發(fā)一位起始位,然后發(fā)8個數(shù)據(jù)位,再發(fā)結(jié)束位,發(fā)送完畢后,程序運行到while (PIN_RXD),等待第二輪信號接收的開始。


#include <reg52.h>


sbit PIN_RXD = P3^0; //接收引腳定義

sbit PIN_TXD = P3^1; //發(fā)送引腳定義


bit RxdOrTxd = 0; //指示當(dāng)前狀態(tài)為接收還是發(fā)送

bit RxdEnd = 0; //接收結(jié)束標(biāo)志

bit TxdEnd = 0; //發(fā)送結(jié)束標(biāo)志

unsigned char RxdBuf = 0; //接收緩沖器

unsigned char TxdBuf = 0; //發(fā)送緩沖器


void ConfigUART(unsigned int baud);

void StartTXD(unsigned char dat);

void StartRXD();


void main ()

{

ConfigUART(9600); //配置波特率為9600

EA = 1; //開總中斷

while(1)

{

while (PIN_RXD); //等待接收引腳出現(xiàn)低電平,即起始位

StartRXD(); //啟動接收

while (!RxdEnd); //等待接收完成

StartTXD(RxdBuf+1); //接收到的數(shù)據(jù)+1后,發(fā)送回去

while (!TxdEnd); //等待發(fā)送完成

}

}


void ConfigUART(unsigned int baud) //串口配置函數(shù),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; //清零接收結(jié)束標(biāo)志

RxdOrTxd = 0; //設(shè)置當(dāng)前狀態(tài)為接收

}

void StartTXD(unsigned char dat) //啟動串行發(fā)送,dat為待發(fā)送字節(jié)數(shù)據(jù)

{

TxdBuf = dat; //待發(fā)送數(shù)據(jù)保存到發(fā)送緩沖器

TL0 = TH0; //T0計數(shù)初值為重載值

ET0 = 1; //使能T0中斷

TR0 = 1; //啟動T0

PIN_TXD = 0; //發(fā)送起始位

TxdEnd = 0; //清零發(fā)送結(jié)束標(biāo)志

RxdOrTxd = 1; //設(shè)置當(dāng)前狀態(tài)為發(fā)送

}


void InterruptTimer0() interrupt 1 //T0中斷服務(wù)函數(shù),處理串行發(fā)送和接收

{

static unsigned char cnt = 0; //bit計數(shù)器,記錄當(dāng)前正在處理的位


if (RxdOrTxd) //串行發(fā)送處理

{

cnt++;

if (cnt <= 8) //低位在先依次發(fā)送8bit數(shù)據(jù)位

{

PIN_TXD = TxdBuf & 0x01;

TxdBuf >>= 1;

}

else if (cnt == 9) //發(fā)送停止位

{

PIN_TXD = 1;

}

else //發(fā)送結(jié)束

{

cnt = 0; //復(fù)位bit計數(shù)器

TR0 = 0; //關(guān)閉T0

TxdEnd = 1; //置發(fā)送結(jié)束標(biāo)志

}

}

else //串行接收處理

{

if (cnt == 0) //處理起始位

{

if (!PIN_RXD) //起始位為0時,清零接收緩沖器,準(zhǔn)備接收數(shù)據(jù)位

{

RxdBuf = 0;

cnt++;

}

else //起始位不為0時,中止接收

{

TR0 = 0; //關(guān)閉T0

}

}

else if (cnt <= 8) //處理8位數(shù)據(jù)位

{

RxdBuf >>= 1; //低位在先,所以將之前接收的位向右移

if (PIN_RXD) //接收腳為1時,緩沖器最高位置1;為0時不處理即仍保持移位后的0

{

RxdBuf |= 0x80;

}

cnt++;

}

else //停止位處理

{

cnt = 0; //復(fù)位bit計數(shù)器

TR0 = 0; //關(guān)閉T0

if (PIN_RXD) //停止位為1時,方能認(rèn)為數(shù)據(jù)有效

{

RxdEnd = 1; //置接收結(jié)束標(biāo)志

}

}

}

}

通過學(xué)習(xí)上面的程序,也慢慢感受到了,程序的延時部分已經(jīng)不再使用簡單的delay來完成了,我們要通過我們的程序編寫積累,慢慢提高自己靈活運用定時器的能力。一個小小的定時器,可以幫我們完成很多很多工作。


    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多