新聞中心

EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計應(yīng)用 > PC與單片機(jī)RS-232串口的通訊和控制

PC與單片機(jī)RS-232串口的通訊和控制

作者: 時間:2016-12-03 來源:網(wǎng)絡(luò) 收藏
這次我們來試著一步步的去掌握PC單片機(jī)通過RS-232進(jìn)行通訊和控制

先說說我硬件的情況。我用的PC是個二手的IBM240小本本,十寸屏,賽揚(yáng)400,機(jī)子很老了。但也有它的優(yōu)點(diǎn):1、串口,并口,PS鼠標(biāo)口、USB口、PCM插槽全有。 調(diào)試硬件電路最好還是用真實串、并口好些,因為用USB轉(zhuǎn)換的串、并口有時會出現(xiàn)兼容性上的問題,就會增加你調(diào)試上的復(fù)雜性。

本文引用地址:http://butianyuan.cn/article/201612/325233.htm

下圖為本人的IBM 240及各種接口圖:


下圖是PC的大小對比圖

單片機(jī)還是我一步步做出來的那個了,USB-ISP編程線也是我前面秀過,好!現(xiàn)在我放上PC與單片機(jī)連接圖:

用本本的好處就是調(diào)整方便,接口、器件都在旁邊,假若是用臺式機(jī),你還得鉆到桌子底下去插拔那些接口,而現(xiàn)在本本卻又沒有串、并口了。
言歸正傳,單片機(jī)的RS-232串口通過9針串口線接到本本的串口上,單片機(jī)的ISP編程口通過USB-ISP編程器接到本本的USB口。

另外本本要接電源,單片機(jī)也要接5V電源,還有千萬千要記得,本本是要插上鼠標(biāo)才玩得轉(zhuǎn)哦!

我將這個一步一步掌握串口的通訊與控制分為五步:

1、測試單片機(jī)與PC的串口連接是否正確好用。

2、用VB自己編寫的程序替換掉串口調(diào)試器軟件來接收單片機(jī)發(fā)送的數(shù)據(jù)。

3、掌握單片機(jī)端如何發(fā)送字符和數(shù)值數(shù)據(jù)。

4、掌握PC端程序如何接收發(fā)送字符和數(shù)值型數(shù)據(jù)。

5、做一個A/D轉(zhuǎn)換(ADC0809)獲取數(shù)據(jù)發(fā)送到PC,并在PC上顯示實時趨勢的例子。

我們要用到的四個軟件:

1、USB接口編程軟件:是PC機(jī)給單片機(jī)進(jìn)行燒寫編程用的

2、串口調(diào)試軟件:用來測試單片機(jī)內(nèi)串口電路、程序工作是否正常。

3、單片機(jī)程序的編程軟件KEIL:用于編寫單片機(jī)內(nèi)的程序并生成HEX文件。

4、VB6.0:用于編寫PC機(jī)上的應(yīng)用程序

先進(jìn)行第一步工作:

在前面一篇《板子上最一個部件——RS232串口》講過如何對單片機(jī)上的串口進(jìn)行調(diào)試,我們還是先對這個連接進(jìn)行測試,我們首先得確認(rèn)連接正確,電路正常,才能進(jìn)行后面程序編寫和調(diào)試工作。
  依舊是那個最簡單的程序,AT89S52從串口不停地發(fā)送“hello world!”

#include
#include
void main(void)
{
SCON=0x50; //串口方式1
TMOD=0x20; //定時器1,定時方式為2
PCON=0x80; //設(shè)定串口工作方式為1
TCON=0x40; //設(shè)定時器1開始計數(shù)
TH1=0xfd; //設(shè)定波特率為19200
TL1=0xfd; //
TI=1;
TR1=1; //啟動定時器
while(1)
{
printf("hello world!n");
}
}

把原先生成好的這個HEX文件用上面講到的Progisp軟件寫到AT89S52里。

然后打開sscom32串口調(diào)試器,設(shè)定好串口號、波特率和數(shù)據(jù)位,按下“打開串口”鈕,應(yīng)該就能收到那個一行行的“hello world!”了。能看到這一行行的文字,說明電路、連接和程序都正常了。

