VC串口通信简介及代码实现

 

串口通信是把CPU的并行数据字符转换成串行数据流发送出去,同时也可以从其他串行设备
接受数据供CPU或者程序处理。
串口按位发送和接受字节。虽然按字节并行通信慢,但是它很简单并且可以实现远距离通信。
串口通信是异步的,端口能够在一根线上发送同时在另一根线上接受,
串口通信的参数包含有波特率,数据位,停止位和奇偶校验。
现在就说说怎么用VC实现串口通信:
一,打开串口设备,涉及的主要有CreateFile,GetCommState,BuildCommDCB,SetCommState等WINDOWS API函数
代码为(其中m_hComm为成员变量):
//pCom类似'COM3'的字符串。
//pDefPara是串口通信参数
int ComDev::OpenDevice(const char *pCom, const char *pDefPara)

        char szMode[200] = {0};
    
        if (strnicmp(pCom, "COM", 3) != 0)
       {
               return -1;//参数错误
       }
 
         int nPort = atoi(pCom+3);
 
         if (nPort <= 0 || nPort > 255)
          {
                return -2 //端口号不合理
          }
 
           if (m_hCom != INVALID_HANDLE_VALUE)
          {
                      return -3; //设备句柄已经存在
          }      
 
          //构建通信设置,类似于"COM3: baud=9600 parity=N data=8 stop=1"
          sprintf(szMode, "%s: %s",pCom , pDefPara);
 
          char szPath[MAX_PATH + 1];
          sprintf(szPath, "\\\\.\\COM%d", nPort);
           m_hCom = CreateFile(szPath,      //文件名
         GENERIC_READ | GENERIC_WRITE,//读写
         0,        //共享模式
        NULL,       //安全
        OPEN_EXISTING,     //如何创建
        FILE_FLAG_OVERLAPPED, //文件属性
        NULL);       //拷贝属性的文件句柄
       if (m_hCom == INVALID_HANDLE_VALUE)
      {
              return -4; //找不到设备
      }
 
        DCB dcb;
         ZeroMemory(&dcb, sizeof(dcb));
         dcb.DCBlength = sizeof(dcb);
         //获取控制设备的当前参数设置
         BOOL bRet = GetCommState(m_hComm, &dcb);
        if (!bRet)
        { 
               closehandle(m_hCom);
                m_hComm = INVALID_HANDLE_VALUE;
               return -5; //获取通信状态失败
         }
      
       //修改当前控制设备参数为szMode里的内容
         bRet = BuildCommDCB(szMode, &dcb);
          if (!bRet)
         {
               closehandle(m_hCom)
               m_hComm = INVALID_HANDLE_VALUE;
               return -6
          }
      
       //设置当前通信控制模块。
          bRet = SetCommState(m_hComm, &dcb);
         if (!bRet)
          {
                closehandle(m_hCom)
                m_hComm = INVALID_HANDLE_VALUE;
                return -7
         }

         return 0;
}

 

二,发送数据
//pStr-----数据内容,
//dwLen----数据长度
//dwTimeout---发送超时时间
int CComDe::Send(const char *pStr, DWORD dwLen, DWORD dwTimeout)
{
  
   if (dwLen==0)
   {
      return 0;
   }
  
   if (dwlen < 0)
   {
      dwLen = strlen(pStr);
   }
  
   COMMTIMEOUTS CommTimeouts;

   if(!GetCommTimeouts(m_hComm,&CommTimeouts))
   {
 return -1;
   }
  
   CommTimeouts.WriteTotalTimeoutMultiplier= 0;
   CommTimeouts.WriteTotalTimeoutConstant = dwTotalTimeout;
   if(!SetCommTimeouts(m_hComm,&CommTimeouts))
   {
       return -2;
   }
  
   HANDLE hFile =  createEvent(NULL, TRUE, FALSE, NULL);
   OVERLAPPED Overlap;
   ZeroMemory(&Overlap, sizeof(Overlap));
   Overlap.hEvent = hFile;
  
   DWORD dwRet;
   BOOL bRet = WriteFile(m_hComm, pStr, dwLen, &dwRet, &Overlap);
   if (!bRet)
   {
 dwRet = GetLastError();
 if (dwRet != ERROR_IO_PENDING)
 {
     return -3;
 }

 dwRet = 0;
 bRet = GetOverlappedResult(m_hCom, &Overlap, &dwRet, TRUE);
 if (!bRet)
 {
     return -4;
 }
   }
  
   if (dwRet < dwLen)
   {
 return -4;
   }

}

三,接受数据
int CComDev::Read(char *pBuf, DWORD dwLen,
           DWORD dwTimeout, DWORD dwIntervalTimeout)
{

   if (dwLen == 0)
      return 0;

   int nRet = 0;

   COMMTIMEOUTS CommTimeouts;

   if(!GetCommTimeouts(m_hComm,&CommTimeouts))
   {
        return -1;
   }
  
   CommTimeouts.WriteTotalTimeoutMultiplier= 0;
   CommTimeouts.WriteTotalTimeoutConstant = dwTotalTimeout;
   if(!SetCommTimeouts(m_hComm,&CommTimeouts))
   {
       return -2;
   }

 //读串口
   HANDLE hFile =  createEvent(NULL, TRUE, FALSE, NULL);
   OVERLAPPED Overlap;
   ZeroMemory(&Overlap, sizeof(Overlap));
   Overlap.hEvent = hFile;
   DWORD dwRet = 0;
   BOOL bRet = ReadFile(m_hComm, pBuf, dwLen, &dwRet, &Overlap);
   if (!bRet)
   {
         dwRet = GetLastError();
       if (dwRet != ERROR_IO_PENDING)
     {
           return -1;
     }

       dwRet = 0;
       bRet = GetOverlappedResult(m_hComm, &Overlap, &dwRet, TRUE);
       if (!bRet && GetLastError() != ERROR_OPERATION_ABORTED)
      {       
            return -1;
       }
    }

    return dwRet;
}

四,刷新端口
void CComDev::flushport(int flag)
{
    char buf[100];
    DWORD dwError;
    COMSTAT stComStat;
 
 DWORD dwFlags = PURGE_TXABORT | PURGE_RXABORT;
 switch (Flag)
 {
 case 1:
  dwFlags |= PURGE_RXCLEAR;//终止读操作并且清除输入缓冲区
  break;
 case 2:
  dwFlags |= PURGE_TXCLEAR;//终止写操作并且清除输出缓冲区
  break;
 case 3:
  dwFlags |= PURGE_RXCLEAR | PURGE_TXCLEAR;
  break;
 default:
         break;
 }
 
 PurgeComm(m_hComm, dwFlags);
 ClearCommError(m_hComm, &dwError, &stComStat);
}


以上代码只是基本的内容,不够简明,根据具体项目有很大的改进空间,至少还得有个
日志模块去记录,这个读者自己去实现和编排了。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值