串口异步读写

#pragma once
#include <windows.h>
#include <process.h>

typedef UINT lpCallBack (LPVOID lpParam);

class BaseComm
{
public:
 BaseComm(void);
 virtual ~BaseComm(void);

 // 打开串口
 // 输入: pPort - 串口名称或设备路径,可用"COM1"
 //       nBaudRate - 波特率
 //       nParity - 奇偶校验
 //       nByteSize - 数据字节宽度
 //       nStopBits - 停止位
 virtual bool OpenComm(wchar_t* pPort = L"COM3", int nBaudRate=9600, int nByteSize=8, int nStopBits=ONESTOPBIT, int nParity=NOPARITY);

 // 关闭串口
 bool CloseComm();

 // 创建监听线程
 bool CreateCommEventThread();

 // 退出监听线程
 void ExitCommEventThread();

protected:
 // 清除收发缓冲区
 void ClearCommBuff();

 // 获得串口句柄
 HANDLE GetHANDLE_Comm() { return hComm; }

 // 写串口
 // 输入: pData - 待写的数据缓冲区指针
 //       nLength - 待写的数据长度
 // 返回: 实际写入的数据长度
 bool WriteComm(void* pData, int nLength);

 // 读串口
 // 输入: pData - 待读的数据缓冲区指针
 //       nLength - 待读的最大数据长度
 // 返回: 实际读出的数据长度
 bool ReadComm(void* pData, int nLength);

 //生成新的线程(in 线程函数指针, in 参数指针,out 线程句柄地址,out 线程ID)
 bool CreateNewThread(lpCallBack *pfnThrearoc,LPVOID pParam,
   HANDLE &hNewThread,DWORD &dwThreadId);

private:
 // 串口设备句柄
 HANDLE hComm;
 // 串口空闲信号(用于发送和接收操作互斥)
 HANDLE hCommFree;
 // 串口接收信号
 HANDLE hCommRecv;
 // 串口接收信号
 HANDLE hCommSend;
 // 串口监听线程开关
 bool IsRunThread;
 // 线程句柄
 HANDLE hCommEventThread;
 // 线程ID
 DWORD dwCommEventThreadID;

 // 串口事件函数
 friend UINT CommEventThread(LPVOID pParam);
};

 

//-------------------------------------------------------------------------------------

 

#include "BaseComm.h"


//将C的运行期函数参数转化为C++的
typedef unsigned (__stdcall *PTHREAD_START)(void *);
#define chBEGINTHREADEX(psa,cbStack,pfnStartAddr,/
 pvParam,fdwCreate,pdwThreadID)( /
 (HANDLE) _beginthreadex( /
 (void*)(psa),(unsigned)(cbStack), /
 (PTHREAD_START)(pfnStartAddr), /
 (void*)(pvParam), /
 (unsigned)(fdwCreate), /
(unsigned*)(pdwThreadID) ) )

UINT CommEventThread(LPVOID pParam)
{
 if( NULL == pParam)
  return 0;
 BaseComm* pBC = (BaseComm*)pParam;
 // 串口事件
 OVERLAPPED tOverLaped;
 tOverLaped.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
 while(pBC->IsRunThread)
 {
  DWORD dwEvtMask, dwResult;
  WaitCommEvent(pBC->hComm,&dwEvtMask, &tOverLaped);
  dwResult = WaitForSingleObject(tOverLaped.hEvent,100);
  if( WAIT_OBJECT_0 == dwResult)
  {
   if( dwEvtMask&EV_RXCHAR == EV_RXCHAR)
   {
    //printf("收到接收数据信号/n");
    SetEvent(pBC->hCommRecv);
   }
   if( dwEvtMask&EV_TXEMPTY == EV_TXEMPTY)
   {
    //printf("发送完毕信号/n");
    SetEvent(pBC->hCommSend);
   }
  }
 }
 return 0;
}

BaseComm::BaseComm(void)
{
 hCommFree = CreateEvent(NULL,FALSE,TRUE,NULL);
 hCommRecv = CreateEvent(NULL,FALSE,FALSE,NULL);
 hCommSend = CreateEvent(NULL,FALSE,FALSE,NULL);
 IsRunThread = false;
}

BaseComm::~BaseComm(void)
{
}

