關(guān)于VC++通信串口編程

姓名:莫益彰

學(xué)號:16030140019

【嵌牛導(dǎo)讀】:串口通信是指外設(shè)和計算機間,通過數(shù)據(jù)信號線 、地線、控制線等,按位進行傳輸數(shù)據(jù)的一種通訊方式。這種通信方式使用的數(shù)據(jù)線少,在遠距離通信中可以節(jié)約通信成本,但其傳輸速度比并行傳輸?shù)汀?/p>

【嵌牛鼻子】:VC++,串口通信原理

【嵌牛提問】:串口是什么,它的操作有哪些?

【嵌牛正文】:

總結(jié)來看串口通信原理,(也可以說大多數(shù)通信原理也是如此)。

通信首先要有個通信,可以簡單的把通信看成一個小桶,發(fā)送方住水桶里裝水,接收方從水桶中取水。如果你要和對方通信首先需要將桶蓋打開,再將水裝入到桶中,這時接收方才能夠從桶中取到水。這里就存在著一定的問題,

1,如果桶蓋還沒有打開,發(fā)送方已經(jīng)發(fā)送了。這時接收方再從桶中取水,肯定取的水不對,會不一部分缺失了。解決方式就是讓桶蓋打開再往其中加水。

2,但是桶蓋何時打開,發(fā)送方何時發(fā)送,這個不好把握。解決方法:接收方接到數(shù)據(jù)時,要返回一個應(yīng)答標志,告訴發(fā)送方我已經(jīng)取到數(shù)據(jù)了,而且是取得到正確數(shù)據(jù)才應(yīng)答,否則不理會,繼續(xù)取數(shù)據(jù)。或者一直查詢,直到與發(fā)送方發(fā)來的數(shù)據(jù)一致再停止取數(shù)據(jù)。

一般的,進行串口通信總有一個是主動方一個是被動方,而且二者傳輸數(shù)據(jù)時,會有一定的協(xié)商好的數(shù)據(jù)格式,二者發(fā)送接收都按照此數(shù)據(jù)格式進行。

在工業(yè)控制中,工控機(一般都基于Windows平臺)經(jīng)常需要與智能儀表通過串口進行通信。串口通信方便易行,應(yīng)用廣泛。

一般情況下,工控機和各智能儀表通過RS485總線進行通信。RS485的通信方式是半雙工的,只能由作為主節(jié)點的工控PC機依次輪詢網(wǎng)絡(luò)上的各智能控制單元子節(jié)點。每次通信都是由PC機通過串口向智能控制單元發(fā)布命令,智能控制單元在接收到正確的命令后作出應(yīng)答。

在Win32下,可以使用兩種編程方式實現(xiàn)串口通信,其一是使用ActiveX控件,這種方法程序簡單,但欠靈活。其二是調(diào)用Windows的API函數(shù),這種方法可以清楚地掌握串口通信的機制,并且自由靈活。本文我們只介紹API串口通信部分。

串口的操作可以有兩種操作方式:同步操作方式和重疊操作方式(又稱為異步操作方式)。同步操作時,API函數(shù)會阻塞直到操作完成以后才能返回(在多線程方式中,雖然不會阻塞主線程,但是仍然會阻塞監(jiān)聽線程);而重疊操作方式,API函數(shù)會立即返回,操作在后臺進行,避免線程的阻塞。

無論那種操作方式,一般都通過四個步驟來完成:

(1) 打開串口

(2) 配置串口

(3) 讀寫串口

(4) 關(guān)閉串口

1、打開串口

Win32系統(tǒng)把文件的概念進行了擴展。無論是文件、通信設(shè)備、命名管道、郵件槽、磁盤、還是控制臺,都是用API函數(shù)CreateFile來打開或創(chuàng)建的。該函數(shù)的原型為:

C++代碼

HANDLE?CreateFile(?LPCTSTR?lpFileName,?DWORD?dwDesiredAccess,?DWORD?dwShareMode,?LPSECURITY_ATTRIBUTES?lpSecurityAttributes,?DWORD?dwCreationDistribution,?DWORD?dwFlagsAndAttributes,?HANDLE?hTemplateFile);

lpFileName:將要打開的串口邏輯名,如“COM1”;

dwDesiredAccess:指定串口訪問的類型,可以是讀取、寫入或二者并列;

dwShareMode:指定共享屬性,由于串口不能共享,該參數(shù)必須置為0;

