WINCE串口编程

正如CE的帮助文档所说,串口通信是最简单的通信之一;稍麻烦的是在读数据方面;其实串与Windows下串口编程相似在WinCE下串口编程也主要是“打开串口”-->“发送数据”-->“接收数据”-->“关闭串口”等,当然“打开串口”后需要对串口进行必要的设置否则无法操作或数据出现乱码等;WinCE下串口操作步骤如下:

一、打开串口

     HANDLE hSerial;    

     hSerial = CreateFile(L"COM1:", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);

     if(m_hSerial == NULL)

     {

      //串口打开失败

      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))

     {

      //配置串口失败

      return;

     }

     //配置超时值

     COMMTIMEOUTS CommTimeouts;

     GetCommTimeouts(hSerial, &CommTimeouts);

     CommTimeouts.ReadIntervalTimeout = MAXDWORD; 

     CommTimeouts.ReadTotalTimeoutMultiplier = 10; 

     CommTimeouts.ReadTotalTimeoutConstant = 10; 

     CommTimeouts.WriteTotalTimeoutMultiplier = 50; 

     CommTimeouts.WriteTotalTimeoutConstant = 100; 

     if (!SetCommTimeouts(hSerial, &CommTimeouts))

     {

      //不能设置超时参数;

      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)

         {

          //接收缓冲区已满

          return -1;

         }

        } 

       } while (dwBytes == 1);

       if(iCounter == 0) //没接到数据

       {

        continue;

       }

       //保存数据

       char* pTmp = new char[iCounter + 1];

       if(pTmp == NULL)

       {

        //内存不足,接收串口数据线程关闭

        return -1;

       }

       memcpy(pTmp, ReceiveBuf, iCounter);

       pTmp[iCounter] = NULL; //字符串结尾

       //创建新线程处理数据 

       AfxBeginThread(ProcessData, pTmp); //在ProcessData函数中处理数据。别忘了delete[] pTmp;

       iCounter = 0; //清空计数器

      } //end while

      return 0;

     } 

     在ReadThread的代码中,对接收数据后的处理采用另外一个线程来执行,这种解决方法不适合所有需要,只适合读取终端设备返回来的少量数据。软件开发者要编写串口读线程代码应该具体问题具体分析。另外如果想在任意时刻停止读串口线程,应该按如下形式调用函数:

     SetCommMask(hPort,EV_RXCHAR|EV_TXEMPTY);

     EV_TXEMPTY表示当输出字符都发送出去作为一个事件。那么我们可以发送任意一个字符,这个字符发送出去后WaitCommEvent就返回。


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值