Windows CE下串口通信

网上已经有CE下串口通信的文章了。我之所以发表同样内容的文章是因为我的文章是一系列的,不会因为别人写过我就不写了。另外我对串口通信有着自己的观点。

  现在大多数的笔记本电脑都没有外置串口,这不奇怪,因为有更快更稳定的接口代替了串口。不过基于 Windows CE 的设备仍然保留着串口,而且目前看来串口的地位暂时不会动摇。目前流行的基于CE的设备很多都具有像导航、打电话等功能,而GPS、GSM/GPRS模块都是外置串口的终端设备,你想不用串口都不行。

  上面我说了我有着自己的观点,我的观点就是不要把串口通信封装成类。我不明白为什么有些人总要把串口封装成类呢。把一个事物封装成类,那这个事物就一定是不易改变的,如果每次编写都要修改,那封装成类就一点意义都没有了。设想如果MFC类总要改变的话,那我们用MFC编的程序也要修改同样次数了。如果编写超级终端一类的程序倒是可以将串口封装成类,因为超级终端只管输入命令和显示输出数据,不对输出数据进行处理,那读串口的函数就可以一直使用而不必更改。但事实上串口通信大多数用来与终端设备进行通信,需要对终端设备返回的数据进行处理。而返回的数据在什么时间返回、数据量的大小不是确定的,非要封装成类难度很大。

  正如CE的帮助文档所说,串口通信是最简单的通信之一。稍麻烦的是在读数据方面。

  一、打开串口    hSerial = CreateFile(L"COM1:",
               GENERIC_READ | GENERIC_WRITE,
               0,
               NULL,
               OPEN_EXISTING,
               0,
               NULL);
    if(m_hSerial == NULL)
    {
       ///L"串口打开失败";
       return;
    }
    ///配置串口
    DCB PortDCB;  
    PortDCB.DCBlength = sizeof(DCB);
    // 默认串口参数
    GetCommState(hSerial, &PortDCB);
    PortDCB.BaudRate = 115200; // baud
    PortDCB.ByteSize = 8;   // Number of bits/byte, 4-8
    PortDCB.Parity = NOPARITY;
    PortDCB.StopBits = ONESTOPBIT; 
    if (! SetCommState(hSerial, &PortDCB))
    {
       ///L"配置串口失败";
       return;
    }
    配置超时值
    COMMTIMEOUTS CommTimeouts;
    GetCommTimeouts(m_hSerial, &CommTimeouts);
    CommTimeouts.ReadIntervalTimeout = MAXDWORD; 
    CommTimeouts.ReadTotalTimeoutMultiplier = 10; 
    CommTimeouts.ReadTotalTimeoutConstant = 10;  
    CommTimeouts.WriteTotalTimeoutMultiplier = 50; 
    CommTimeouts.WriteTotalTimeoutConstant = 100;  
    if (!SetCommTimeouts(hSerial, &CommTimeouts))
    {
       ///L"不能设置超时参数";
       return;
    }         
  CE的串口驱动不支持重叠,这个大家都知道的。这样的话收和发就要分开。要接收串口数据就必须创建一个线程专门用于接收数据。串口的配置不需要设置很多参数,默认的配置大部分是不需要修改的。一般改动就是波特率、位数、奇偶校检等几项。超时值是需要改动的。ReadIntervalTimeout是指两个字符传送之间的超时时间。一次写操作的超时时间等于WriteTotalTimeoutMultiplier 乘以 要发送的字符数 加上WriteTotalTimeoutConstant。 单位是毫秒。读操作的超时和写类似。所以设置超时是一个关键。设置太小可能丢失数据。 

 二、关闭串口

  关闭串口用关闭句柄函数。if(hSerial != NULL) 
{
  CloseHandle(hSerial);
  hSerial = NULL;
}
三、向串口发送数据WriteFile (hSerial,      // 句柄
      &Byte,       // 数据缓冲区地址
      nByte,       // 数据大小
      &dwNumBytes,    // 返回发送出去的字节数
      NULL        // 不支持重叠
);
  向串口发送数据一般都会成功。需要注意的是如果终端设备需要一定处理时间或者称反应时间的话,那么两个写操作之间一定要注意时间间隔不能太小。具体的时间由终端设备的反应时间和缓冲区大小有关。

  四、读取串口数据

  串口麻烦就麻烦在读取数据上。除了考虑及时的读取数据外,还要解决接收到的数据的处理工作。如果在读取串口数据的线程中安置数据处理工作,那么可能会丢失数据(终端设备发送数据但是没收到),也有可能不会丢失(终端设备发送的数据的时间、大小都是确定的)。如果肯定接收的数据在处理工作结束后终端设备才发送数据,那么完全可以将数据处理工作放在读取串口的线程中。对于及时的读取数据,下面提供了一种解决办法:*** 假设接收的都是字符 ***
UINT ReadThread(LPVOID pParam) ?接收串口数据线程
{  
    HANDLE  hPort = *(HANDLE*)pParam;
    BYTE  Byte;
    int  iCounter = 0;
    DWORD  dwBytes;
    char  ReceiveBuf[1000]; ///缓冲区的大小  
       
    SetCommMask (hPort, EV_RXCHAR);  ///只接收字符
    while (hPort != INVALID_HANDLE_VALUE)
    {
       DWORD dwCommStatus;
       WaitCommEvent(hPort, &dwCommStatus, 0);
       SetCommMask (hPort, EV_RXCHAR); ///重新设置要等待的信号
        接收数据
       do
       {
           ReadFile(hPort, &Byte, 1, &dwBytes, 0);            
           if(dwBytes == 1)
           {
              ReceiveBuf[iCounter++] = Byte;
              if(iCounter == 1000)
              {
                  ///L"接收缓冲区已满";
                  return -1;
              }
           }             
       } while (dwBytes == 1);
       if(iCounter == 0) ?没接到数据
       {
           continue;
       }
       //保存数据
       char* pTmp = new char[iCounter + 1];
       if(pTmp == NULL)
       {
           ///L"内存不足,接收串口数据线程关闭";
           return -1;
       }
       memcpy(pTmp, ReceiveBuf, iCounter);
       pTmp[iCounter] = NULL;  字符串结尾
       创建新线程处理数据     
       
       在ProcessData函数中处理数据。别忘了delete[] pTmp;
       AfxBeginThread(ProcessData, pTmp); 
       iCounter = 0;     清空计数器
    } ///end while
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值