如果是亂碼,則要將單片機(jī)上的復(fù)位鈕按一下。如果還是亂碼,那一般就是波特率不對,晶振應(yīng)為11.0592MHZ或串口接觸不良,線過長等原因。如果跟本就收不到任何字符,就說明電路或連接有故障,或者程序有問題。那就要好好查查了。
  好!現(xiàn)在電路、連接、程序都可以正常工作。但在串口調(diào)試器接收框里看到接收到的一行行“hello world!”顯示太快,不容易看出它一次一次發(fā)送的過程,不便于分析問題,我們得給它加點(diǎn)延時。

#include
#include

void delay(void) //定義一個延時子程序
{
unsigned int i;
for (i=65535;i>0;i--);
}

void main(void) //主程序
{
SCON=0x50; //串口方式1
TMOD=0x20; //定時器1,定時方式為2
PCON=0x80; //設(shè)定串口工作方式為1
TCON=0x40; //設(shè)定時器1開始計數(shù)
TH1=0xfd; //設(shè)定波特率為19200
TL1=0xfd; //
TI=1;
TR1=1; //啟動定時器
while(1)
{
printf("hello world!n"); //向串口送出數(shù)據(jù)
delay(); //調(diào)用延時
delay();
}

}

程序?qū)懞昧?,在KEIL里添加上延時語句后,重新生成HEX文件。再用Progisp將它寫進(jìn)AT89S52里,這時,你就可以看到串口調(diào)試器已經(jīng)接收到大約一秒一次的“Hello world!”了。
  在這里說明一下,只要像最上面我圖上給出的那樣把單片機(jī)和PC連接好后,無論你往AT89S52里燒寫程序,還是單片機(jī)連接到PC并向PC串口發(fā)送數(shù)據(jù),都不用再插拔器件了,只需要在這幾個程序間切換工作便可以了。(是不是很方便呢


這樣第一項工作就完成了,確認(rèn)電路的連接及單片機(jī)程序都工作正常。


下面要進(jìn)行第二項工作:

目的:用我自己的PC程序把串口調(diào)試器軟件替換掉。因為我最終要的是接收單片機(jī)上的數(shù)據(jù),并將接收的數(shù)據(jù)在PC上進(jìn)行處理、存儲,而串口調(diào)試器只能接收固定的內(nèi)容,你也不無法把收到的數(shù)據(jù)接管過來,僅僅能做連接測試而已。

我用的是最簡單易用的Visual Basic 6.0。具體如何操作運(yùn)用,網(wǎng)上有很多教程,也很容易上手。

打開VB6.0,新建一個工程,也就是要建立一個新的程序。

這是個標(biāo)準(zhǔn)的VB6.0界面,我們要進(jìn)行串口的操作需要添加一個串口控件MSCOMM32.OCX,或許你的機(jī)子上有,也許沒有,沒有的在網(wǎng)上搜了下一個裝在你c:winntsystem32 。然后你用鼠標(biāo)右鍵點(diǎn)擊VB界面左側(cè)的工具箱,彈出菜單后選部件,或者在上部的主菜單上點(diǎn)“工程”--“部件”,就會彈出如下界面:

在列出的項里找到Microsoft Comm Control 6.0。在前面的小方框里點(diǎn)上鉤。注意看下面的提示欄里就告訴你這個控件的文件名和所在的目錄。點(diǎn)“確定”鈕,這時在VB主界面的工具箱里就會多出個小電話的控件圖標(biāo)了:

接下來點(diǎn)擊這個控件圖標(biāo),然后在Form1的窗口上拉出個框(或者雙擊小電話圖標(biāo))把圖標(biāo)放到Form1窗口上去。如下圖:

如果你的圖標(biāo)放不上去并彈出如下提示框:

就說明你的VB6.0是簡化版,不是正式安裝的。解決方法如下:
首先把MSComm32.OCX拷進(jìn)C:WINNTSYSTEM32 (我的機(jī)器一開始并沒有這個控件,我去網(wǎng)上下了一個,機(jī)器里面有此控件的此步不做?。ㄗⅲ郝窂揭晕覚C(jī)器的winXP系統(tǒng)為例)
然后點(diǎn)擊 開始>運(yùn)行>regsvr32 c:winntsystem32mscomm32.ocx 成功后,開始>運(yùn)行>regedit,進(jìn)入注冊表,找到HKEY_CLASSES_ROOTLicenses,然后新建一個項,命名為:“4250E830-6AC2-11cf-8ADB-00AA00C00905”,值為:“kjljvjjjoquqmjjjvpqqkqmqykypoqjquoun”。一切就OK了。

VB6.0設(shè)置正常后,我由簡入繁地進(jìn)行程序的編寫。在窗體上先放上一個串口控件,一個文本框,一個按鈕,一個定時器。如下圖:

串口控件是單片機(jī)串口和PC串口進(jìn)行通訊的橋梁;文本框用來顯示我們收到的數(shù)據(jù),按鈕用來啟動這個接收,定時器用來定時檢查每一小段時間檢查是否有串口數(shù)據(jù)收到。
我們先對串口控件進(jìn)行屬性設(shè)置,Commport是串口號設(shè)置,一般設(shè)置為1,Settings是對串口的波特率、有無奇偶校驗,數(shù)據(jù)位數(shù),停止位數(shù)進(jìn)行設(shè)置,因為我的單片機(jī)程序上用的波特率是19200,所以在這兒我只對波特率進(jìn)行調(diào)整,其它都是都用默認(rèn)值。如下圖:

對按鈕控鍵進(jìn)行設(shè)置:只是將“Caption”標(biāo)題屬性改為“接收數(shù)據(jù)”。
對定時器進(jìn)行設(shè)置,將“Interval”間歇時間改為400。這樣就是每400毫秒檢查一次有無數(shù)據(jù)收到。
對文本框進(jìn)行設(shè)置:將“MultiLine”多行顯示設(shè)為“True”允許。
控件的屬性設(shè)置完了,下面我們?yōu)槌绦驅(qū)懘a,先雙擊“接收數(shù)據(jù)”按鈕。會彈出代碼窗口,我了如下代碼,如圖:

上面就是我們編寫的按鈕事件代碼。寫完后我們在鍵盤上按“Shift”+“F7”,回到對象窗口。再雙擊那個定時器控件,界面就切換到定時器的代碼窗口,我們寫程序如下圖:

現(xiàn)在我們的這個VB程序就寫好了。接著就試著運(yùn)行一下這個程序,且慢!我們還是要先啟動串口調(diào)試器看看單片機(jī)是否還在不斷的發(fā)送著“hello world!”,確認(rèn)它還是在不停地顯示著那行“hello world!”,就可以關(guān)了串口調(diào)試器。然后在VB6.0的主界面點(diǎn)擊那個小三角的播放鈕。我的程序就運(yùn)行如下了:

第二項任務(wù)完成!我自己接管了接收的數(shù)據(jù)。點(diǎn)菜單的保存這項工程。

第三項任務(wù):掌握單片機(jī)端如何發(fā)送字符和數(shù)值數(shù)據(jù)。

接下來我要做的是對AT89S52內(nèi)串行數(shù)據(jù)的發(fā)送進(jìn)行解和掌握,以便我們能隨心所欲地將單片機(jī)獲得的數(shù)值數(shù)據(jù)或字符數(shù)據(jù)發(fā)送給PC機(jī)進(jìn)行處理或存儲。

先來看看原來我寫的AT89S52不斷發(fā)送“hello world!”的那段程序。

#include
#include
void delay(void) //定義一個延時子程序
{
unsigned int i;
for (i=65535;i>0;i--);
}

void main(void) //主程序
{
SCON=0x50; //串口方式1
TMOD=0x20; //定時器1,定時方式為2
PCON=0x80; //設(shè)定串口工作方式為1
TCON=0x40; //設(shè)定時器1開始計數(shù)
TH1=0xfd; //設(shè)定波特率為19200
TL1=0xfd; //
TI=1;
TR1=1; //啟動定時器
while(1)
{
printf("hello world!n"); //向串口送出數(shù)據(jù)
delay(); //調(diào)用延時
delay();
}

}

