基本概念
本文將會(huì)采用由簡(jiǎn)入深的方式對(duì)串口開發(fā)進(jìn)行介紹,但是在步入正題前我們必須介紹接口技術(shù)的兩個(gè)重要概念—上位機(jī)、下位機(jī),因?yàn)檫@兩個(gè)概念非常的重要。
上位機(jī):也就是通信雙方較為主動(dòng)的一方,也稱為主機(jī),可以是兩臺(tái)電腦中的其中一臺(tái),可以是兩臺(tái)設(shè)備間的其中一臺(tái),也可以電腦與設(shè)備間的其中一臺(tái),關(guān)鍵是看哪一方處于比較主動(dòng)的位置。一般情況下是指電腦。
下位機(jī):是通信雙方相比而言處于較為被動(dòng)的一方,一般是指設(shè)備(例如單片機(jī)),也可以是某臺(tái)電腦。
這兩種稱謂是相對(duì)的,區(qū)分的方式是確定主動(dòng)方與被動(dòng)方。
下面將抽取一對(duì)典型的通信實(shí)體(類型-2),開始介紹串口通信的原理以及開發(fā)實(shí)例。
實(shí)例介紹:
對(duì)于類型-2,也即是電腦對(duì)電腦的通信方式,暫不涉及過(guò)多的硬件知識(shí)利于初學(xué)者入門。
電腦對(duì)電腦的串行連接一般使用串口數(shù)據(jù)線作為通信載體,串口數(shù)據(jù)線可以到市場(chǎng)購(gòu)買也可以自制。對(duì)于一些初學(xué)者來(lái)說(shuō),剛開始并沒(méi)有作好這方面的準(zhǔn)備,不過(guò)沒(méi)有關(guān)系,下面將分別介紹在沒(méi)有以及擁有串口數(shù)據(jù)線的情況下如何進(jìn)行串口方面的開發(fā)試驗(yàn)。
沒(méi)有串口數(shù)據(jù)線的情況;
有串口數(shù)據(jù)線,但是只有一臺(tái)擁有兩個(gè)串口的電腦。
開發(fā)環(huán)境的準(zhǔn)備:
本文采用VC++ 6.0作為開發(fā)環(huán)境,以后會(huì)增加VB、Dephi、C++ Builder等環(huán)境下的實(shí)例。操作系統(tǒng)為window 2000/XP/2003。
串口監(jiān)控工具推薦使用AccessPort或PortMon,這兩款軟件都是免費(fèi)的。本文以AccessPort為例進(jìn)行說(shuō)明。
串口操作的原理:
對(duì)串口的整個(gè)操作過(guò)程一般分為四個(gè)步驟:
1. 打開串口;
2. 設(shè)置串口參數(shù);
3. 讀、寫數(shù)據(jù);
4. 關(guān)閉串口。
所以,我們的開發(fā)也將圍繞這幾個(gè)步驟進(jìn)行。
實(shí)踐:
1. 沒(méi)有串口數(shù)據(jù)線的情況:
在這種情況下我們可以進(jìn)行往串口寫入數(shù)據(jù)的試驗(yàn),利用串口監(jiān)控工具驗(yàn)證數(shù)據(jù)是否真實(shí)的寫入指定串口。
啟動(dòng)VC++ 6.0,新建一個(gè)window32 控制臺(tái)類型的工程,名稱為ComTest1
確定之后進(jìn)入第二個(gè)步驟:
選中第二項(xiàng),然后結(jié)束,此時(shí)我們就創(chuàng)建了一個(gè)名為ComTest1的工程,里面只有一個(gè)空的main函數(shù)。
接下來(lái),我們將對(duì)串口進(jìn)行四項(xiàng)操作,打開串口,設(shè)置串口參數(shù),寫入數(shù)據(jù),關(guān)閉串口,代碼如下:
#include "stdafx.h"
#include
#include
int main(int argc, char* argv[])
{
//1.打開指定串口
HANDLE hComm = CreateFile("COM1", // 串口名稱(COMx)
GENERIC_READ | GENERIC_WRITE, // 串口屬性為可讀/寫
0, // 串口設(shè)備必須被獨(dú)占性的訪問(wèn)
NULL, // 無(wú)安全屬性
OPEN_EXISTING, // 串口設(shè)備必須使用OPEN_EXISTING參數(shù)
FILE_ATTRIBUTE_NORMAL, // 同步式 I/O
0); // 對(duì)于串口設(shè)備而言此參數(shù)必須為0
if (hComm == INVALID_HANDLE_VALUE)
{
//如果該串口不存在或者正被另外一個(gè)應(yīng)用程序使用,
//則打開失敗,本程序退出
return FALSE;
}
//2.設(shè)置串口參數(shù):波特率、數(shù)據(jù)位、校驗(yàn)位、停止位等信息
DCB dcb;
GetCommState(hComm, &dcb); //獲取該端口的默認(rèn)參數(shù)
//修改波特率
dcb.BaudRate = 115200;
//重新設(shè)置參數(shù)
SetCommState(hComm, &dcb);
//3.往串口寫數(shù)據(jù)
char lpBuffer[] = "Hello world!"; //將要寫入的數(shù)據(jù)
DWORD nNumberOfBytesToWrite = strlen(lpBuffer); //將要寫入的數(shù)據(jù)長(zhǎng)度
DWORD nBytesSent; //實(shí)際寫入的數(shù)據(jù)長(zhǎng)度
WriteFile(hComm, lpBuffer, nNumberOfBytesToWrite, &nBytesSent, NULL);
//4.關(guān)閉串口
CloseHandle(hComm);
return 0;
}
接下來(lái)我們將驗(yàn)證字符串”Hello world!”是否已經(jīng)寫入串口com1。啟動(dòng)AccessPort串口調(diào)試工具,選擇Monitor模式,然后選擇被監(jiān)控的串口com1,開始監(jiān)控;然后編譯并運(yùn)行我們的工程ComTest1,此時(shí)AccessPort攔截到的信息如下:
Port Opened - ComTest1.exe
Baud Rate: 115200
StopBits: 1, Parity: No, DataBits: 8
Length: 0012, Data: Hello world!
Port Closed
其中的信息與我們的工程ComTest1中的四個(gè)操作步驟一一對(duì)應(yīng),因此可以證明我們的第一個(gè)串口程序?qū)懭氲臄?shù)據(jù)是正確的。
2. 有串口數(shù)據(jù)線,但是只有一臺(tái)擁有兩個(gè)串口的電腦的情況
在這種情況下,我們將串口數(shù)據(jù)線把電腦的COM1與COM2連接起來(lái),啟動(dòng)AccessPort并選擇Terminal模式,設(shè)置COM2口的波特率為115200,無(wú)校驗(yàn)位、8個(gè)數(shù)據(jù)位、1個(gè)停止位,并打開該端口;然后運(yùn)行我們的ComTest1工程,接下來(lái)我們會(huì)看到按照十六進(jìn)制-字符串方式顯示的數(shù)據(jù),說(shuō)明ComTest1運(yùn)行正確,寫入com1的數(shù)據(jù)被轉(zhuǎn)發(fā)到了com2上,效果圖如下:
這僅僅是證明我們的ComTest1寫入成功,如果我們?cè)谠创aWriteFile函數(shù)之后加入如下代碼,就可以接收到AccessPort通過(guò)com2 發(fā)送到com1的數(shù)據(jù):
//讀串口數(shù)據(jù)
char lpReadBuf[1024] = { 0 }; //接收緩沖區(qū)長(zhǎng)度為1024,內(nèi)容都為0
DWORD nNumberOfBytesToRead = 1024; //最大讀取1024個(gè)字節(jié)
DWORD nBytesRead;
ReadFile(hComm, lpReadBuf, nNumberOfBytesToRead, &nBytesRead, NULL);
printf("Read Data: %s", lpReadBuf);
我們?cè)贑omTest1工程文件的 ReadFile(hComm, lpReadBuf, nNumberOfBytesToRead, &nBytesRead, NULL);以及return 0;這兩行按F9分別設(shè)置斷點(diǎn)并編譯運(yùn)行,接下來(lái)在AccessPort的數(shù)據(jù)發(fā)送區(qū)輸入字符串Test并發(fā)送,然后繼續(xù)運(yùn)行ComTest1至return 0;這一行,最后我們會(huì)看到運(yùn)行的結(jié)果如下:
這樣我們就完成了一個(gè)最簡(jiǎn)單的可進(jìn)行讀、寫操作的串口程序。通過(guò)上面的介紹,你會(huì)發(fā)現(xiàn)串口開發(fā)并不是什么難事。在我們接下來(lái)的系列文章中將會(huì)深入細(xì)致的介紹更多的內(nèi)容。