串口编程详解(二)

串口编程详解(二)

Version:1.0 StartHTML:000000217 EndHTML:000081408 StartFragment:000005962 EndFragment:000081346 StartSelection:000005983 EndSelection:000081324 SourceURL:http://blog.chinaunix.net/uid-21411227-id-1826782.htmlWIN32串口编程详解(二)-zhenhuaqin-ChinaUnix博客

分类:

2010-01-12 22:31:04

4.2 同步方式读写串口:

下面先例举同步方式读写串口的代码:

//同步读串口

char str[100];

DWORD wCount;//读取的字节数

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);

4.3 重叠操作:

操作还未完成函数就返回。

重叠I/O非常灵活,它也可以实现阻塞(例如我们可以设置一定要读取到一个数据才能进行到下一步操作)。有两种方法可以等待操作完成:一种方法是用象WaitForSingleObject这样的等待函数来等待OVERLAPPED结构的hEvent成员;另一种方法是调用GetOverlappedResult函数等待,后面将演示说明。

下面我们先简单说一下OVERLAPPED结构和GetOverlappedResult函数:

1) OVERLAPPED结构

OVERLAPPED结构包含了重叠I/O的一些信息,

定义如下: typedef struct _OVERLAPPED { // o

DWORD  Internal;

DWORD  InternalHigh;

DWORD  Offset;

DWORD  OffsetHigh;

HANDLE hEvent;

} OVERLAPPED;

在使用ReadFile和WriteFile重叠操作时,线程需要创建OVERLAPPED结构以供这两个函数使用。线程通过OVERLAPPED结构获得当前的操作状态,该结构最重要的成员是hEvent。hEvent是读写事件。当串口使用异步通讯时,函数返回时操作可能还没有完成,程序可以通过检查该事件得知是否读写完毕。

当调用ReadFile, WriteFile 函数的时候,该成员会自动被置为无信号状态;当重叠操作完成后,该成员变量会自动被置为有信号状态。

GetOverlappedResult函数

BOOL GetOverlappedResult(

HANDLE hFile, // 串口的句柄

// 指向重叠操作开始时指定的OVERLAPPED结构

LPOVERLAPPED lpOverlapped,

// 指向一个32位变量,该变量的值返回实际读写操作传输的字节数。

LPDWORD lpNumberOfBytesTransferred,

// 该参数用于指定函数是否一直等到重叠操作结束。

// 如果该参数为TRUE,函数直到操作结束才返回。

// 如果该参数为FALSE,函数直接返回,这时如果操作没有完成,

// 通过调用GetLastError()函数会返回ERROR_IO_INCOMPLETE。

BOOL bWait

);

该函数返回重叠操作的结果,用来判断异步操作是否完成,它是通过判断OVERLAPPED结构中的hEvent是否被置位来实现的。

4.4 异步读串口的示例代码:

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函数返回FALSE

{

if(GetLastError()==ERROR_IO_PENDING)

//GetLastError()函数返回ERROR_IO_PENDING,表明串口正在进行读操作        {

WaitForSingleObject(m_osRead.hEvent,2000);

//使用WaitForSingleObject函数等待,直到读操作完成或延时已达到2秒钟

//当串口读操作进行完毕后,m_osRead的hEvent事件会变为有信号

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 函数进行读操作前,应先使用ClearCommError函数清除错误。ClearCommError函数的原型如下: BOOL ClearCommError(

HANDLE hFile, // 串口句柄

LPDWORD lpErrors,       // 指向接收错误码的变量

LPCOMSTAT lpStat // 指向通讯状态缓冲区

);

该函数获得通信错误并报告串口的当前状态,同时,该函数清除串口的错误标志以便继续输入、输出操作。

参数lpStat指向一个COMSTAT结构,该结构返回串口状态信息。

COMSTAT结构

COMSTAT结构包含串口的信息,结构定义如下:

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成员变量,该成员变量的值代表输入缓冲区的字节数。

最后用PurgeComm函数清空串口的输入输出缓冲区。

这段代码用WaitForSingleObject函数来等待OVERLAPPED结构的hEvent成员,

下面我们再演示一段调用GetOverlappedResult函数等待的异步读串口示例代码:

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函数返回FALSE

{

if(GetLastError()==ERROR_IO_PENDING)

{

GetOverlappedResult(hCom,

&m_osRead,&dwBytesRead,TRUE);

// GetOverlappedResult函数的最后一个参数设为TRUE,

//函数会一直等待,直到读操作完成或由于错误而返回。

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;

5.关闭串口

利用API函数关闭串口非常简单,只需使用CreateFile函数返回的句柄作为参数调用CloseHandle即可:

BOOL CloseHandle(

HANDLE hObject; //handle to object to close

);