lpSecurityAttributes:引用安全性屬性結(jié)構(gòu),缺省值為NULL;

dwCreationDistribution:創(chuàng)建標志,對串口操作該參數(shù)必須置為OPEN_EXISTING;

dwFlagsAndAttributes:屬性描述,用于指定該串口是否進行異步操作,該值為FILE_FLAG_OVERLAPPED,表示使用異步的I/O;該值為0,表示同步I/O操作;

hTemplateFile:對串口而言該參數(shù)必須置為NULL。

同步I/O方式打開串口的示例代碼:

C++代碼

HANDLE?hCom;?//全局變量,串口句柄

hCom=CreateFile("COM1",//COM1口

GENERIC_READ|GENERIC_WRITE,?//允許讀和寫

0,?//獨占方式

NULL,

OPEN_EXISTING,?//打開而不是創(chuàng)建

0,?//同步方式

NULL);

if(hCom==(HANDLE)-1)

{

AfxMessageBox("打開COM失敗!");

return?FALSE;

}

return?TRUE;

重疊I/O打開串口的示例代碼:

C++代碼

HANDLE?hCom;?//全局變量,串口句柄

hCom?=CreateFile("COM1",?//COM1口

GENERIC_READ|GENERIC_WRITE,?//允許讀和寫

0,?//獨占方式

NULL,

OPEN_EXISTING,?//打開而不是創(chuàng)建

FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED,?//重疊方式

NULL);

if(hCom?==INVALID_HANDLE_VALUE)

{

AfxMessageBox("打開COM失敗!");

return?FALSE;

}

return?TRUE;

2、配置串口

在打開通訊設(shè)備句柄后,常常需要對串口進行一些初始化配置工作。這需要通過一個DCB結(jié)構(gòu)來進行。DCB結(jié)構(gòu)包含了諸如波特率、數(shù)據(jù)位數(shù)、奇偶校驗和停止位數(shù)等信息。在查詢或配置串口的屬性時,都要用DCB結(jié)構(gòu)來作為緩沖區(qū)。

一般用CreateFile打開串口后,可以調(diào)用GetCommState函數(shù)來獲取串口的初始配置。要修改串口的配置,應(yīng)該先修改DCB結(jié)構(gòu),然后再調(diào)用SetCommState函數(shù)設(shè)置串口。

DCB結(jié)構(gòu)包含了串口的各項參數(shù)設(shè)置,下面僅介紹幾個該結(jié)構(gòu)常用的變量:

