使用API编程,异步通信方式。
计算机仅仅从串口读数据,不用向串口写数据,因此比较简单。
思路:使用一个辅助线程来读串口。
发现问题:当设备向计算机发送数据时候,比如发送6个字节,计算机会接收两次,第一次接收6个字节,第二次接收0个字节。这里,我给出主要代码:
一、打开串口1,以及串口主要设置信息:
g_hCom1 = CreateFile("COM1",
GENERIC_WRITE | GENERIC_READ,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
NULL
);
波特率9600,校验,缓冲区大小,超时等等,都设置好。//超时
tmOuts.ReadIntervalTimeout = 500;
tmOuts.ReadTotalTimeoutMultiplier = 0;
tmOuts.ReadTotalTimeoutConstant = 1000;//设置触发事件为
SetCommMask(hCom, EV_RXCHAR);
二、监控串口1的线程,主要代码:
UINT WatchComm1Thread(LPVOID pParam)
{
  DWORD dwMask, dwTransfered;
  OVERLAPPED ol;
  memset(&ol, 0, sizeof(OVERLAPPED));
  ol.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);  while(1)
  {
    if(!WaitCommEvent(g_hCom1 , &dwMask, &ol))//语句1
    {
      if(GetLastError() == ERROR_IO_PENDING)
          GetOverlappedResult(g_hCom1, &ol, &dwTransfered, TRUE);//语句2
    }    if((dwMask & EV_RXCHAR) == EV_RXCHAR)
    {
      int iReadLen = ReadComm1();//语句3
    }
  }
}
三、读串口函数ReadComm1()主要代码:
int ReadComm1()
{
  DWORD dwError, dwRecvedLen = 0, dwTansfered;
  COMSTAT comStat;
  OVERLAPPED olRead1;
  
  memset(&olRead1, 0, sizeof(OVERLAPPED));
  olRead1.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  
  ClearCommError(g_hCom1, &dwError, &comStat);  if(comStat.cbInQue > 0)
  {
    if(!ReadFile(g_hCom1, g_RecvBuf1, comStat.cbInQue, &dwRecvedLen, &olRead1))
    {
      if(GetLastError() == ERROR_IO_PENDING)
        GetOverlappedResult(g_hCom1, &olRead1, &dwTansfered, TRUE);
    }
  }  CloseHandle(olRead1.hEvent);
  return (int)dwRecvedLen;
}
/////////////////////////////////////////
我开始调试了:
我在“语句1”设置断点。程序运行起来,很快执行到“语句1”处,单步运行,使其执行到“语句2”,再单步运行,因为设备一直不向计算机发送数据,“语句2”一直不会返回,这些都表明程序是好的。设备向计算机发送6个字节,“语句2”立即返回,通过单步,可以发现“语句3”读取了6个字节,一切正常。然后继续单步,使其运行到“语句1”处,单步运行,使其执行到“语句2”,再单步运行,却发现“语句2”立即返回,(可是现在并串口中没有数据可读啊,“语句2”为什么会立即返回呢),再单步,程序符合“if((dwMask & EV_RXCHAR) == EV_RXCHAR)”的条件,运行到“语句3”,解下来就可以发现“语句3”读到了0个字节,怎么回事?

解决方案 »

  1.   

    you could try to use SearialCOM Class
    may be which could help you anything
      

  2.   

    用MScomm,程序给其他人使用的时候要涉及到控件的注册问题。SearialCOM我不知道,也不想用。
      

  3.   

    EV_RXCHAR
    A character was received and placed in the input buffer
    串口向计算机发送六个字节,系统会受到六次EV_RXCHAR消息,第一次你就收了六个字节,以后的五次就只能收0字节了
    至于为什么只受到2次EV_RXCHAR,我觉得原因应该是
        if(!ReadFile(g_hCom1, g_RecvBuf1, comStat.cbInQue, &dwRecvedLen, &olRead1))
        {
          if(GetLastError() == ERROR_IO_PENDING)
            GetOverlappedResult(g_hCom1, &olRead1, &dwTansfered, TRUE);
        }
    这里做了GetOverlappedResult的缘故,只有第一次和最后一次被受到了另:其实SearialCOM真的很好用,而且和你的程序很相似,可以比较一下
      

  4.   

    BBirdlyh(BBird),感谢你的分析。我又调试看了看,发现情况不像你说的那样,不像你分析语句GetOverlappedResult那样。在int ReadComm1()函数中,“if(GetLastError() == ERROR_IO_PENDING)”,“GetOverlappedResult(g_hCom1, &olRead1, &dwTansfered, TRUE);”这两句都没有执行,
    也就是说,在读串口的时候,一次性就读完了comStat.cbInQue数量的字节,ReadFile语句返回了TRUE。呵呵。
      

  5.   

    正是因为你一次读完了6个字节,但没有阻止EV_RXCHAR消息,所以下次还会去处理但安道理来说应该会受到6次,我所说的GetOverlappedResult的情况是在分析你为什么会受到2次还有一个函数是用来清除接下来的EV_RXCHAR 或是其他消息的,也就是说你第一次收到EV_RXCHAR后,全部读出6个字节,然后调用该函数清除后续的EV_RXCHAR消息,msdn上有(DEVICE IO)你可以查一下一般最好的办法是一次只收一个字节,然后攒着,知道受到要求的字节数并且验证正确再向处理模块发消息处理
      

  6.   

    同意楼上的
    可以一个一个读
    完了之后再处理.否则在语句3处加个对comStat.cbInQue是否为空的判断
    另:BBirdlyh(BBird)说的没错