上面的程序中除了設(shè)置串口的語句和延時語句外,負(fù)責(zé)向串口發(fā)送的語句只有一行,即“printf("helleo world!n")”。學(xué)習(xí)過編程的一般都知道,print語句的作用是輸出字符串的,但我們?nèi)绻麖膯纹瑱C(jī)的A/D模塊上獲得了數(shù)據(jù)想發(fā)送到PC,應(yīng)該怎么做呢?雖然你也可以先將這些數(shù)據(jù)轉(zhuǎn)換成數(shù)字字符串,例如我們從一個8位的A/D模塊上獲得的數(shù)據(jù)是個數(shù)值從0-255的8位的數(shù)值,如果數(shù)值是1,那你得先將1這個數(shù)值轉(zhuǎn)換成“1”字符對應(yīng)的代碼49(二進(jìn)制110001,十六進(jìn)制31H),再用printf語句發(fā)送出去。如果值是255,那你得先把它轉(zhuǎn)換成3個字符“2”、“5”、“5”,再用printf發(fā)送出去。但這樣既復(fù)雜又不規(guī)范,“1”是一個字符,“2”、“5”、“5”是三個字符,隨著數(shù)值的不同,發(fā)送的數(shù)據(jù)的字節(jié)數(shù)據(jù)也不同,這樣可不行。

我們還是先蹲蹲馬步,了解一下單片機(jī)串口發(fā)送數(shù)據(jù)的實質(zhì):

上圖是串口的發(fā)送時序示意圖,最上面的TX表示的是單片機(jī)串口的發(fā)送線,,第二根CLK是內(nèi)部時鐘線,最下面的是發(fā)送標(biāo)志信號TI。

我們以最常用的串行方式1,即10位異步通信方式來簡單分析一下。它規(guī)定了1位起始位、8位數(shù)據(jù)位和1位停止位。其中第一位(起始位)和最后一位(停止位)是在你設(shè)定好串口的方式,打開串口后由芯片內(nèi)串口模塊自動插入的,不用人為加。

當(dāng)你想通過串口發(fā)送數(shù)據(jù)時,只需要向AT89S52內(nèi)的一個8位的特殊功能寄存器SBUF(99H)送入一個字節(jié)你想要發(fā)送給PC的數(shù)據(jù),它就會自動連同起始位,數(shù)據(jù)位,停止位一起產(chǎn)生10位串行的電位信號送出。在第10個脈沖后將TX線的電位拉高,同時將標(biāo)志位TI置1,告訴自己的程序發(fā)送結(jié)束。

接收方也是以規(guī)定好的相同的波特率時鐘脈沖為基準(zhǔn),當(dāng)某一個脈沖到來后檢測到RX線上的電位被拉低,就知道對方開始發(fā)送數(shù)據(jù)了,然后從下一個脈沖起計數(shù)并在每個脈沖后檢查RX線上的電位,若是高電位便記做1,低電位便記做0,如此得到8個位的數(shù)據(jù),然后在第10個脈沖后,檢測到RX線上的電位為1就知道這幀數(shù)據(jù)傳送完畢。(注意:單片機(jī)的串行發(fā)送口(TX)和PC的接收口(RX)是通過串行線直接連接的,所以這兩點(diǎn)的信號是相同的)

例如要發(fā)送“1”這個字符,代碼是49(二進(jìn)制110001,十六進(jìn)制31H),串口發(fā)送時低位在前,如下圖

歸納起來,若想發(fā)送數(shù)據(jù)只要向SBUF送一個字節(jié)的數(shù)據(jù),然后等TI變?yōu)?后,就再發(fā)第二個字節(jié)依,此類推。

再說說字符和數(shù)值的關(guān)系,對于電路來說,它不知道什么是字符,什么是數(shù)值,只是按高低電位發(fā)送一幀幀的電信號。例如00000000代表0(00H),10101010代表170(AAH),11111111代表255(FF),但對于接收方PC就有不同了,大家都知道,電腦下載文本比下載一幅圖像的數(shù)據(jù)量要小得多,原因就是文本只是用一個代碼來代表一個將要顯示的文字圖像,而這個文字的圖像數(shù)據(jù)就預(yù)先存在自己的電腦里,就是所說的字庫。而你下載一幅圖像,則需要每一個陣點(diǎn)的數(shù)據(jù)都得傳送,所以數(shù)據(jù)量很大。西文也是一樣的,也是用代碼來代表一個需要顯示的西文字符圖像,這就是ACSII碼。這樣用一個字節(jié)的數(shù)(0-255)的范圍就能代表所有的西文字符和常用符號了,例如用數(shù)值65(十六進(jìn)制為41H)代表“A”。用數(shù)值49(十六進(jìn)制為31H)代表“1”,我只要向SBUF里輸入值65,PC只要以字符方式接收,就會顯示“A”字。如果以數(shù)值方式接收,變量的值就是65。這里面也包括有一些非字符的功能控制符號。例如13代表回車,10代表換行。

