现在的位置: 首页 > 综合 > 正文

使用Win32API实现Windows下异步串口通讯(下)

2013年12月01日 ⁄ 综合 ⁄ 共 5137字 ⁄ 字号 评论关闭

只一个框架性流程而矣............

实现重叠模型的步骤
下面就结合俺写的一个Console程序简单示例进行说明:

【第一步】打开串口
 HANDLE m_hCom = CreateFile("com1",GENERIC_READ | GENERIC_WRITE, 0, NULL,
    OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
 if (m_hCom == INVALID_HANDLE_VALUE)
 {
  cout<<"CreateFile fail!"<<ENDL;
  return -1;
 }
 cout<<"CreateFile OK!"<<ENDL;< p="" />

【第二步】设置缓冲区大小
 if(!SetupComm(m_hCom,2048,2048))
 {
  cout<<"SetupComm fail! Close Comm!"<<ENDL;
  CloseHandle(m_hCom);
  return -1;
 }
 cout<<"SetupComm OK!"<<ENDL;< p="" />

【第三步】设置超时
COMMTIMEOUTS TimeOuts;
memset(&TimeOuts,0,sizeof(TimeOuts));
TimeOuts.ReadIntervalTimeout = MAXDWORD;
TimeOuts.ReadTotalTimeoutConstant = 0;
TimeOuts.ReadTotalTimeoutMultiplier = 0;
TimeOuts.WriteTotalTimeoutConstant = 2000;
TimeOuts.WriteTotalTimeoutMultiplier = 50;
SetCommTimeouts(m_hCom,&TimeOuts);

【第四步】设置串口参数
       DCB dcb;
 if (!GetCommState(m_hCom,&dcb))
 {
  cout<<"GetCommState fail! Comm close"<<ENDL;
  CloseHandle(m_hCom);
  return -1;
 }
 cout<<"GetCommState OK!"<<ENDL;
 
 dcb.DCBlength = sizeof(dcb);
 if (!BuildCommDCB("9600,n,8,1",&dcb))//填充DCB的数据传输率、奇偶校验类型、数据位、停止位
 {
  //参数修改错误,进行错误处理
  cout<<"BuileCOmmDCB fail,Comm close!"<<ENDL;
  CloseHandle(m_hCom);
  return -1;
  }
 if(SetCommState(m_hCom,&dcb))
 {
  cout<<"SetCommState OK!"<<ENDL;
 }

【第五步】建立并初始化重叠结构
 OVERLAPPED wrOverlapped;
 ZeroMemory(&wrOverlapped,sizeof(wrOverlapped));
 if (wrOverlapped.hEvent != NULL)
 {
  ResetEvent(wrOverlapped.hEvent);
  wrOverlapped.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
 }

【第六步】封装数据(按照自己的格式封装需要发送的数据,此步可以省略)
typedef enum
{
 HEAT_BEAT, //心跳数据
 NET_STATE,//网络状态数据
 PACKET  //正常数据包
 //支持可扩展性......
}ProtocolType;

typedef enum
{
 Train_No,//无线车次信息
 Attemper_Command,//调度命令信息
 Revert_Command,//调度命令回执信息
 Replay_Command,//重发的调度命令信息
     KGL_SING    //开关量数据
 //支持可扩展性......
}PacketDataType;

//串口数据结构
typedef struct SerialNetProto
{
 unsigned long  PacketSize; //包总长度,不包括本身字段
 ProtocolType  NetState; //协议包类型
 PacketDataType DataType; //数据类型
 unsigned long SourcedAddr; //数据包源地址
 unsigned long DestinationAddr; //数据包目的地址
 unsigned long DataLength;    //包的数据段长度
 unsigned long Offset;    // 数据在整个包中的偏移地址
}PacketHead;

 int DataLen = 100;
 char *pBuf = new char[DataLen];
 strcpy(pBuf,"Hello World!");
 DataLen   = strlen(pBuf);
 PacketHead Myhead;
 Myhead.DestinationAddr = 11;
 Myhead.SourcedAddr = 10;
 Myhead.DataType = Attemper_Command;
 Myhead.DataLength = DataLen;
 Myhead.NetState = PACKET;
 Myhead.PacketSize = sizeof(PacketHead) - sizeof(unsigned long);
 Myhead.Offset = sizeof(Myhead.DestinationAddr) +sizeof(Myhead.SourcedAddr) + sizeof(Myhead.DataType) +sizeof(Myhead.DataLength) + sizeof(Myhead.NetState) + sizeof(Myhead.PacketSize);
 
 char *pSendBuffer = new char[sizeof(Myhead)+DataLen+ 4];//发送的数据
 memcpy(pSendBuffer,"##",2);//包头标志
 memcpy(pSendBuffer+2,(char*)&Myhead,sizeof(Myhead));//包头
 memcpy(pSendBuffer+2+sizeof(Myhead),pBuf,DataLen);//数据
 memcpy(pSendBuffer+2+sizeof(Myhead)+DataLen,"@@",2);//包尾标志

【第七步】发送数据
 DWORD dwError;
 //DWORD dwWantSend = 100;
 DWORD dwRealSend = 0;
 char* pReadBuf = NULL;
 if (ClearCommError(m_hCom,&dwError,NULL))
 {
  PurgeComm(m_hCom,PURGE_TXABORT | PURGE_TXCLEAR);
  cout<<"PurgeComm OK!"<<ENDL;
 }
 if (!WriteFile(m_hCom,pSendBuffer,sizeof(Myhead)+DataLen+ 4,&dwRealSend,&wrOverlapped))
 {
  if (GetLastError() == ERROR_IO_PENDING)
  {
   while (!GetOverlappedResult(m_hCom,&wrOverlapped,&dwRealSend,FALSE))   {
    if (GetLastError() == ERROR_IO_INCOMPLETE)
    {
     //cout<<"写未完成,继续!"<<ENDL;
     continue;
    }
    else
    {
     cout<<"发生错误,尝试恢复!"<<ENDL;
     ClearCommError(m_hCom,&dwError,NULL);
     break;
    }
   }
  }
 }

【第八步】数据接收
 DWORD dwError;
 DWORD dwWantRead = 100;
 DWORD dwRealRead = 0;
 char* pReadBuf = new char[100];
 if (ClearCommError(m_hCom,&dwError,NULL))
 {
  PurgeComm(m_hCom,PURGE_TXABORT | PURGE_TXCLEAR);
  cout<<"PurgeComm OK!"<<ENDL;
 }

 if(!ReadFile(m_hComm,pReadBuf,dwWantRead,&RealRead,&wrOverlapped))
 {
  if(dwError = GetLastError()==ERROR_IO_PENDING)
  {
   While(GetOverlappedResult(m_hComm,&wrOverlapped,&dwRealRead,FALSE))
   {
    //对接收到的数据进行数据解析,处理
    //【第九步】............
    cout<<"dwRealRead = "<<DWREALREAD<<ENDL;
   }
  }
 }
【第九步】数据解析(数据解包处理)

#define MAX_SERIAL_BUFFER 4096
BOOL CanGetFullFrame(char* pReadBuf,int& dwRealRead)
{
 static char Buf[MAX_SERIAL_BUFFER*2];//自定义一个数据缓冲区
 static unsigned long nFrameStart = 0;//数据祯的开始位置
 static unsigned long nFrameEnd = 0;//数据祯的结束位置
 static unsigned long nCurrectPos = 0;//指针当前位置
 char *pdest = NULL;
 
 if (pReadBuf && (dwRealRead!= 0))
 {
  memcpy(&Buf[nCurrectPos],pReadBuf,dwRealRead);
  nCurrectPos = nCurrectPos + dwRealRead;//更新当前位置
 }
 //查找数据祯的开始标志
 pdest = (char*)Find(Buf,"##",MAX_SERIAL_BUFFER*2,2);
 if (pdest)
 {
  nFrameStart = unsigned long(pdest - Buf);//找到数据祯的开始位置
 }
 else//没有找到开始祯标志"##"
 {
  Buf[0] = Buf[nCurrectPos];//丢弃数据
  nFrameStart = 0;
  return FALSE;
 }
 
 //查找数据祯的结尾标志
 pdest =  (char*)Find(Buf,"@@",MAX_SERIAL_BUFFER*2,2);
 if (pdest)
 {
  nFrameEnd = unsigned long (pdest - Buf+2);
  dwRealRead= nFrameEnd - nFrameStart;
  memcpy(pReadBuf,&Buf[nFrameStart],dwRealRead);

  nFrameStart = nFrameEnd;//指向下一帧的开始位置
  nCurrectPos = nCurrectPos - dwRealRead;//修正nCurrentPos值
  memcpy(Buf,&Buf[nFrameEnd],nCurrectPos);//向前移动数据
  return TRUE;
 }
 else
 {
  return FALSE;
 }
}

//一个在内存块中查找指定字符串的函数
void* Find(const char *pSour,const char *pDest,int SourLen,int DestLen)
{
 int i = 0, j = 0;
 while(i < SourLen && j < DestLen)
 {
  if(*(pSour + i) == *(pDest + j))
  {
   i++;
   j++;
  }
  else
  {
   i =i - j + 1;
   j = 0;
  }
 }
 if(j == DestLen)
 {
  return (void*)(pSour + (i - DestLen));
 }
 else
 {
  return NULL;
 }

}
【第十步】重新投递Overlapped,略......

抱歉!评论已关闭.