|
10.5使用邏輯分析儀測量串口通信 萬用表、示波器、邏輯分析儀是電子工程師常用的測量設(shè)備。萬用表主要用來測量電壓、電流等參數(shù),示波器通常用來測量模擬信號等信號質(zhì)量參數(shù),邏輯分析儀通常用來分析數(shù)字通信信號以及解析通信協(xié)議。對于串口通信這種數(shù)字通信,用邏輯分析儀可以清晰的測量出每一位的脈寬,波特率,還可以將串口通信數(shù)據(jù)直接解析出來,是數(shù)字信號分析利器。 下面使用Kingst品牌的 LA5016邏輯分析儀測量一下上一小節(jié)串口助手按照三種情況發(fā)送“31”后,單片機的RXD引腳接收到的波形數(shù)據(jù),以及TXD引腳發(fā)送出去的波形數(shù)據(jù),按照使用方法將邏輯分析儀的通道0和通道1分別接到單片機的RXD和TXD引腳上,GND接到單片機的GND插針上,測量到的波形如圖10-5所示,從圖上可以看到測量的單片機TXD發(fā)送引腳一個脈沖寬度大概是104.156us,9600波特率的一個位寬理論值是1/9600=104.166us。 圖10-5 邏輯分析儀信號測量圖 邏輯分析儀不僅僅可以測量波形的脈沖寬度,周期,占空比頻率這些信息,對于標(biāo)準(zhǔn)的通信協(xié)議,可以直接將波形解析出HEX格式,同時軟件右下角也可以顯示出解析后的數(shù)據(jù)。如圖10-6所示。從圖上還可以看出解析的過程中,有一個圓綠點表示串口起始位,白點表示數(shù)據(jù)位,方紅點表示停止位。
10-6 邏輯分析儀解析串口圖(一) 除了可以顯示成為十六進(jìn)制數(shù)據(jù),還可以顯示成其他格式。將第三次發(fā)送的“文本模式”下的“31”的發(fā)送和接收數(shù)據(jù)顯示格式,同時顯示HEX和ASCII格式,如圖10-7所示。 10-7 邏輯分析儀解析串口圖(二) 合理使用工具,可以將一些信號參數(shù)更加清晰直觀的展示出來,在項目開發(fā)過程中起到事半功倍的效果。 10.6 指針的概念與指針變量的聲明10.6.1變量的地址要研究指針,得先來深入理解內(nèi)存地址這個概念。打個比方:整個內(nèi)存就相當(dāng)于一個擁有很多房間的大樓,每個房間都有房間號,比如從101、102、103一直到NNN,可以說這些房間號就是房間的地址。相對應(yīng)的內(nèi)存中的每個單元也都有自己的編號,比如從0x00、0x01、0x02一直到0xNN,同樣可以說這些編號就是內(nèi)存單元的地址。房間里可以住人,對應(yīng)的內(nèi)存單元里就可以“住進(jìn)”變量了:假如一位名字叫A的人住在101房間,可以說A的住址就是101,或者101就是A的住址;對應(yīng)的,假如一個名為x的變量住在編號為0x00的這個內(nèi)存單元中,那么可以說變量x的內(nèi)存地址就是0x00,或者0x00就是變量x的地址。 基本的內(nèi)存單元是字節(jié),英文單詞為Byte,STC89C52單片機共有512字節(jié)的RAM內(nèi)存,它分為內(nèi)部256字節(jié)和外部256字節(jié),僅以內(nèi)部的256字節(jié)為例,很明顯其地址的編號從0開始就是0x00~0xFF。用C語言定義的各種變量就存在0x00~0xFF的地址范圍內(nèi),而不同類型的變量會占用不同數(shù)量的內(nèi)存單元,可以結(jié)合前面講過的C語言變量類型深入理解。假如現(xiàn)在定義了unsigned char a = 1; unsigned char b = 2; unsigned int c = 3; unsigned long d = 4; 這樣4個變量,把這4個變量分別放到內(nèi)存中,如表10-4所示。 變量a、b和c和d之間的變量類型不同,因此在內(nèi)存中所占的存儲單元也不一樣,a和b都占一個字節(jié),c占了2個字節(jié),而d占了4個字節(jié)。那么,a的地址就是0x00,b的地址就是0x01,c的地址就是0x02,d的地址就是0x04,它們的地址的表達(dá)方式可以寫成:&a,&b,&c,&d。這樣就代表了相應(yīng)變量的地址,C語言中變量前加一個&表示取這個變量的地址,&在這里就叫做“取址符”。 這里有一點延伸內(nèi)容,變量c是unsigned int類型的,占了2個字節(jié),存儲在了0x02和0x03這兩個內(nèi)存地址上,那么0x02是它的低字節(jié)還是高字節(jié)呢?這個問題由所用的C編譯器與單片機架構(gòu)共同決定,單片機類型不同就有可能不同。比如:在Keil+51單片機的環(huán)境下,0x02存的是高字節(jié),0x03存的是低字節(jié)。這是編譯底層實現(xiàn)上的細(xì)節(jié)問題,并不影響上層的應(yīng)用,如下這兩種情況在應(yīng)用上絲毫不受這個細(xì)節(jié)的影響:強制類型轉(zhuǎn)換——b = (unsigned char) c,那么b的值一定是c的低字節(jié);取地址——&c,則得到的一定是0x02,這都是C語言本身所決定的規(guī)則,不因單片機編譯器的不同而有所改變。 實際生活中要尋找一個人有兩種方式,一種方式是通過它的名字來找人,還有第二種方式就是通過它的住址來找人。在派出所的戶籍管理系統(tǒng)的信息輸入方框內(nèi),輸入小明的家庭住址,系統(tǒng)會自動指向小明的相關(guān)信息,輸入小剛的家庭住址,系統(tǒng)會自動指向小剛的相關(guān)信息。這個供輸入地址的方框,在戶籍管理系統(tǒng)叫做“地址輸入框”。 那么,在C語言中,要訪問一個變量,同樣有兩種方式:一種是通過變量名來訪問,另一種自然就是通過變量的地址來訪問了。在C語言中,地址就等同于指針,變量的地址就是變量的指針。要把地址送到上邊那個所謂的“地址輸入框”內(nèi),這個“地址輸入框”既可以輸入x的指針,又可以輸入y的指針,所以這個“地址輸入框”相當(dāng)于一個特殊的變量——保存指針的變量,因此稱之為指針變量,簡稱為指針,通常說的指針是指指針變量。 地址輸入框輸入誰的地址,指向的就是這個人的信息,而給指針變量輸入哪個普通變量的地址,它自然就指向了這個變量的內(nèi)容,通常的說法就是指針指向了該變量。 10.6.2 指針變量的聲明在C語言中,變量的地址往往都是編譯系統(tǒng)自動分配的,對用戶來說是不知道某個變量的具體地址的。所以定義一個指針變量p,把普通變量a的地址直接送給指針變量p就是p = &a;這樣的寫法。 對于指針變量p的定義和初始化,一般有兩種方式,這兩種方式初學(xué)者很容易混淆,死記硬背完全記住是最好的辦法。 方法1:定義時直接進(jìn)行初始化賦值。 unsigned char a; unsigned char *p = &a; 方法2:定義后再進(jìn)行賦值。 unsigned char a; unsigned char *p; p = &a; 這兩種寫法都是正確的。定義的指針變量前邊加了個*,這個*p就代表了這個p是個指針變量,不是個普通的變量,它是專門用來存放變量地址的。此外,定義*p的時候,用了unsigned char來定義,這里表示的是這個指針指向的變量類型是unsigned char型的。 指針變量比較好理解,但是為什么讀者還是學(xué)不好指針呢?在C語言中,有一些運算和定義是有區(qū)別的。重點強調(diào)兩個區(qū)別,只要把這兩個區(qū)別弄明白了,起碼指針變量這部分就不是問題了。這兩個重要區(qū)別也需要死記硬背記住。 第一個重要區(qū)別:指針變量p和普通變量a的區(qū)別。定義一個變量a,同時也可以給變量a賦值a = 1,也可以賦值a = 2。定義一個指針變量p,另外還定義了一個普通變量a=1,普通變量b=2,那么這個指針變量可以指向a的地址,也可以指向b的地址,可以寫成p = &a,也可以寫成p = &b,就是不能寫成p = 1或者p = 2或者p = a,這三種表達(dá)方式都是錯的。 因此這里不要看到定義*p的時候前邊有個unsigned char型,就錯誤的賦值p=1,這個只是說明p指向的變量是這個unsigned char類型的,而p本身,是指針變量,不可以給它賦值普通的值或者變量,后邊會直接把指針變量稱之為指針,要注意一下這個小細(xì)節(jié)。 第二個重要區(qū)別:定義指針變量*p和取值運算*p的區(qū)別。 “*”這個符號,在C語言有三個用法,第一個用法是乘法運算符號。 第二個用法,是定義指針變量的時候用的,比如unsigned char *p,這個地方使用“*”代表的意思是p是一個指針變量,而非普通的變量。 第三種用法,是取值運算,它和定義指針變量是完全兩碼事,比如: unsigned char a = 1; unsigned char b = 2; unsigned char *p; p = &a; b = *p; 這樣運算完之后,b的值為1。在這段代碼中,&a表示取a這個變量的地址,把這個地址送給p,再用*p運算是取指針變量p指向的地址的變量的值,把這個值送給b,結(jié)果相當(dāng)于b=a。同樣是*p,放在定義的位置就是定義指針變量,放在執(zhí)行代碼中就是取值運算。 10.6.3指針的簡單示例為了鞏固指針的用法,使用指針實現(xiàn)流水燈程序,從簡單程序開始了解指針。 這是一個使用指針實現(xiàn)流水燈的例子,純粹是為了講指針而寫這樣一段程序,程序中傳遞的是buf的地址,把這個地址直接傳遞給函數(shù)ShiftLeft的形參指針變量p,也就是p指向了buf。對比之前的函數(shù)調(diào)用有重大區(qū)別,如果是普通變量傳遞,只能單向的,也就是說,主函數(shù)傳遞給子函數(shù)的值,子函數(shù)只能使用卻不能改變。而現(xiàn)在傳遞的是指針,*p就是直接取了buf這個變量的值,并且將其進(jìn)行了修改。 再次強調(diào),只要是*p前邊帶了變量類型如unsigned char,就是表示定義了一個指針變量p,而執(zhí)行代碼中的*p,是指p所指向的內(nèi)容。 通過理論的學(xué)習(xí)和這樣一個例程對指針有一個初步的認(rèn)識,至于它的靈活應(yīng)用,需要在后邊的程序中慢慢去體會。 10.7 練習(xí)題1、能夠理解UART串口通信的基本原理和通信過程。 2、學(xué)會通過配置寄存器,實現(xiàn)串口通信的基本操作過程。 3、了解字符和數(shù)據(jù)之間的轉(zhuǎn)換依據(jù)和方法。 4、完成通過串口控制流水燈流動和停止的程序。 5、理解指針的基本概念。
|