下面我們就來試試改寫一下發(fā)送程序:試著用送數(shù)值和送字符兩種方式發(fā)送。同樣是“A”“B”“C”“D”四個字符。

#include
#include
void delay(void) //定義一個延時子程序
{
unsigned int i;
for (i=65535;i>0;i--);
}

void main(void) //主程序
{
SCON=0x50; //串口方式1
TMOD=0x20; //定時器1,定時方式為2
PCON=0x80; //設(shè)定串口工作方式為1
TCON=0x40; //設(shè)定時器1開始計數(shù)
TH1=0xfd; //設(shè)定波特率為19200
TL1=0xfd; //
TI=1;
TR1=1; //啟動定時器
while(1)
{

SBUF=65; //向SBUF內(nèi)寫入65的數(shù)值,也就是字符“A”的代碼

while(TI==0); //檢測TI,當(dāng)TI=0時,說明還沒發(fā)送完,就循環(huán)等待。

TI=0; //當(dāng)TI=1時,就把TI的值置0,以便下一組發(fā)送。

SBUF=66; //向SBUF送數(shù)值66.即字符“B”的代碼

while(TI==0);

TI=0;

SBUF=C; //向SBUF送字符“C”

while(TI==0);

TI=0;

SBUF=D"; //向SBUF送字符“D”

while(TI==0);

TI=0;

delay(); //調(diào)用延時
delay();
}

}

將程序編譯生成HEX文件后寫入AT89S52。打開我上面用VB6編好那個程序,點(diǎn)擊“接收數(shù)據(jù)”鈕。如下圖:

它的確按我預(yù)想的執(zhí)行了。只要是節(jié)字?jǐn)?shù)據(jù),無論是數(shù)值還是字符代友都是可以進(jìn)行發(fā)送的。這是C語言的優(yōu)點(diǎn)。

另外我們順便看一下原先用printf函數(shù)發(fā)送生成HEX和直接寫SBUF來成HEX的差別:


上圖的提示顯示了生成的代碼共用了1120個字節(jié)。這是用printf函數(shù)發(fā)送的。

下圖是直接寫SBUF后的編譯提示信息:

哈!直接操作串口緩沖寄存器只用了89個字節(jié)。這是直接進(jìn)行底層操作的優(yōu)勢。

上面的程序發(fā)送“A”“B”“C”“D”四個數(shù)據(jù),因為沒有發(fā)送回車符,所以一次次的字符都是連續(xù)顯示的。我們再修改一下,把要發(fā)送的ABCD這四個數(shù)據(jù)再加兩個代表回車的控制字符數(shù)據(jù)定義到一個字節(jié)數(shù)組中變量中,再改用循環(huán)的方式來發(fā)送,程序如下:

#include
#include
void delay(void) //定義一個延時子程序
{
unsigned int i;
for (i=65535;i>0;i--);
}

void main(void)
{
unsigned char buf[ ]={65,66,C,D,13,10}; //定義一個單字節(jié)數(shù)組最后兩個數(shù)值13和10是回車符。
unsigned char i;
SCON=0x50; //串口方式1
TMOD=0x20; //定時器1,定時方式為2
PCON=0x80; //設(shè)定串口工作方式為1
TCON=0x40; //設(shè)定時器1開始計數(shù)
TH1=0xfd; //設(shè)定波特率為19200
TL1=0xfd; //
//TI=1;
TR1=1; //啟動定時器
while(1)
{
for(i=0;i<6;i++)
{
SBUF=buf[i]; //向串口送出數(shù)據(jù)
while(TI==0);
TI=0;
}
delay(); //調(diào)用延時
delay();
}

}

下面是運(yùn)行結(jié)果:


這樣就和原先printf函數(shù)輸出的效果一樣了。

從上面程序我們知道了,如果我們想發(fā)送測量的數(shù)值數(shù)據(jù),可以把用A/D模塊獲得的測量數(shù)據(jù)賦給buf[ ]數(shù)組里的變量,然后就可以進(jìn)行發(fā)送處理了。字符直接用上面的發(fā)送方法就行了。