typedef struct _DCB{ ………

DWORD BaudRate;//波特率,指定通信設(shè)備的傳輸速率。這個成員可以是實際波特率值或者下面的常量值之一:? CBR_110,CBR_300,CBR_600,CBR_1200,CBR_2400,CBR_4800,CBR_9600,CBR_19200, CBR_38400, CBR_56000, CBR_57600, CBR_115200, CBR_128000, CBR_256000, CBR_14400

DWORD fParity; // 指定奇偶校驗使能。若此成員為1,允許奇偶校驗檢查 …

BYTE ByteSize; // 通信字節(jié)位數(shù),4—8

BYTE Parity; //指定奇偶校驗方法。此成員可以有下列值: EVENPARITY 偶校驗 NOPARITY 無校驗 MARKPARITY 標記校驗 ODDPARITY 奇校驗

BYTE StopBits; //指定停止位的位數(shù)。此成員可以有下列值: ONESTOPBIT 1位停止位 TWOSTOPBITS 2位停止位

ON 5STOPBITS?? 1.5位停止位

GetCommState函數(shù)可以獲得COM口的設(shè)備控制塊,從而獲得相關(guān)參數(shù):

BOOL GetCommState(

HANDLE hFile, //標識通訊端口的句柄

LPDCB lpDCB //指向一個設(shè)備控制塊(DCB結(jié)構(gòu))的指針 );

SetCommState函數(shù)設(shè)置COM口的設(shè)備控制塊:

BOOL SetCommState( HANDLE hFile, LPDCB lpDCB );

除了在BCD中的設(shè)置外,程序一般還需要設(shè)置I/O緩沖區(qū)的大小和超時。Windows用I/O緩沖區(qū)來暫存串口輸入和輸出的數(shù)據(jù)。如果通信的速率較高,則應(yīng)該設(shè)置較大的緩沖區(qū)。調(diào)用SetupComm函數(shù)可以設(shè)置串行口的輸入和輸出緩沖區(qū)的大小。

BOOL SetupComm( HANDLE hFile, // 通信設(shè)備的句柄

DWORD dwInQueue, // 輸入緩沖區(qū)的大?。ㄗ止?jié)數(shù))

DWORD dwOutQueue // 輸出緩沖區(qū)的大?。ㄗ止?jié)數(shù)) );

在用ReadFile和WriteFile讀寫串行口時,需要考慮超時問題。超時的作用是在指定的時間內(nèi)沒有讀入或發(fā)送指定數(shù)量的字符,ReadFile或WriteFile的操作仍然會結(jié)束。

要查詢當前的超時設(shè)置應(yīng)調(diào)用GetCommTimeouts函數(shù),該函數(shù)會填充一個COMMTIMEOUTS結(jié)構(gòu)。調(diào)用SetCommTimeouts可以用某一個COMMTIMEOUTS結(jié)構(gòu)的內(nèi)容來設(shè)置超時。

讀寫串口的超時有兩種:間隔超時和總超時。間隔超時是指在接收時兩個字符之間的最大時延??偝瑫r是指讀寫操作總共花費的最大時間。寫操作只支持總超時,而讀操作兩種超時均支持。用COMMTIMEOUTS結(jié)構(gòu)可以規(guī)定讀寫操作的超時。

COMMTIMEOUTS結(jié)構(gòu)的定義為:

typedef struct _COMMTIMEOUTS {

DWORD ReadIntervalTimeout; //讀間隔超時

DWORD ReadTotalTimeoutMultiplier; //讀時間系數(shù)

DWORD ReadTotalTimeoutConstant; //讀時間常量

DWORD WriteTotalTimeoutMultiplier; // 寫時間系數(shù)

DWORD WriteTotalTimeoutConstant; //寫時間常量

} COMMTIMEOUTS,*LPCOMMTIMEOUTS;

COMMTIMEOUTS結(jié)構(gòu)的成員都以毫秒為單位。

總超時的計算公式是:總超時=時間系數(shù)×要求讀/寫的字符數(shù)+時間常量

例如,要讀入10個字符,那么讀操作的總超時的計算公式為:

讀總超時=ReadTotalTimeoutMultiplier×10+ReadTotalTimeoutConstant

可以看出:間隔超時和總超時的設(shè)置是不相關(guān)的,這可以方便通信程序靈活地設(shè)置各種超時。

如果所有寫超時參數(shù)均為0,那么就不使用寫超時。如果ReadIntervalTimeout為0,那么就不使用讀間隔超時。如果ReadTotalTimeoutMultiplier 和 ReadTotalTimeoutConstant 都為0,則不使用讀總超時。如果讀間隔超時被設(shè)置成MAXDWORD并且讀時間系數(shù)和讀時間常量都為0,那么在讀一次輸入緩沖區(qū)的內(nèi)容后讀操作就立即返回,而不管是否讀入了要求的字符。

在用重疊方式讀寫串口時,雖然ReadFile和WriteFile在完成操作以前就可能返回,但超時仍然是起作用的。在這種情況下,超時規(guī)定的是操作的完成時間,而不是ReadFile和WriteFile的返回時間。

配置串口的示例代碼:

SetupComm(hCom,1024,1024); //輸入緩沖區(qū)和輸出緩沖區(qū)的大小都是1024

COMMTIMEOUTS TimeOuts; //設(shè)定讀超時

TimeOuts.ReadIntervalTimeout=1000;

TimeOuts.ReadTotalTimeoutMultiplier=500;

TimeOuts.ReadTotalTimeoutConstant=5000; //設(shè)定寫超時

TimeOuts.WriteTotalTimeoutMultiplier=500;

TimeOuts.WriteTotalTimeoutConstant=2000;

SetCommTimeouts(hCom,&TimeOuts); //設(shè)置超時

DCB dcb;

GetCommState(hCom,&dcb);

dcb.BaudRate=9600; //波特率為9600

dcb.ByteSize=8; //每個字節(jié)有8位

dcb.Parity=NOPARITY; //無奇偶校驗位

dcb.StopBits=TWOSTOPBITS; //兩個停止位

SetCommState(hCom,&dcb);

PurgeComm(hCom,PURGE_TXCLEAR|PURGE_RXCLEAR);

在讀寫串口之前,還要用PurgeComm()函數(shù)清空緩沖區(qū),該函數(shù)原型:

BOOL PurgeComm( HANDLE hFile, //串口句柄

DWORD dwFlags // 需要完成的操作 );

參數(shù)dwFlags指定要完成的操作,可以是下列值的組合:

PURGE_TXABORT 中斷所有寫操作并立即返回,即使寫操作還沒有完成。

PURGE_RXABORT 中斷所有讀操作并立即返回,即使讀操作還沒有完成。

PURGE_TXCLEAR 清除輸出緩沖區(qū)

PURGE_RXCLEAR 清除輸入緩沖區(qū)

3、讀寫串口

我們使用ReadFile和WriteFile讀寫串口,下面是兩個函數(shù)的聲明:

BOOL ReadFile( HANDLE hFile, //串口的句柄

// 讀入的數(shù)據(jù)存儲的地址,

// 即讀入的數(shù)據(jù)將存儲在以該指針的值為首地址的一片內(nèi)存區(qū)

LPVOID lpBuffer,

// 要讀入的數(shù)據(jù)的字節(jié)數(shù)

DWORD nNumberOfBytesToRead,

// 指向一個DWORD數(shù)值,該數(shù)值返回讀操作實際讀入的字節(jié)數(shù)

LPDWORD lpNumberOfBytesRead,

// 重疊操作時,該參數(shù)指向一個OVERLAPPED結(jié)構(gòu),同步操作時,該參數(shù)為NULL。

LPOVERLAPPED lpOverlapped );

BOOL WriteFile( HANDLE hFile, //串口的句柄

// 寫入的數(shù)據(jù)存儲的地址,

// 即以該指針的值為首地址的

LPCVOID lpBuffer,

//要寫入的數(shù)據(jù)的字節(jié)數(shù)

DWORD nNumberOfBytesToWrite,

// 指向指向一個DWORD數(shù)值,該數(shù)值返回實際寫入的字節(jié)數(shù)

LPDWORD lpNumberOfBytesWritten,

// 重疊操作時,該參數(shù)指向一個OVERLAPPED結(jié)構(gòu),

// 同步操作時,該參數(shù)為NULL。

LPOVERLAPPED lpOverlapped );

在用ReadFile和WriteFile讀寫串口時,既可以同步執(zhí)行,也可以重疊執(zhí)行。在同步執(zhí)行時,函數(shù)直到操作完成后才返回。這意味著同步執(zhí)行時線程會被阻塞,從而導(dǎo)致效率下降。在重疊執(zhí)行時,即使操作還未完成,這兩個函數(shù)也會立即返回,費時的I/O操作在后臺進行。

ReadFile和WriteFile函數(shù)是同步還是異步由CreateFile函數(shù)決定,如果在調(diào)用CreateFile創(chuàng)建句柄時指定了FILE_FLAG_OVERLAPPED標志,那么調(diào)用ReadFile和WriteFile對該句柄進行的操作就應(yīng)該是重疊的;如果未指定重疊標志,則讀寫操作應(yīng)該是同步的。ReadFile和WriteFile函數(shù)的同步或者異步應(yīng)該和CreateFile函數(shù)相一致。

ReadFile函數(shù)只要在串口輸入緩沖區(qū)中讀入指定數(shù)量的字符,就算完成操作。而WriteFile函數(shù)不但要把指定數(shù)量的字符拷入到輸出緩沖區(qū),而且要等這些字符從串行口送出去后才算完成操作。

如果操作成功,這兩個函數(shù)都返回TRUE。需要注意的是,當ReadFile和WriteFile返回FALSE時,不一定就是操作失敗,線程應(yīng)該調(diào)用GetLastError函數(shù)分析返回的結(jié)果。例如,在重疊操作時如果操作還未完成函數(shù)就返回,那么函數(shù)就返回FALSE,而且GetLastError函數(shù)返回ERROR_IO_PENDING。這說明重疊操作還未完成。

同步方式讀寫串口比較簡單,下面先例舉同步方式讀寫串口的代碼:

//同步讀串口

char str[100];

DWORD wCount;//讀取的字節(jié)數(shù)

BOOL bReadStat;

bReadStat=ReadFile(hCom,str,100,&wCount,NULL);

if(!bReadStat) { AfxMessageBox("讀串口失敗!"); return FALSE; } return TRUE; //同步寫串口

char lpOutBuffer[100];

DWORD dwBytesWrite=100;

COMSTAT ComStat;

DWORD dwErrorFlags;

BOOL bWriteStat;

ClearCommError(hCom,&dwErrorFlags,&ComStat);

bWriteStat=WriteFile(hCom,lpOutBuffer,dwBytesWrite,& dwBytesWrite,NULL);

if(!bWriteStat) { AfxMessageBox("寫串口失敗!"); }

PurgeComm(hCom, PURGE_TXABORT| PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR);

在重疊操作時,操作還未完成函數(shù)就返回。

重疊I/O非常靈活,它也可以實現(xiàn)阻塞(例如我們可以設(shè)置一定要讀取到一個數(shù)據(jù)才能進行到下一步操作)。有兩種方法可以等待操作完成:一種方法是用象WaitForSingleObject這樣的等待函數(shù)來等待OVERLAPPED結(jié)構(gòu)的hEvent成員;另一種方法是調(diào)用GetOverlappedResult函數(shù)等待,后面將演示說明。

下面我們先簡單說一下OVERLAPPED結(jié)構(gòu)和GetOverlappedResult函數(shù):

OVERLAPPED結(jié)構(gòu)

OVERLAPPED結(jié)構(gòu)包含了重疊I/O的一些信息,定義如下:

typedef struct _OVERLAPPED { // o

DWORD Internal;

DWORD InternalHigh;

DWORD Offset;

DWORD OffsetHigh;

HANDLE hEvent;

} OVERLAPPED;

在使用ReadFile和WriteFile重疊操作時,線程需要創(chuàng)建OVERLAPPED結(jié)構(gòu)以供這兩個函數(shù)使用。線程通過OVERLAPPED結(jié)構(gòu)獲得當前的操作狀態(tài),該結(jié)構(gòu)最重要的成員是hEvent。hEvent是讀寫事件。當串口使用異步通訊時,函數(shù)返回時操作可能還沒有完成,程序可以通過檢查該事件得知是否讀寫完畢。

當調(diào)用ReadFile, WriteFile 函數(shù)的時候,該成員會自動被置為無信號狀態(tài);當重疊操作完成后,該成員變量會自動被置為有信號狀態(tài)。

GetOverlappedResult函數(shù) BOOL GetOverlappedResult( HANDLE hFile, // 串口的句柄 // 指向重疊操作開始時指定的OVERLAPPED結(jié)構(gòu) LPOVERLAPPED lpOverlapped, // 指向一個32位變量,該變量的值返回實際讀寫操作傳輸?shù)淖止?jié)數(shù)。 LPDWORD lpNumberOfBytesTransferred, // 該參數(shù)用于指定函數(shù)是否一直等到重疊操作結(jié)束。 // 如果該參數(shù)為TRUE,函數(shù)直到操作結(jié)束才返回。 // 如果該參數(shù)為FALSE,函數(shù)直接返回,這時如果操作沒有完成, // 通過調(diào)用GetLastError()函數(shù)會返回ERROR_IO_INCOMPLETE。 BOOL bWait );

該函數(shù)返回重疊操作的結(jié)果,用來判斷異步操作是否完成,它是通過判斷OVERLAPPED結(jié)構(gòu)中的hEvent是否被置位來實現(xiàn)的。

異步讀串口的示例代碼:

char lpInBuffer[1024];

DWORD dwBytesRead=1024;

COMSTAT ComStat;

DWORD dwErrorFlags;

OVERLAPPED m_osRead;

memset(&m_osRead,0,sizeof(OVERLAPPED));

m_osRead.hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);

ClearCommError(hCom,&dwErrorFlags,&ComStat);

dwBytesRead=min(dwBytesRead,(DWORD)ComStat.cbInQue);

if(!dwBytesRead) return FALSE;

BOOL bReadStatus;

bReadStatus=ReadFile(hCom,lpInBuffer, dwBytesRead,&dwBytesRead,&m_osRead);

if(!bReadStatus)

//如果ReadFile函數(shù)返回FALSE

{

if(GetLastError()==ERROR_IO_PENDING)

//GetLastError()函數(shù)返回ERROR_IO_PENDING,表明串口正在進行讀操作

{

WaitForSingleObject(m_osRead.hEvent,2000);

//使用WaitForSingleObject函數(shù)等待,直到讀操作完成或延時已達到2秒鐘

//當串口讀操作進行完畢后,m_osRead的hEvent事件會變?yōu)橛行盘?/p>

PurgeComm(hCom, PURGE_TXABORT| PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR);

return dwBytesRead;

}

return 0;

}

PurgeComm(hCom, PURGE_TXABORT| PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR);

return dwBytesRead;

對以上代碼再作簡要說明:

在使用ReadFile 函數(shù)進行讀操作前,應(yīng)先使用ClearCommError函數(shù)清除錯誤。

ClearCommError函數(shù)的原型如下:

BOOL ClearCommError( HANDLE hFile, // 串口句柄

LPDWORD lpErrors, // 指向接收錯誤碼的變量

LPCOMSTAT lpStat // 指向通訊狀態(tài)緩沖區(qū) );

該函數(shù)獲得通信錯誤并報告串口的當前狀態(tài),同時,該函數(shù)清除串口的錯誤標志以便繼續(xù)輸入、輸出操作。

參數(shù)lpStat指向一個COMSTAT結(jié)構(gòu),該結(jié)構(gòu)返回串口狀態(tài)信息。

COMSTAT結(jié)構(gòu) COMSTAT結(jié)構(gòu)包含串口的信息,結(jié)構(gòu)定義如下:

typedef struct _COMSTAT { // cst DWORD fCtsHold : 1; // Tx waiting for CTS signal DWORD fDsrHold : 1; // Tx waiting for DSR signal DWORD fRlsdHold : 1; // Tx waiting for RLSD signal DWORD fXoffHold : 1; // Tx waiting, XOFF char rec''d DWORD fXoffSent : 1; // Tx waiting, XOFF char sent DWORD fEof : 1; // EOF character sent DWORD fTxim : 1; // character waiting for Tx DWORD fReserved : 25; // reserved DWORD cbInQue; // bytes in input buffer DWORD cbOutQue; // bytes in output buffer } COMSTAT, *LPCOMSTAT;

本文只用到了cbInQue成員變量,該成員變量的值代表輸入緩沖區(qū)的字節(jié)數(shù)。

最后用PurgeComm函數(shù)清空串口的輸入輸出緩沖區(qū)。

這段代碼用WaitForSingleObject函數(shù)來等待OVERLAPPED結(jié)構(gòu)的hEvent成員,下面我們再演示一段調(diào)用GetOverlappedResult函數(shù)等待的異步讀串口示例代碼:

char lpInBuffer[1024];

DWORD dwBytesRead=1024;

BOOL bReadStatus;

DWORD dwErrorFlags;

COMSTAT ComStat;

OVERLAPPED m_osRead;

ClearCommError(hCom,&dwErrorFlags,&ComStat);

if(!ComStat.cbInQue) return 0;

dwBytesRead=min(dwBytesRead,(DWORD)ComStat.cbInQue);

bReadStatus=ReadFile(hCom, lpInBuffer,dwBytesRead, &dwBytesRead,&m_osRead);

if(!bReadStatus) //如果ReadFile函數(shù)返回FALSE

{ if(GetLastError()==ERROR_IO_PENDING)

{ GetOverlappedResult(hCom, &m_osRead,&dwBytesRead,TRUE);

// GetOverlappedResult函數(shù)的最后一個參數(shù)設(shè)為TRUE,

//函數(shù)會一直等待,直到讀操作完成或由于錯誤而返回。

return dwBytesRead; }

return 0; }

return dwBytesRead;

異步寫串口的示例代碼:

char buffer[1024];

DWORD dwBytesWritten=1024;

DWORD dwErrorFlags;

COMSTAT ComStat;

OVERLAPPED m_osWrite;

BOOL bWriteStat;

bWriteStat=WriteFile(hCom,buffer,dwBytesWritten, &dwBytesWritten,&m_OsWrite);

if(!bWriteStat)

{ if(GetLastError()==ERROR_IO_PENDING)

{ WaitForSingleObject(m_osWrite.hEvent,1000);

return dwBytesWritten; }

return 0; }

return dwBytesWritten;

4、關(guān)閉串口

利用API函數(shù)關(guān)閉串口非常簡單,只需使用CreateFile函數(shù)返回的句柄作為參數(shù)調(diào)用CloseHandle即可:

BOOL CloseHandle(

HANDLE hObject; //handle to object to close

);

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,825評論 6 546
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,814評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 178,980評論 0 384
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 64,064評論 1 319
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,779評論 6 414
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 56,109評論 1 330
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,099評論 3 450
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 43,287評論 0 291
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,799評論 1 338
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 41,515評論 3 361
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,750評論 1 375
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,221評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,933評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,327評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,667評論 1 296
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,492評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,703評論 2 380

推薦閱讀更多精彩內(nèi)容