以下是串口类CSerialPort中的CommThread线程函数
UINT CSerialPort::CommThread(LPVOID pParam)
{ CSerialPort *port = (CSerialPort*)pParam;
port->m_bThreadAlive = TRUE;
DWORD BytesTransfered = 0; 
DWORD Event = 0;
DWORD CommEvent = 0;
DWORD dwError = 0;
COMSTAT comstat;
BOOL  bResult = TRUE;
if (port->m_hComm)
PurgeComm(port->m_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT);
for (;;) 


bResult = WaitCommEvent(port->m_hComm, &Event, &port->m_ov); if (!bResult)  
{  switch (dwError = GetLastError()) 

case ERROR_IO_PENDING: 
{  break;
}
case 87:
{ break;
}
default:
{ port->ProcessErrorMessage("WaitCommEvent()");
break;
}
}
}
else
{


bResult = ClearCommError(port->m_hComm, &dwError, &comstat); if (comstat.cbInQue == 0)
continue;
} Event = WaitForMultipleObjects(3, port->m_hEventArray, FALSE, INFINITE); switch (Event)
{
case 0:
{ CloseHandle(port->m_hComm);
port->m_hComm=NULL;
port->m_bThreadAlive = FALSE; AfxEndThread(100); break;
}
case 1:
{
GetCommMask(port->m_hComm, &CommEvent);
if (CommEvent & EV_RXCHAR) ReceiveChar(port, comstat);
if (CommEvent & EV_CTS)
::SendMessage(port->m_pOwner->m_hWnd, WM_COMM_CTS_DETECTED, (WPARAM) 0, (LPARAM) port->m_nPortNr);
if (CommEvent & EV_BREAK)
::SendMessage(port->m_pOwner->m_hWnd, WM_COMM_BREAK_DETECTED, (WPARAM) 0, (LPARAM) port->m_nPortNr);
if (CommEvent & EV_ERR)
::SendMessage(port->m_pOwner->m_hWnd, WM_COMM_ERR_DETECTED, (WPARAM) 0, (LPARAM) port->m_nPortNr);
if (CommEvent & EV_RING)
::SendMessage(port->m_pOwner->m_hWnd, WM_COMM_RING_DETECTED, (WPARAM) 0, (LPARAM) port->m_nPortNr);

if (CommEvent & EV_RXFLAG)
::SendMessage(port->m_pOwner->m_hWnd, WM_COMM_RXFLAG_DETECTED, (WPARAM) 0, (LPARAM) port->m_nPortNr);

break;
}  
case 2: 
{

WriteChar(port);
break;
} }  }  return 0;
}WaitCommEvent函数和WaitForMultipleObjects函数都是串口事件等待函数,这里用WaitCommEvent函数有何意义呢?