這樣第三項工作也完成?。ò。±哿?,要歇歇,歇歇!

第四步:掌握PC端程序如何接收發(fā)送字符和數(shù)值型數(shù)據(jù)。

接下來我們來看看PC端的程序如何正常接收并處理收到的數(shù)據(jù)。字符沒有問題,因為剛才就是顯示的字符,但我主要是想看看采用字符方式接收對于0-255范圍內(nèi)那些非字符數(shù)值能否正常接收和處理。
打開VB6,調(diào)出我們原先編寫的程序,在串口控件的屬性中有個InputMode屬性,如果是0就是以字符方式接收,如果是1就是以二進(jìn)制方式接收。

原先我們就是用了缺省的字符方式。為了便于分析收到的數(shù)據(jù),我們得分別修改一下單片機(jī)和PC里的程序,首先不能讓單片機(jī)不停的發(fā)送,而是從PC機(jī)先向AT89S52發(fā)送一個字符“s”,AT89S52收到并確認(rèn)是“s”字符后再發(fā)送一組數(shù)據(jù),發(fā)完后停下,等待PC的下次請求。這樣我們可以準(zhǔn)確和穩(wěn)定地看到這組數(shù)據(jù)的情況。

VB程序的修改如下:

我們在Command1+_Click事件的代碼里添加了一行MSComm1.Output="s",也就是每當(dāng)我按下“接收數(shù)據(jù)”鈕時向AT89S52發(fā)送了一個"s"字符,然后清空文本框內(nèi)容,然后啟動定時器子程序Timer1每100毫秒檢查一次有無收到數(shù)據(jù),收到數(shù)據(jù)便顯示出來。

對AT89S52內(nèi)的程序做修改,程序循環(huán)檢查有無收到數(shù)據(jù),當(dāng)?shù)腞I=1時便有數(shù)據(jù)收到,確認(rèn)收到的數(shù)據(jù)為字符“s”時,便送出數(shù)組內(nèi)數(shù)據(jù)。修改程序如下:
#include

void delay(void) //定義一個延時子程序
{
unsigned int i;
for (i=65535;i>0;i--);
}

void main(void)
{
unsigned char buf[]={65,66,C,D,E,F};//定義一個單字節(jié)數(shù)組
unsigned char i;
SCON=0x50; //串口方式1
TMOD=0x20; //定時器1,定時方式為2
PCON=0x80; //設(shè)定串口工作方式為1
TCON=0x40; //設(shè)定時器1開始計數(shù)
TH1=0xfd; //設(shè)定波特率為19200
TL1=0xfd; //
//TI=1;
TR1=1; //啟動定時器
while(1)
{ if(RI==1) //如果接收到數(shù)據(jù)則進(jìn)入以下操作
{if(SBUF==s) //如果收到的數(shù)據(jù)為“s”字符則進(jìn)入發(fā)送操作
{
   for(i=0;i<6;i++)//循環(huán)發(fā)送出數(shù)組buf[ ]的6個數(shù)據(jù)
{
SBUF=buf[i]; //向串口送出數(shù)據(jù)
while(TI==0);
TI=0;
delay(); //調(diào)用延時子程序
}
RI=0;//上面的發(fā)送操作完畢后將標(biāo)志RI清0等待PC下次請求
}
}
}
}
編譯、生成HEX文件然后將文件寫進(jìn)AT89S52。我們運(yùn)行VB6編寫的Scom1程序。

現(xiàn)在我點(diǎn)擊“接收數(shù)據(jù)”鈕后,文本框內(nèi)一個字符一個字符的依次顯示出“ABCDEF”如下圖:


當(dāng)我再次點(diǎn)擊“接收數(shù)據(jù)”鈕時,文本框先清空,然后再重復(fù)上面的顯示。達(dá)到我們的要求。PC機(jī)每請求一次,單片機(jī)就發(fā)送一次數(shù)據(jù)。


