使用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.   

    我以前用的是MOXA提供的串口dll,基本构架应该是
    1 先初始化函数,收到字节就触发一个回调函数。
    2 在回调函数里查看收到的字节数,如果为0就返回,不为0就全部Read出来,然后放到一个全局的缓冲里,然后发出一个收到字符的消息;
    3 主程序接到消息触发自己定义的一个查看函数,查看函数的作用是将收到的字节从缓冲里拿出来,然后和以前的数据组成到一起,然后判断是否到达数据的帧尾部。如果到达帧尾部,则取出完整的一帧数据,否则返回。PS:串口的事件触发不是全收到才触发的,它是一字节一字节的接收的,所以每次触发的字节数不固定。要在触发事件里将收到的字节读出来放到一个全局的缓冲里。然后在外边判断是否收满一帧。