// 打开串口
// 输入: pPort - 串口名称或设备路径,可用"COM1"
//      nBaudRate - 波特率
//      nParity - 奇偶校验
//      nByteSize - 数据字节宽度
//      nStopBits - 停止位
bool BaseComm::OpenComm(wchar_t* pPort, int nBaudRate, int nByteSize, int nStopBits, int nParity)
{
 //接入串口
 hComm = CreateFile(pPort, // 串口名称或设备路径
  GENERIC_READ | GENERIC_WRITE, // 读写方式
  0,    // 共享方式:独占
  0,    // 默认的安全描述符
  OPEN_EXISTING, // 打开一个存在的串口
  FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED,    //异步方式打开
  0);    // 不需参照模板文件
 if( INVALID_HANDLE_VALUE == hComm)
 { 
  return false;  // 打开串口失败
 }
 Sleep(500);

 //清空串口错误标志并记录当前通信状态
 DWORD res;
 COMSTAT rst;
 ClearCommError(hComm,&res,&rst);

 // 设置输入输出缓冲区大小
 SetupComm(hComm, 1024, 1024);

 //串口参数处理
 DCB dcb;      // 串口控制块
 if( !GetCommState(hComm, &dcb))
 {// 读取DCB
  return false;  // 打开串口失败
 };  
 dcb.BaudRate = nBaudRate;
 dcb.ByteSize = nByteSize;
 dcb.Parity = nParity;
 dcb.StopBits = nStopBits;
 dcb.fParity = FALSE;   // 禁止奇偶校验
 dcb.fBinary = TRUE;    // 禁止流量控制
 dcb.fDtrControl = 0;
 dcb.fRtsControl = 0;
 dcb.fOutX = 0;
 dcb.fInX = 0;
 dcb.fTXContinueOnXoff = 0;
 if( !SetCommState(hComm, &dcb))  // 设置串口DCB
 {
  CloseComm();
  return false;
 }
 Sleep(200);


 if( !SetCommMask(hComm, EV_RXCHAR|EV_TXEMPTY))
 {// 串口事件: 接收到一个字符或发送区缓冲为空
  CloseComm();
  return false;
 }

 //超时处理
 COMMTIMEOUTS CommTimeOuts;
 GetCommTimeouts(hComm, &CommTimeOuts);
 CommTimeOuts.ReadIntervalTimeout = 100;    // 接收字符间最大时间间隔
 CommTimeOuts.ReadTotalTimeoutMultiplier = 1;  // 读操作时每字符的时间: 1 ms (n个字符总共为n ms)
 CommTimeOuts.ReadTotalTimeoutConstant = 500;  // 读数据总超时常量
 CommTimeOuts.WriteTotalTimeoutMultiplier = 1;  // 写操作时每字符的时间: 1 ms (n个字符总共为n ms)
 CommTimeOuts.WriteTotalTimeoutConstant = 100;  // 基本的(额外的)写超时时间: 100 ms
 if( !SetCommTimeouts(hComm, &CommTimeOuts))
 {
  CloseComm();
  return false;
 }

 ClearCommBuff();

 return true;
}

bool BaseComm::CloseComm()
{
 if( INVALID_HANDLE_VALUE != hComm)
 {
  SetCommMask(hComm, 0);  // 串口事件
  ClearCommBuff();
  CloseHandle(hComm);
  hComm = INVALID_HANDLE_VALUE;
  return true;
 }
 return false;
}

void BaseComm::ClearCommBuff()
{
 if( INVALID_HANDLE_VALUE != hComm)
 {
  PurgeComm(hComm, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR );  // 清除收发缓冲
 }
}

// 创建监听线程
bool BaseComm::CreateCommEventThread()
{
 if( IsRunThread)
  return false;
 IsRunThread = true;
 if( !CreateNewThread(CommEventThread,this,hCommEventThread,dwCommEventThreadID))
 {
  IsRunThread = false;
  Sleep(300);
 }
 return true;
}

void  BaseComm::ExitCommEventThread()
{
 IsRunThread = false;
}

bool BaseComm::CreateNewThread(lpCallBack *pfnThrearoc,LPVOID pParam,
   HANDLE &hNewThread,DWORD &dwThreadId)
{
 //创建新线程
 hNewThread = chBEGINTHREADEX(NULL,0,pfnThrearoc,pParam,0,&dwThreadId);
 if( INVALID_HANDLE_VALUE == hNewThread)
 {
  return false;
 }
 return true;
}


// 写串口
// 输入: pData - 待写的数据缓冲区指针
//       nLength - 待写的数据长度
// 返回: 实际写入的数据长度
bool BaseComm::WriteComm(void* pData, int nLength)
{
 Sleep(500);
 DWORD res;
 res = WaitForSingleObject(hCommFree,INFINITE);
 if( WAIT_OBJECT_0 == res)
 {
  //printf("写操作!/n");
  COMSTAT rst;
  ClearCommError(hComm,&res,&rst);

  OVERLAPPED wOverLaped;
  wOverLaped.InternalHigh = 0;
  wOverLaped.Offset = 0;
  wOverLaped.OffsetHigh = 0;
  wOverLaped.hEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
  DWORD factdata = 0;
  if( WriteFile(hComm,pData,nLength,&factdata,&wOverLaped))
  {
   SetEvent(hCommFree);
   return true;
  }
  else
  {
   res = WaitForSingleObject(wOverLaped.hEvent,INFINITE);
   if( WAIT_OBJECT_0 == res)
   {
    if(  wOverLaped.InternalHigh+factdata >= nLength)
    {
     SetEvent(hCommFree);
     return true;
    }
   }
  }
 }
 SetEvent(hCommFree);
 return false;
}

// 读串口
// 输入: pData - 待读的数据缓冲区指针
//       nLength - 待读的最大数据长度
// 返回: 实际读出的数据长度
bool BaseComm::ReadComm(void* pData, int nLength)
{
 DWORD res;
 res = WaitForSingleObject(hCommRecv,INFINITE);
 if( WAIT_OBJECT_0 != res)
  return false;
 res = WaitForSingleObject(hCommFree,INFINITE);
 if( WAIT_OBJECT_0 == res)
 {
  COMSTAT rst;
  do
  {
   ClearCommError(hComm,&res,&rst);
  }while( rst.cbInQue <nLength);
  
  DWORD factdata = 0;
  OVERLAPPED rOverLaped;
  rOverLaped.InternalHigh = 0;
  rOverLaped.Offset = 0;
  rOverLaped.OffsetHigh = 0;
  rOverLaped.hEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
  if( ReadFile(hComm,pData,nLength,&factdata,&rOverLaped))
  {
   SetEvent(hCommFree);
   return true;
  }
  else
  {
   res = WaitForSingleObject(rOverLaped.hEvent,INFINITE);
   SetEvent(hCommFree);
   return true;
  }  
 }
 SetEvent(hCommFree);
 return false;
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值