解决方案 »

  1.   

    标记下,WaitCommEvent是用来监听串口中是否接收到数据,已经接收的状态然后做相应的处理
      

  2.   

    MSDN:Waits for an event to occur for a specified communications device. The set of events that are monitored by this function is contained in the event mask associated with the device handle./*
    Monitoring Communications Events
    The following example code opens the serial port for overlapped I/O, creates an event mask to monitor CTS and DSR signals, and then waits for an event to occur. The WaitCommEvent function should be executed as an overlapped operation so the other threads of the process can perform I/O operations during the wait.
    */#include <windows.h>
    #include <assert.h>
    #include <stdio.h>void main( )
    {
        HANDLE hCom;
        OVERLAPPED o;
        BOOL fSuccess;
        DWORD dwEvtMask;    hCom = CreateFile( TEXT("COM1"),
            GENERIC_READ | GENERIC_WRITE,
            0,    // exclusive access 
            NULL, // default security attributes 
            OPEN_EXISTING,
            FILE_FLAG_OVERLAPPED,
            NULL 
            );    if (hCom == INVALID_HANDLE_VALUE) 
        {
            // Handle the error. 
            printf("CreateFile failed with error %d.\n", GetLastError());
            return;
        }    // Set the event mask.     fSuccess = SetCommMask(hCom, EV_CTS | EV_DSR);    if (!fSuccess) 
        {
            // Handle the error. 
            printf("SetCommMask failed with error %d.\n", GetLastError());
            return;
        }    // Create an event object for use by WaitCommEvent.     o.hEvent = CreateEvent(
            NULL,   // default security attributes 
            TRUE,   // manual-reset event 
            FALSE,  // not signaled 
            NULL    // no name
    );
            // Initialize the rest of the OVERLAPPED structure to zero.
        o.Internal = 0;
        o.InternalHigh = 0;
        o.Offset = 0;
        o.OffsetHigh = 0;    assert(o.hEvent);    if (WaitCommEvent(hCom, &dwEvtMask, &o)) 
        {
            if (dwEvtMask & EV_DSR) 
            {
                 // To do.
            }        if (dwEvtMask & EV_CTS) 
            {
                // To do. 
            }
        }
        else
        {
            DWORD dwRet = GetLastError();
            if( ERROR_IO_PENDING == dwRet)
            {
                printf("I/O is pending...\n");            // To do.
            }
            else 
                printf("Wait failed with error %d.\n", GetLastError());
        }
    }
      

  3.   


    从源代码来看,即使WaitCommEvent没有接收到数据,依然执行到WaitForMultipleObjects进行事件等待啊?
      

  4.   

    我猜想,这段代码中,WaitCommEvent唯一的作用是
    if (comstat.cbInQue == 0)
    continue;
    就是当有串口接收到数据的事件,但是数据数量为0,这种情况下程序不做任何处理
    串口事件的处理几乎都是靠WaitForMultipleObjects完成的,WaitCommEvent几乎没什么作用,完全可以用WaitForMultipleObjects替代WaitCommEvent
    请教各位高手,是这样吗?
      

  5.   

    应该你串口 是以异步打开的,你改成NULL试试,运行带WaitCommEvent 就阻塞等数据了
      

  6.   

    这代码看着眼熟
    CSerialPort?
    你注意看一下WaitForMultipleObjects的作用是为了区分关闭、读、写这三个操作的
    和串口本身的功能关系不大
      

  7.   

    WaitCommEvent判断接收串口数据是否出错  另外主要用在异步方式下
    WaitForMultipleObjects这里对串口的不同事件进行不同的处理  最简单的串口有发送 和接收 等   
    处理方式都不一样的
      

  8.   

    串口 是以异步打开的,你改成NULL试试,运行带WaitCommEvent 就阻塞等数据了
      

  9.   


    WaitForMultipleObjects(3, port->m_hEventArray, FALSE, INFINITE);
    这个函数不用INFINITE,不也是异步方式么?
    呵呵,感觉两个函数还是差不多
      

  10.   

    什么叫做异步,WaitForMultipleObjects(3, port->m_hEventArray, FALSE, INFINITE);
    这个是等待port->m_hEventArray数组中的其中一个事件信号,然后做相应处理
      

  11.   

    对接收数据的功能来说都一样
    要不改成WaitForSingleObject(m_ov.hEvent,10),这不也是异步?
    我怎么觉得串口程序里的异步,就像同步,不过是多了一个线程而已
      

  12.   


    串口同步开:WaitCommEvent()会阻塞串口线程,等数据,用WaitForXXXObject()可等待你自定义的事件,该事件也可控制同异步
    串口异步开: WaitCommEvent()非阻塞串口线程,用WaitForXXXObject()可等待你overlapped指定事件,判断异步操作是否完成,即实现串口线程阻塞使用WaitForXXXObject函数可精确控制不同线程优先权切换,
                                         
      

  13.   

    WaitForMultipleObjects的作用是为了区分关闭、读、写这三个操作的
    和串口本身的功能关系不大
      

  14.   

    if (comstat.cbInQue == 0)
    说明串口数据已经接收完毕  可以对接收到的数据进行处理了
      

  15.   

    串口接收线程函数:
    // 工作者线程,负责监视串行口
    UINT ReceiveDataThread(LPVOID pParam)
    {
    CThreadCommDlg *pRxThread=(CThreadCommDlg*)pParam; OVERLAPPED m_osRead;
    memset(&m_osRead,0,sizeof(OVERLAPPED));
    m_osRead.hEvent=CreateEvent(NULL,TRUE,FALSE,NULL); COMSTAT ComStat;
    DWORD dwErrorFlags; char str[512];
    memset(str,'\0',512);
    DWORD dwBytesRead=500;//读取的字节数
    DWORD dwBytesHaveRead = 0;//读取的字节数
    BOOL bReadStat; CString strReceiveData; ClearCommError(hCom,&dwErrorFlags,&ComStat); while (true)
    {
    memset(str,'\0',512); //dwBytesRead=min(dwBytesRead, (DWORD)ComStat.cbInQue); bReadStat=ReadFile(hCom,str,dwBytesRead,&dwBytesHaveRead,&m_osRead);
    //bReadStat=ReadFile(hCom,str,dwBytesRead,&dwBytesRead,&m_osRead); // 这样会导致接收不到数据:原因,while(true)第一次执行时,就会把待读取字符数dwBytesRead置为0 /*if (0 != dwBytesHaveRead)
    {
    CString strTemp;
    strTemp.Format(L"%d", dwBytesHaveRead); AfxMessageBox(strTemp);
    }*/ if(!bReadStat)
    {
    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);*/ //strReceiveData += str; if ('\0' != str[0])
    {
    //AfxMessageBox(strReceiveData); ::SendMessage(pRxThread->m_hWnd, COM_RX_DATA, (WPARAM)str, (LPARAM)dwBytesHaveRead); 
    } //pRxThread->m_receive_data += str;
    //pRxThread->UpdateData(false); // 程序运行到此处会出错
    } return 0;
    }