接下來我要做的是讓文本框里不再顯示“ABCDEF”這幾個字符,而是要顯示AT89S52發(fā)過來的數(shù)值,例如我發(fā)送65的值,文本框里就顯示65,我發(fā)送255,文本框就顯示255,這樣我就能測試出用字符接收的方法能否將一個字節(jié)的值(0-255)都能正確接收和顯示。我們把那句Text1.Text = Text1.Text + MSComm1.Input 。改成Text1.Text = Text1.Text + str(asc(MSComm1.Input )),就是把原先字符串變量MSComm1.Input先轉(zhuǎn)換成ASCII值,再把這個值顯示出來。改完了。我們運(yùn)行下試試。


上圖顯示的確可以正確顯示出數(shù)值,但這僅僅只是有相對應(yīng)字符幾個代碼數(shù)值,我再來試試,非字符的ASCII值,看是否都能正確收到并顯示。先修改AT89S52里我們原先發(fā)送的那些數(shù)組buf[ ]里的值,讓它們部分不在字符范圍里,看能不能正確接收到顯示。我們將數(shù)組unsigned char buf[]={65,66,C,D,E,F};改寫為既有字符也有非字符范圍的數(shù)組unsigned char buf[]={0,1,2,D,254,255};


從上圖來看,后兩個數(shù)據(jù)顯示不對,254沒有顯示出來,255顯示為63,經(jīng)過修改AT89S52程序,把0-255的數(shù)值都發(fā)送一遍,發(fā)現(xiàn)大于128的數(shù)值幾乎都不能正確接收。所以,得出結(jié)論:以字符方式接收數(shù)值數(shù)據(jù)是不可行的!

如下圖:


接下來我改變串口控件的InputMode屬性,將它的值改為1,即用二進(jìn)制讀取來試試。但二進(jìn)制方式怎么讀取呢,看了很多資料,也試了很多次,終于弄明白了,原來先要定義一個字節(jié)型的可變數(shù)組,這樣當(dāng)接收到數(shù)據(jù)時把接收到的一個或多個數(shù)值的首地址變量Mscomm1.input賦給這個字節(jié)數(shù)組名。于是你就可以運(yùn)用這個字節(jié)數(shù)組里的變量了。

我先在VB里修改串口控件的InputMode屬性,如下圖:

然后我要在VB程序里先定義一個單字節(jié)Byte類型的數(shù)組,將收到的數(shù)據(jù)變量(Mscomm1.Input)賦給inbuff這個數(shù)組名,程序修改如下圖:

AT89S52里程序,基本不動,只是等待PC機(jī)發(fā)來請求字符“s”。收到請求后,發(fā)送0-255的全部數(shù)值。
修改的程序如下:

#include

void delay(void) //定義一個延時子程序
{
unsigned int i;
for (i=15535;i>0;i--);
}

void main(void)
{
unsigned char buf[]={3,4,5,D,255,253};//定義一個單字節(jié)數(shù)組
unsigned char i;
SCON=0x50; //串口方式1
TMOD=0x20; //定時器1,定時方式為2
PCON=0x80; //設(shè)定串口工作方式為1
TCON=0x40; //設(shè)定時器1開始計數(shù)
TH1=0xfd; //設(shè)定波特率為19200
TL1=0xfd; //
//TI=1;
TR1=1; //啟動定時器
while(1)
{ if(RI==1) //如果接收到數(shù)據(jù)則進(jìn)入以下操作
{if(SBUF==s) //如果收到的數(shù)據(jù)為“s”字符則進(jìn)入發(fā)送操作
{for(i=0;i<255;i++)//循環(huán)發(fā)送出數(shù),這里做為調(diào)試,我們先發(fā)0-255的數(shù)值。

{
SBUF=i; //向串口送出數(shù)據(jù),這里不發(fā)buf [ ]數(shù)組的數(shù)據(jù),而是直接發(fā)送循環(huán)體里的i 值(0-254)。
while(TI==0);
TI=0;
delay(); //調(diào)用延時
}

SBUF=255; //上面循環(huán)里沒有包括255這個值,這里補(bǔ)發(fā)送一次

while(TI==0);
TI=0;
RI=0;//發(fā)送完畢將收到請求標(biāo)志清0等待PC下次請求
}
}
}

}

顯示結(jié)果如下:

這樣,所有的數(shù)值都是可以正確接收并顯示了。

結(jié)論:要接收數(shù)值數(shù)據(jù),串口控件必須修改為二進(jìn)制的接收屬性。即:InputMode=1



評論


技術(shù)專區(qū)

關(guān)閉