通信,按照傳統(tǒng)的理解就是信息的傳輸與交換。對(duì)于單片機(jī)來(lái)說(shuō),通信則與傳感器、存儲(chǔ)芯片、外圍控制芯片等技術(shù)緊密結(jié)合,成為整個(gè)單片機(jī)系統(tǒng)的“神經(jīng)中樞”。沒(méi)有通信,單片機(jī)所實(shí)現(xiàn)的功能僅僅局限于單片機(jī)本身,就無(wú)法通過(guò)其它設(shè)備獲得有用信息,也無(wú)法將自己產(chǎn)生的信息告訴其它設(shè)備。如果單片機(jī)通信沒(méi)處理好的話,它和外圍器件的合作程度就受到限制,最終整個(gè)系統(tǒng)也無(wú)法完成強(qiáng)大的功能,由此可見(jiàn)單片機(jī)通信技術(shù)的重要性。UART(Universal Asynchronous Receiver/Transmitter,即通用異步收發(fā)器)串行通信是單片機(jī)最常用的一種通信技術(shù),通常用于單片機(jī)和電腦之間以及單片機(jī)和單片機(jī)之間的通信。
11.1 串行通信的初步認(rèn)識(shí)
通信按照基本類型可以分為并行通信和串行通信。并行通信時(shí)數(shù)據(jù)的各個(gè)位同時(shí)傳送,可以實(shí)現(xiàn)字節(jié)為單位通信,但是通信線多占用資源多,成本高。比如我們前邊用到的P0 = 0xFE;一次給P0的8個(gè)IO口分別賦值,同時(shí)進(jìn)行信號(hào)輸出,類似于有8個(gè)車道同時(shí)可以過(guò)去8輛車一樣,這種形式就是并行的,我們習(xí)慣上還稱P0、P1、P2和P3為51單片機(jī)的4組并行總線。
而串行通信,就如同一條車道,一次只能一輛車過(guò)去,如果一個(gè)0xFE這樣一個(gè)字節(jié)的數(shù)據(jù)要傳輸過(guò)去的話,假如低位在前高位在后的話,那發(fā)送方式就是0-1-1-1-1-1-1-1-1,一位一位的發(fā)送出去的,要發(fā)送8次才能發(fā)送完一個(gè)字節(jié)。
STC89C52有兩個(gè)引腳是專門用來(lái)做UART串行通信的,一個(gè)是P3.0一個(gè)是P3.1,它們還分別有另外的名字叫做RXD和TXD,由它們組成的通信接口就叫做串行接口,簡(jiǎn)稱串口。用兩個(gè)單片機(jī)進(jìn)行UART串口通信,基本的演示圖如圖11-1所示。
圖11-1 單片機(jī)之間UART通信示意圖
圖中,GND表示單片機(jī)系統(tǒng)電源的參考地,TXD是串行發(fā)送引腳,RXD是串行接收引腳。兩個(gè)單片機(jī)之間要通信,首先電源基準(zhǔn)得一樣,所以我們要把兩個(gè)單片機(jī)的GND相互連接起來(lái),然后單片機(jī)1的TXD引腳接到單片機(jī)2的RXD引腳上,即此路為單片機(jī)1發(fā)送而單片機(jī)2接收的通道,單片機(jī)1的RXD引腳接到單片機(jī)2的TXD引腳上,即此路為單片機(jī)2發(fā)送而單片機(jī)1接收的通道。這個(gè)示意圖就體現(xiàn)了兩個(gè)單片機(jī)相互收發(fā)信息的過(guò)程。
當(dāng)單片機(jī)1想給單片機(jī)2發(fā)送數(shù)據(jù)時(shí),比如發(fā)送一個(gè)0xE4這個(gè)數(shù)據(jù),用二進(jìn)制形式表示就是0b11100100,在UART通信過(guò)程中,是低位先發(fā),高位后發(fā)的原則,那么就讓TXD首先拉低電平,持續(xù)一段時(shí)間,發(fā)送一位0,然后繼續(xù)拉低,再持續(xù)一段時(shí)間,又發(fā)送了一位0,然后拉高電平,持續(xù)一段時(shí)間,發(fā)了一位1……一直到把8位二進(jìn)制數(shù)字0b11100100全部發(fā)送完畢。這里就涉及到了一個(gè)問(wèn)題,就是持續(xù)的這“一段時(shí)間”到底是多久?由此便引入了通信中的一個(gè)重要概念——波特率,也叫做比特率。
波特率就是發(fā)送二進(jìn)制數(shù)據(jù)位的速率,習(xí)慣上用baud表示,即我們發(fā)送一位二進(jìn)制數(shù)據(jù)的持續(xù)時(shí)間=1/baud。在通信之前,單片機(jī)1和單片機(jī)2首先都要明確的約定好它們之間的通信波特率,必須保持一致,收發(fā)雙方才能正常實(shí)現(xiàn)通信,這一點(diǎn)大家一定要記清楚。
約定好速度后,我們還要考慮第二個(gè)問(wèn)題,數(shù)據(jù)什么時(shí)候是起始,什么時(shí)候是結(jié)束呢?不管是提前接收還是延遲接收,數(shù)據(jù)都會(huì)接收錯(cuò)誤。在UART通信的時(shí)候,一個(gè)字節(jié)是8位,規(guī)定當(dāng)沒(méi)有通信信號(hào)發(fā)生時(shí),通信線路保持高電平,當(dāng)要發(fā)送數(shù)據(jù)之前,先發(fā)一位0表示起始位,然后發(fā)送8位數(shù)據(jù)位,數(shù)據(jù)位是先低后高的順序,數(shù)據(jù)位發(fā)完后再發(fā)一位1表示停止位。這樣本來(lái)要發(fā)送一個(gè)字節(jié)的8位數(shù)據(jù),而實(shí)際上我們一共發(fā)送了10位,多出來(lái)的兩位其中一位起始位,一位停止位。而接收方呢,原本一直保持的高電平,一旦檢測(cè)到了一位低電平,那就知道了要開(kāi)始準(zhǔn)備接收數(shù)據(jù)了,接收到8位數(shù)據(jù)位后,然后檢測(cè)到停止位,再準(zhǔn)備下一個(gè)數(shù)據(jù)的接收。我們圖示看一下,如圖11-2所示。
圖11-2 串口數(shù)據(jù)發(fā)送示意圖
圖11-2串口數(shù)據(jù)發(fā)送示意圖,實(shí)際上是一個(gè)時(shí)域示意圖,就是信號(hào)隨著時(shí)間變化的對(duì)應(yīng)關(guān)系。比如在單片機(jī)的發(fā)送引腳上,左邊的是先發(fā)生的,右邊的是后發(fā)生的,數(shù)據(jù)位的切換時(shí)間就是波特率分之一秒,如果能夠理解時(shí)域的概念,后邊很多通信的時(shí)序圖就很容易理解了。
11.2 RS232通信接口
在我們的臺(tái)式電腦上,一般都會(huì)有一個(gè)9針的串行接口,這個(gè)串行接口叫做RS232接口,它和UART通信有關(guān)聯(lián),但是由于現(xiàn)在筆記本電腦都不帶這種9針串口了,所以和單片機(jī)通信越來(lái)越趨向于使用USB虛擬的串口,因此這一節(jié)的內(nèi)容作為了解內(nèi)容,大家知道有這么回事就行了。
我們先來(lái)認(rèn)識(shí)一下這個(gè)標(biāo)準(zhǔn)串口,在物理結(jié)構(gòu)上分為9針的和9孔的,習(xí)慣上我們也稱之為公頭和母頭,如圖11-3所示。
圖11-3 RS232通信接口
RS232接口一共有9個(gè)引腳,分別定義是:1、載波檢測(cè)DCD;2、接收數(shù)據(jù)RXD;3、發(fā)送數(shù)據(jù)TXD;4、數(shù)據(jù)終端準(zhǔn)備好DTR;5、信號(hào)地線SG;6、數(shù)據(jù)準(zhǔn)備好DSR;7、請(qǐng)求發(fā)送RTS;8、清除發(fā)送CTS;9、振鈴提示RI。我們要讓這個(gè)串口和我們單片機(jī)進(jìn)行通信,我們只需要關(guān)心其中的2腳RXD、3腳TXD和5腳GND即可。
雖然這三個(gè)引腳的名字和我們單片機(jī)上的串口名字一樣,但是卻不能直接和單片機(jī)對(duì)連通信,這是為什么呢?隨著我們了解的內(nèi)容越來(lái)越多,我們得慢慢知道,不是所有的電路都是5V代表高電平而0V代表低電平的。對(duì)于RS232標(biāo)準(zhǔn)來(lái)說(shuō),它是個(gè)反邏輯,也叫做負(fù)邏輯。為何叫負(fù)邏輯?它的TXD和RXD的電壓,-3V~-15V電壓代表是1,+3~+15V電壓代表是0。低電平代表的是1,而高電平代表的是0,所以稱之為負(fù)邏輯。因此電腦的9針RS232串口是不能和單片機(jī)直接連接的,需要用一個(gè)電平轉(zhuǎn)換芯片MAX232來(lái)完成,如圖11-4所示。
圖11-4 MAX232轉(zhuǎn)接圖
這個(gè)芯片就可以實(shí)現(xiàn)把標(biāo)準(zhǔn)RS232串口電平轉(zhuǎn)換成我們單片機(jī)能夠識(shí)別和承受的UART 0V/5V電平。從這里大家似乎慢慢有點(diǎn)明白了,其實(shí)RS232串口和UART串口,它們的協(xié)議類型是一樣的,只是電平標(biāo)準(zhǔn)不同而已,而MAX232這個(gè)芯片起到的就是中間人的作用,它把UART電平轉(zhuǎn)換成RS232電平,也把RS232電平轉(zhuǎn)換成UART電平,從而實(shí)現(xiàn)標(biāo)準(zhǔn)RS232接口和單片機(jī)UART之間的通信連接。
11.3 USB轉(zhuǎn)串口通信
隨著技術(shù)的發(fā)展,工業(yè)上還有RS232串口通信的大量使用,但是商業(yè)技術(shù)的應(yīng)用上,已經(jīng)慢慢的使用USB轉(zhuǎn)UART技術(shù)取代了RS232串口,絕大多數(shù)筆記本電腦已經(jīng)沒(méi)有串口這個(gè)東西了,那我們要實(shí)現(xiàn)單片機(jī)和電腦之間的通信該怎么辦呢?
我們只需要在電路上添加一個(gè)USB轉(zhuǎn)串口芯片,就可以成功實(shí)現(xiàn)USB通信協(xié)議和標(biāo)準(zhǔn)UART串行通信協(xié)議的轉(zhuǎn)換,在我們的開(kāi)發(fā)板上,我們使用的是CH340T這個(gè)芯片,如圖11-5所示。
圖11-5 USB轉(zhuǎn)串口電路
圖中左下方J1和J2是兩個(gè)跳線的組合,大家可以在我們板子左下方的位置找到,我們需要用跳線帽把中間和下邊的針短接在一起。右側(cè)的CH340T這個(gè)電路很簡(jiǎn)單,把電源、晶振接好后,6腳和7腳的DP和DM分別接USB口的2個(gè)數(shù)據(jù)引腳上去,3腳和4腳通過(guò)跳線接到了我們單片機(jī)的TXD和RXD上去。
CH340T的電路里3腳位置加了個(gè)4148的二極管,是一個(gè)小技巧。因?yàn)镾TC89C52這個(gè)單片機(jī)下載程序時(shí)需要冷啟動(dòng),就是先點(diǎn)下載后上電,上電瞬間單片機(jī)會(huì)先檢測(cè)需要不需要下載程序。雖然單片機(jī)的VCC是由開(kāi)關(guān)來(lái)控制,但是由于CH340T的3腳是輸出引腳,如果沒(méi)有此二極管,開(kāi)關(guān)后級(jí)單片機(jī)在斷電的情況下,CH340T的3腳和單片機(jī)的P3.0(即RXD)引腳連在一起,有電流會(huì)通過(guò)這個(gè)引腳流入后級(jí)電路并且給后級(jí)的電容充電,造成后級(jí)有一定幅度的電壓,這個(gè)電壓值雖然只有兩三伏左右,但是可能會(huì)影響到正常的冷啟動(dòng)。加了二極管后,一方面不影響通信,另外一個(gè)方面還可以消除這種不良影響。這個(gè)地方可以暫時(shí)作為了解,大家如果自己做這類電路,可以參考一下。
11.4 IO口模擬UART串口通信
為了讓大家充分理解UART串口通信的原理,我們先把P3.0和P3.1當(dāng)做IO口來(lái)進(jìn)行模擬實(shí)際串口通信的過(guò)程,原理搞懂后,我們?cè)偈褂?a href="http://www.ttokpm.com/tags/寄存器/" target="_blank">寄存器配置實(shí)現(xiàn)串口通信過(guò)程。
對(duì)于UART串口波特率,常用的值是300、600、1200、2400、4800、9600、14400、19200、28800、38400、57600、115200等速率。IO口模擬UART串行通信程序是一個(gè)簡(jiǎn)單的演示程序,我們使用串口調(diào)試助手下發(fā)一個(gè)數(shù)據(jù),數(shù)據(jù)加1后,再自動(dòng)返回。
串口調(diào)試助手,這里我們直接使用STC-ISP軟件自帶的串口調(diào)試助手,先把串口調(diào)試助手的使用給大家說(shuō)一下,如圖11-6所示。第一步要選擇串口助手菜單,第二步選擇十六進(jìn)制顯示,第三步選擇十六進(jìn)制發(fā)送,第四步選擇COM口,這個(gè)COM口要和自己電腦設(shè)備管理器里的那個(gè)COM口一致,波特率按我們程序設(shè)定好的選擇,我們程序中讓一個(gè)數(shù)據(jù)位持續(xù)時(shí)間是1/9600秒,那這個(gè)地方選擇波特率就是選9600,校驗(yàn)位選N,數(shù)據(jù)位8,停止位1。
圖11-6 串口調(diào)試助手示意圖
串口調(diào)試助手的實(shí)質(zhì)就是利用電腦上的UART通信接口,發(fā)送數(shù)據(jù)給我們的單片機(jī),也可以把我們的單片機(jī)發(fā)送的數(shù)據(jù)接收到這個(gè)調(diào)試助手界面上。
因?yàn)槌醮谓佑|通信方面的技術(shù),所以我把后面的IO模擬串口通信程序進(jìn)行一下解釋,大家可以邊看我的解釋邊看程序,把底層原理先徹底弄懂。
變量定義部分就不用說(shuō)了,直接看main主函數(shù)。首先是對(duì)通信的波特率的設(shè)定,在這里我們配置的波特率是9600,那么串口調(diào)試助手也得是9600。配置波特率的時(shí)候,我們用的是定時(shí)器T0的模式2。模式2中,不再是TH0代表高8位,TL0代表低8位了,而只有TL0在進(jìn)行計(jì)數(shù),當(dāng)TL0溢出后,不僅僅會(huì)讓TF0變1,而且還會(huì)將TH0中的內(nèi)容重新自動(dòng)裝到TL0中。這樣有一個(gè)好處,就是我們可以把想要的定時(shí)器初值提前存在TH0中,當(dāng)TL0溢出后,TH0自動(dòng)把初值就重新送入TL0了,全自動(dòng)的,不需要程序中再給TL0重新賦值了,配置方式很簡(jiǎn)單,大家可以自己看下程序并且計(jì)算一下初值。
波特率設(shè)置好以后,打開(kāi)中斷,然后等待接收串口調(diào)試助手下發(fā)的數(shù)據(jù)。接收數(shù)據(jù)的時(shí)候,首先要進(jìn)行低電平檢測(cè)while (PIN_RXD),若沒(méi)有低電平則說(shuō)明沒(méi)有數(shù)據(jù),一旦檢測(cè)到低電平,就進(jìn)入啟動(dòng)接收函數(shù)StartRXD()。接收函數(shù)最開(kāi)始啟動(dòng)半個(gè)波特率周期,初學(xué)可能這里不是很明白。大家回頭看一下我們的圖11-2里邊的串口數(shù)據(jù)示意圖,如果在數(shù)據(jù)位電平變化的時(shí)候去讀取,因?yàn)闀r(shí)序上的誤差以及信號(hào)穩(wěn)定性的問(wèn)題很容易讀錯(cuò)數(shù)據(jù),所以我們希望在信號(hào)最穩(wěn)定的時(shí)候去讀數(shù)據(jù)。除了信號(hào)變化的那個(gè)沿的位置外,其它位置都很穩(wěn)定,那么我們現(xiàn)在就約定在信號(hào)中間位置去讀取電平狀態(tài),這樣能夠保證我們讀的一定是正確的。
一旦讀到了起始信號(hào),我們就把當(dāng)前狀態(tài)設(shè)定成接收狀態(tài),并且打開(kāi)定時(shí)器中斷,第一次是半個(gè)周期進(jìn)入中斷后,對(duì)起始位進(jìn)行二次判斷一下,確認(rèn)一下起始位是低電平,而不是一個(gè)干擾信號(hào)。以后每經(jīng)過(guò)1/9600秒進(jìn)入一次中斷,并且把這個(gè)引腳的狀態(tài)讀到RxdBuf里邊。等待接收完畢之后,我們?cè)侔堰@個(gè)RxdBuf加1,再通過(guò)TXD引腳發(fā)送出去,同樣需要先發(fā)一位起始位,然后發(fā)8個(gè)數(shù)據(jù)位,再發(fā)結(jié)束位,發(fā)送完畢后,程序運(yùn)行到while (PIN_RXD),等待第二輪信號(hào)接收的開(kāi)始。
11.5 UART串口通信的基本應(yīng)用
11.5.1 通信的三種基本類型
常用的通信從傳輸方向上可以分為單工通信、半雙工通信、全雙工通信三類。
單工通信就是指只允許一方向另外一方傳送信息,而另一方不能回傳信息。比如電視遙控器、收音機(jī)廣播等,都是單工通信技術(shù)。
半雙工通信是指數(shù)據(jù)可以在雙方之間相互傳播,但是同一時(shí)刻只能其中一方發(fā)給另外一方,比如我們的對(duì)講機(jī)就是典型的半雙工。
全雙工通信就發(fā)送數(shù)據(jù)的同時(shí)也能夠接收數(shù)據(jù),兩者同步進(jìn)行,就如同我們的電話一樣,我們說(shuō)話的同時(shí)也可以聽(tīng)到對(duì)方的聲音。
11.5.2 UART模塊介紹
IO口模擬串口通信,讓大家了解了串口通信的本質(zhì),但是我們的單片機(jī)程序卻需要不停的檢測(cè)掃描單片機(jī)IO口收到的數(shù)據(jù),大量占用了單片機(jī)的運(yùn)行時(shí)間。這時(shí)候就會(huì)有聰明人想了,其實(shí)我們并不是很關(guān)心通信的過(guò)程,我們只需要一個(gè)通信的結(jié)果,最終得到接收到的數(shù)據(jù)就行了。這樣我們可以在單片機(jī)內(nèi)部做一個(gè)硬件模塊,讓它自動(dòng)接收數(shù)據(jù),接收完了,通知我們一下就可以了,我們的51單片機(jī)內(nèi)部就存在這樣一個(gè)UART模塊,要正確使用它,當(dāng)然還得先把對(duì)應(yīng)的特殊功能寄存器配置好。
51單片機(jī)的UART串口的結(jié)構(gòu)由串行口控制寄存器SCON、發(fā)送和接收電路三部分構(gòu)成,先來(lái)了解一下串口控制寄存器SCON。如表11-1表11-2所示。
表11-1 SCON——串行控制寄存器的位分配(地址0x98、可位尋址)
表11-2 SCON——串行控制寄存器的位描述
前邊學(xué)了那么多寄存器的配置,相信SCON這個(gè)地方,對(duì)于大多數(shù)同學(xué)來(lái)說(shuō)已經(jīng)不是難點(diǎn)了,應(yīng)該能看懂并且可以自己配置了。對(duì)于串口的四種模式,模式1是最常用的,就是我們前邊提到的1位起始位,8位數(shù)據(jù)位和1位停止位。下面我們就詳細(xì)介紹模式1的工作細(xì)節(jié)和使用方法,至于其它3種模式與此也是大同小異,真正遇到需要使用的時(shí)候大家再去查閱相關(guān)資料就行了。
在我們使用IO口模擬串口通信的時(shí)候,串口的波特率是使用定時(shí)器T0的中斷體現(xiàn)出來(lái)的。在硬件串口模塊中,有一個(gè)專門的波特率發(fā)生器用來(lái)控制發(fā)送和接收數(shù)據(jù)的速度。對(duì)于STC89C52單片機(jī)來(lái)講,這個(gè)波特率發(fā)生器只能由定時(shí)器T1或定時(shí)器T2產(chǎn)生,而不能由定時(shí)器T0產(chǎn)生,這和我們模擬的通信是完全不同的概念。
如果用定時(shí)器2,需要配置額外的寄存器,默認(rèn)是使用定時(shí)器1的,我們本章內(nèi)容主要就使用定時(shí)器T1作為波特率發(fā)生器來(lái)講解,方式1下的波特率發(fā)生器必須使用定時(shí)器T1的模式2,也就是自動(dòng)重裝載模式,定時(shí)器的重載值計(jì)算公式為:
TH1 = TL1 = 256 - 晶振值/12 /2/16 /波特率
和波特率有關(guān)的還有一個(gè)寄存器,是一個(gè)電源管理寄存器PCON,他的最高位可以把波特率提高一倍,也就是如果寫PCON |= 0x80以后,計(jì)算公式就成了:
TH1 = TL1 = 256 - 晶振值/12 /16 /波特率
公式中數(shù)字的含義這里解釋一下,256是8位定時(shí)器的溢出值,也就是TL1的溢出值,晶振值在我們的開(kāi)發(fā)板上就是11059200,12是說(shuō)1個(gè)機(jī)器周期等于12個(gè)時(shí)鐘周期,值得關(guān)注的是這個(gè)16,我們來(lái)重點(diǎn)說(shuō)明。在IO口模擬串口通信接收數(shù)據(jù)的時(shí)候,采集的是這一位數(shù)據(jù)的中間位置,而實(shí)際上串口模塊比我們模擬的要復(fù)雜和精確一些。他采取的方式是把一位信號(hào)采集16次,其中第7、8、9次取出來(lái),這三次中其中兩次如果是高電平,那么就認(rèn)定這一位數(shù)據(jù)是1,如果兩次是低電平,那么就認(rèn)定這一位是0,這樣一旦受到意外干擾讀錯(cuò)一次數(shù)據(jù),也依然可以保證最終數(shù)據(jù)的正確性。
了解了串口采集模式,在這里要給大家留一個(gè)思考題?!熬д裰?12/2/16/波特率”這個(gè)地方計(jì)算的時(shí)候,出現(xiàn)不能除盡,或者出現(xiàn)小數(shù)怎么辦,允許出現(xiàn)多大的偏差?把這部分理解了,也就理解了我們的晶振為何使用11.0592M了。
串口通信的發(fā)送和接收電路在物理上有2個(gè)名字相同的SBUF寄存器,它們的地址也都是0x99,但是一個(gè)用來(lái)做發(fā)送緩沖,一個(gè)用來(lái)做接收緩沖。意思就是說(shuō),有2個(gè)房間,兩個(gè)房間的門牌號(hào)是一樣的,其中一個(gè)只出人不進(jìn)人,另外一個(gè)只進(jìn)人不出人,這樣的話,我們就可以實(shí)現(xiàn)UART的全雙工通信,相互之間不會(huì)產(chǎn)生干擾。但是在邏輯上呢,我們每次只操作SBUF,單片機(jī)會(huì)自動(dòng)根據(jù)對(duì)它執(zhí)行的是“讀”還是“寫”操作來(lái)選擇是接收SBUF還是發(fā)送SBUF,后邊通過(guò)程序,我們就會(huì)徹底了解這個(gè)問(wèn)題。
11.5.3 UART串口程序
一般情況下,我們編寫串口通信程序的基本步驟如下所示:
1、配置串口為模式1。
2、配置定時(shí)器T1為模式2,即自動(dòng)重裝模式。
3、根據(jù)波特率計(jì)算TH1和TL1的初值,如果有需要可以使用PCON進(jìn)行波特率加倍。
4、打開(kāi)定時(shí)器控制寄存器TR1,讓定時(shí)器跑起來(lái)。
這里還要特別注意一下,就是在使用T1做波特率發(fā)生器的時(shí)候,千萬(wàn)不要再使能T1的中斷了。
我們先來(lái)看一下由IO口模擬串口通信直接改為使用硬件UART模塊時(shí)的程序代碼,看看程序是不是簡(jiǎn)單了很多,因?yàn)榇蟛糠值墓ぷ饔布K都替我們做了。程序功能和IO口模擬的是完全一樣的。
當(dāng)然了,這個(gè)程序還是用在主循環(huán)里等待接收中斷標(biāo)志位和發(fā)送中斷標(biāo)志位的方法來(lái)編寫的,而實(shí)際工程開(kāi)發(fā)中,當(dāng)然就不能這么干了,我們也只是為了用直觀的對(duì)比來(lái)告訴同學(xué)們硬件模塊可以大大簡(jiǎn)化程序代碼,那么實(shí)際使用串口的時(shí)候就用到串口中斷了,來(lái)看一下用中斷實(shí)現(xiàn)的程序。請(qǐng)注意一點(diǎn),因?yàn)榻邮蘸桶l(fā)送觸發(fā)的是同一個(gè)串口中斷,所以在串口中斷函數(shù)中就必須先判斷是哪種中斷,然后再作出相應(yīng)的處理。
大家可以試驗(yàn)一下,看看是不是和前邊用IO口模擬通信實(shí)現(xiàn)的效果一致,而主循環(huán)卻完全空出來(lái)了,我們就可以隨意添加其它功能代碼進(jìn)去。
11.6 通信實(shí)例與ASCII碼
我們學(xué)習(xí)串口通信主要是要實(shí)現(xiàn)單片機(jī)和電腦之間的信息交互,可以用電腦控制單片機(jī)的一些信息,可以把單片機(jī)的一些信息狀況發(fā)給電腦上的軟件。下面我們就做一個(gè)簡(jiǎn)單的例程,實(shí)現(xiàn)單片機(jī)串口調(diào)試助手發(fā)送的數(shù)據(jù),在我們開(kāi)發(fā)板上的數(shù)碼管上顯示出來(lái)。
大家在做這個(gè)實(shí)驗(yàn)的時(shí)候,有個(gè)小問(wèn)題要注意一下。因?yàn)镾TC89C52下載程序是使用了UART串口下載,下載完程序后,程序運(yùn)行起來(lái)了,可是下載軟件最后還會(huì)通過(guò)串口發(fā)送一些額外的數(shù)據(jù),所以程序剛下載進(jìn)去不是顯示00,而可能是其他數(shù)據(jù)。大家只要把電源開(kāi)關(guān)關(guān)閉,重新打開(kāi)一次就好了。
細(xì)心的同學(xué)可能會(huì)發(fā)現(xiàn),在串口調(diào)試助手發(fā)送選項(xiàng)和接收選項(xiàng)處,還有個(gè)“字符格式發(fā)送”和“字符格式顯示”,這是什么意思呢?
先拋開(kāi)我們使用的漢字不談,那么我們常用的字符就包含了09的數(shù)字、AZ/a~z的字母、還有各種標(biāo)點(diǎn)符號(hào)等。那么在單片機(jī)系統(tǒng)里面我們?cè)趺磥?lái)表示它們呢?ASCII碼(American Standard Code for Information Interchange,即美國(guó)信息互換標(biāo)準(zhǔn)代碼)可以完成這個(gè)使命:我們知道,在單片機(jī)中一個(gè)字節(jié)的數(shù)據(jù)可以有0~255共256個(gè)值,我們?nèi)∑渲械?~127共128個(gè)值賦予了它另外一層涵義,即讓它們分別來(lái)代表一個(gè)常用字符,其具體的對(duì)應(yīng)關(guān)系如表11-3所示。
表11-3 ASCII碼字符表
這樣我們就在常用字符和字節(jié)數(shù)據(jù)之間建立了一一對(duì)應(yīng)的關(guān)系,那么現(xiàn)在一個(gè)字節(jié)就既可以代表一個(gè)整數(shù)又可以代表一個(gè)字符了,但它本質(zhì)上只是一個(gè)字節(jié)的數(shù)據(jù),而我們賦予了它不同的涵義,什么時(shí)候賦予它哪種涵義就看編程者的意圖了。ASCII碼在單片機(jī)系統(tǒng)中應(yīng)用非常廣泛,我們后續(xù)的課程也會(huì)經(jīng)常使用到它,下面我們來(lái)對(duì)它做一個(gè)直觀的認(rèn)識(shí),同學(xué)們一定要深刻理解其本質(zhì)。
對(duì)照上述表格,我們就可以實(shí)現(xiàn)字符和數(shù)字之間的轉(zhuǎn)換了,比如還是這個(gè)程序,我們發(fā)送的時(shí)候改成字符格式發(fā)送,接收還是用十六進(jìn)制接收,這樣接收和數(shù)碼管好做一下對(duì)比。
我們用字符格式發(fā)送一個(gè)小寫的a,返回一個(gè)十六進(jìn)制的0x61,數(shù)碼管上顯示的也是61,ASCII碼表里字符a對(duì)應(yīng)十進(jìn)制是97,等于十六進(jìn)制的0x61;我們?cè)儆米址袷桨l(fā)送一個(gè)數(shù)字1,返回一個(gè)十六進(jìn)制的0x31,數(shù)碼管上顯示的也是31,ASCII表里字符1對(duì)應(yīng)的十進(jìn)制是49,等于十六進(jìn)制的0x31。這下大家就該清楚了:所謂的十六進(jìn)制發(fā)送和十六進(jìn)制接收,都是按字節(jié)數(shù)據(jù)的真實(shí)值進(jìn)行的;而字符格式發(fā)送和字符格式接收,是按ASCII碼表中字符形式進(jìn)行的,但它實(shí)際上最終傳輸?shù)倪€是一個(gè)字節(jié)數(shù)據(jù)。這個(gè)表格,當(dāng)然不需要大家去記住,理解它,用的時(shí)候過(guò)來(lái)查就行了。
通信的學(xué)習(xí),不像前邊控制部分那么直觀了,通信部分我們的程序只能獲得一個(gè)結(jié)果,而其過(guò)程我們卻無(wú)法直接看到,所以慢慢的可能大家就會(huì)知道有示波器和邏輯分析儀這類測(cè)量?jī)x器。如果學(xué)校實(shí)驗(yàn)室或者公司里有示波器或者邏輯分析儀這類儀器,可以拿過(guò)來(lái)抓一下串口波形,直觀的了解一下。如果暫時(shí)還沒(méi)有這些儀器,先知道這么回事,有條件再說(shuō)。因?yàn)楣ぞ哳愒O(shè)備有的比較昂貴,有條件可以盡量使用學(xué)校或者公司的。在這里我用一款簡(jiǎn)易的邏輯分析儀把串口通信的波形抓出來(lái)給大家看一下,大家了解一下即可,如圖11-7所示。
圖11-7 邏輯分析儀串口數(shù)據(jù)示意圖
分析儀和示波器的作用,就是把通信過(guò)程的波形抓出來(lái)進(jìn)行分析。先大概說(shuō)一下波形的意思。波形左邊是低位,右邊是高位,上邊這個(gè)波形是電腦發(fā)送給單片機(jī)的,下邊這個(gè)波形是單片機(jī)回發(fā)給電腦的。以上邊的波形為例,左邊第一位是起始位0,從低位到高位依次是10001100,順序倒一下,就是數(shù)據(jù)0x31,也就是ASCII碼表里的‘1’。大家可以注意到分析儀在每個(gè)數(shù)據(jù)位都給標(biāo)了一個(gè)白色的點(diǎn),表示是數(shù)據(jù),起始位和無(wú)數(shù)據(jù)的時(shí)候都沒(méi)有這個(gè)白點(diǎn)。時(shí)間標(biāo)T1和T2的差值在右邊顯示出來(lái)是0.102ms,大概是9600分之一,稍微有點(diǎn)偏差,在容許范圍內(nèi)即可。通過(guò)圖11-7,我們可以清晰的了解了串口通信的收發(fā)的詳細(xì)過(guò)程。
那我們這里再來(lái)了解一下,如果我們使用串口調(diào)試助手,用字符格式直接發(fā)送一個(gè)“12”,我們?cè)谖覀兊臄?shù)碼管上應(yīng)該顯示什么呢?串口調(diào)試助手應(yīng)該返回什么呢?經(jīng)過(guò)試驗(yàn)發(fā)現(xiàn),我們數(shù)碼管顯示的是32,而串口調(diào)試助手返回十六進(jìn)制顯示的是31、32兩個(gè)數(shù)據(jù),如圖11-8所示。
圖11-8 串口調(diào)試助手?jǐn)?shù)據(jù)顯示
我們?cè)儆眠壿嫹治鰞x把這個(gè)數(shù)據(jù)抓出來(lái)看一下,如圖11-9所示。
圖11-9 邏輯分析儀抓取數(shù)據(jù)
對(duì)于ASCII碼表來(lái)說(shuō),數(shù)字本身是字符而非數(shù)據(jù),所以如果發(fā)送“12”的話,實(shí)際上是是分別發(fā)送了“1”和“2”兩個(gè)字符,單片機(jī)呢,先收到第一個(gè)字符“1”,在數(shù)碼管上會(huì)顯示出31這個(gè)對(duì)應(yīng)數(shù)字,但是馬上就又收到了“2”這個(gè)字符,數(shù)碼管瞬間從31變成了32,而我們視覺(jué)上呢,是沒(méi)有辦法發(fā)現(xiàn)這種快速變化的,所以我們感覺(jué)數(shù)碼管直接顯示的是32。
評(píng)論
查看更多