使用winAPI串口通信(二)

  采用同步方式的查询方式读取串口数据时,若由于串口操作耗费较长的时间,则程序会被挂起.为解决这种问题,可以在读取数据时采用重叠I/O操作.此时,读写数据的操作在单独的线程 中进行,发出读写要求的主线程可以继续运行.当读写数据成功后,读写数据线程可以通过某种方式通知主线程.两个线程协调工作 ,可以明显提高程序的效率.

         为了实现重叠I/O操作,主要有如下几个编程步骤:  定义全局变量、创建串口、发出读写操作、读写线程函数的建立、关闭串口等.

          1. 定义全局变量

               HANDLE     hCom;          //串口句柄

               DWORD    ThreadProcWrite(LPVOID  pParam);       //写线程函数

               DWORD    ThreadProcRead(LPVOID  pParam);      //读线程函数

               OVERLAPPED     Wol = { 0 };          //写操作OVERLAPPED结构变量

               OVERLAPPED     Rol = { 0 };          //读操作OVERLAPPED结构变量

               HANDLE    hThreadWrite;         //写线程句柄

               HANDLE    hThreadRead;        //读线程句柄

               HWND     hWnd;        //窗口句柄

          2. 创建串口

               hCom = CreateFile ( "COM2",

                             GENERIC_READ | GENERIC_WRITE,

                             0,

                             NULL,

                             OPEN_EXISTING,

                             FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,//使用重叠方式

                             NULL );

                      if( hCom != INVALID_HANDLE_VALUE)

                 {

                             SetupComm(hCom,1024,512);

                              DCB   myDCB;

                              GetCommState( hCom,&myDCB);

                              myDCB.BaudRate=CBR_19200;

                              myDCB.fBinary=TRUE;

                              myDCB.fParity=TRUE;

                              myDCB.ByteSize=8;

                              myDCB.Parity=ODDPARITY;

                              myDCB.StopBits=ONESTOPBIT;

                              SetCommState(hCom,&myDCB);

                 }

                else

                {

                         AfxMessageBox("创建串口失败!");

                }

                hWnd = GetSafeHwnd();          //获取当前窗口的句柄

          3. 发出读写操作

               (1) 读操作

                    在读操作中,只是启动读线程.实际的读操作在读线程函数中完成.

                    DWORD    dwThreadID;

                    DWORD    dwParam;

                    hThreadRead = CreateThread ( NULL,

                                                0,

                                                (LPTHREAD_START_ROUTINE)ThreadProcRead,

                                                &dwParam,

                                                0,       //创建线程后,立即执行该线程

                                                &dwThreadID);

                     if(hThreadRead==NULL)

                     {

                               AfxMessageBox("读线程创建失败!");

                     }

                           CreateThread()函数用于创建一个线程.

                    HANDLE   CreateThread (

                                       //线程安全属性,NULL表示该线程不能被继承

                                       LPSECURITY_ATTRIBUTES     lpThreadAttributes,

                                       //初始化栈大小.0表示默认值或按调用栈线程配置

                                       DWORD     dwStackSize,

                                       //执行函数名称

                                       LPTHREAD_START_ROUTINE      lpStartAddress,   

                                       LPVOID   lpParameter,           //向新线程传递的参数

                                       DWORD   dwCreationFlags,     //创建标志.0表示创建后立即执行 

                                                    LPDWORD     lpThreadId

                            );

                     (2) 写操作

                           在写操作中,同样只是启动写线程.实际的写操作在写线程函数中完成.

                           DWORD    dwThreadID;

                           DWORD    dwParam;

                           hThreadWrite = CreateThread( NULL,

                                                       0,

                                                       (LPTHREAD_START_ROUTINE)ThreadProcWrite,

                                                       &dwParam,

                                                       0,

                                                       &dwThreadID);

                             if(hThreadWrite==NULL)

                             {

                                       AfxMessageBox("写线程创建失败!");

                              }

                 4.读写线程函数的建立

                     读写的实际操作在读写线程函数中执行. 这两个函数都是全局函数.

                     (1) 读线程函数

                           在读线程函数中,首先应初始化重叠结构Rol的成员 hEvent,将其设置为无信号状态.当读操作完成或出现通信错误时,该变量会被自动设置为有信号状态.接下来就可以使用ReadFile()函数发出读 命令.若该读函数返回TRUE,说明读操作已经完成,可以处理读取的数据.若该读函数返回FALSE,说明读操作未完成.此时使用 WaitForSingleObject()函数等待读操作的结构。根据返回结果的不同,采取相应的处理代码即可.

                       DWORD     ThreadProcRead(LPVOID   pParam)

                       {

                               BYTE    myByte[20];

                               CString    myStr;

                               DWORD    dwRes;

                               DWORD    dwRead;

                               BOOL    fRes;

                               char    myChar[10];

                               Rol.hEvent = CreateEvent ( NULL,          //创建Rol的hEvent成员为无信号状态

                                                      TRUE;

                                                      FALSE;

                                                      NULL);

                               if (Rol.hEvent == NULL)

                               {

                                      AfxMessageBox ("hEvent 空");

                                      return -1;

                                }

                                if (ReadFile (hCom,         //串口句柄

                                                      &myByte,     //存放读取数据

                                                      3,         //要读取的字节数

                                                       NULL,

                                                       &Rol) )       //指向创建hCom时的Rol的指针

                                  {

                                           //AfxMessageBox("成功读出!");

                                          //在这里加入处理读取数据代码,数据存放在myByte数组中 
                                  }

                                 else

                                 {

                                           dwRes = WaitForSingleObject ( Rol.Event , 5000 );   //5秒超时

                                           switch(dwRes)

                                           {

                                                 case   WAIT_OBJECT_0:

                                                           if (!GetOverlappedResult (hCom,

                                                                 &Rol,

                                                                 &dwRead,    //实际读出的字节数

                                                                  TRUE) )     //TRUE表示直到操作完成函数才返回

                                                           {

                                                                 //操作失败,可以使用GetLastError()获取错误信息

                                                           }

                                                          else

                                                           {

                                                                     //操作成功完成,数据读取存入myByte中

                                                                     //这里加入处理数据的代码

                                                            }

                                                            break;

                                                case   WAIT_TIMEOUT:

                                                          //读操作失败,原因是超时

                                                          break;

                                                default:

                                                          //这里加入默认处理代码

                                                          break;

                                           }

                               }

                              closeHandle(Rol.hEvent);

                              return 0;

                        }

                        CreateEvent() 函数用来创建一个事件句柄,并设置其信号状态.

                        HANDLE    CreateEvent (

                                       //事件安全属性,NULL表示该事件句柄不能用于继承

                                      LPSECURITY_ATTRIBUTES   lpEventAttributes,

                                      BOOL    bManualReset,    //TRUE表示该事件需人工复位

                                      BOOL    bInitialState,   //事件对象的初始状态,TRUE表示有信号,反之无信号

                                       LPCTSTR    lpName       //指向事件对象的名称,NULL表示创建一个无名事件对象

                                      );

                  ReadFile()函数是读缓冲区命令,若该命令执行后返回TRUE,说明已经读成功. 若该命令返回FALSE,说明该命令返回时,读操作尚未完成,读操作继续在后台中进行. 此时使用waitForSingleObject()函数来获取后台 读命令的操作结果. 

                   DWORD    WaitForSingleObject (

                                      HANDLE     hHandle,       //指向等待对象的句柄

                                      DWORD     dwMilliseconds,       //超时时间

                                     );

                   GetOverlappedResult()函数其实与WaitForSingleObject()函数功能类似,都可以返回某操作的操作结果. 之所以使用GetOverlappedResult()函数,是因为它可以返回读操作实际读出的字节数量.

                   BOOL    GetOverlappedResult (

                                 HANDLE      hFile,           //指向串口句柄

                                 LPOVERLAPPED    lpOverlapped,       //执行读函数中使用的OVERLAPPED结构变量

                                 LPDWORD    lpNumberOfBytesTransferred,     //存放实际读出字节数量变量的地址

                                 BOOL     bWait      //设为TRUE表示读操作完成该函数才返回,若为FALSE表示如果操作未完成时函数将返回FALSE.

                                );

                     (2) 写线程函数

                          写线程函数所作操作与读线程函数的操作相似.首先初始化 Wol的hEvent事件成员,然后发出写命令WriteFile().若该写命令返回TRUE,说明写操作成功完成.若写命令返回FALSE,说明写操 作没有完成.使用WaitForSingleObject()函数等待写操作的结果,根据返回结果的不同,采取相应的处理代码.

                           DWORD     ThreadProcWrite(LPVOID   pParam)

                       {

                               BYTE    myByte[9];

                               CString    myStr;

                               DWORD    dwRes;

                               DWORD    dwWrite;

                               BOOL    fRes;

                               char    myChar[10];

                               for (i=0;i<=9;i++)

                               {

                                        myByte[i] = i;    //发送数据写入myByte中

                               }

                               Wol.Internal = 0;        //设置OVERLAPPED结构Wol

                               Wol.InternalHigh = 0;

                               Wol.Offset = 0;

                               Wol.OffsetHigh = 0;             

                               Wol.hEvent = CreateEvent ( NULL,          //创建Wol的hEvent成员为无信号状态

                                                      TRUE;

                                                      FALSE;

                                                      NULL);

                               if (Wol.hEvent == NULL)

                               {

                                      AfxMessageBox ("hEvent 空");

                                      return -1;

                                }

                                if (WriteFile (hCom,         //串口句柄

                                                      &myByte,     //存放待发送数据

                                                      3,         //欲发送的字节数

                                                       NULL,

                                                       &Wol) )       //指向创建hCom时的Wol的指针

                                  {

                                           //AfxMessageBox("发送成功!");

                                          //在这里加入处理读取数据代码,数据存放在myByte数组中 
                                  }

                                 else

                                 {

                                           dwRes = WaitForSingleObject ( Wol.Event , 500 );   //5ms超时

                                           switch(dwRes)

                                           {

                                                 case   WAIT_OBJECT_0:

                                                           if (!GetOverlappedResult (hCom,

                                                                 &Wol,

                                                                 &dwWrite,   

                                                                  TRUE) )     //TRUE表示直到操作完成函数才返回

                                                           {

                                                                 //操作失败,可以使用GetLastError()获取错误信息

                                                           }

                                                          else

                                                           {

                                                                     //发送数据成功

                                                                     //这里加入发送成功的处理代码

                                                            }

                                                            break;

                                                case   WAIT_TIMEOUT:

                                                          //读操作失败,原因是超时

                                                          break;

                                                default:

                                                          //这里加入默认处理代码

                                                          break;

                                           }

                               }

                              closeHandle(Wol.hEvent);

                              return 0;

                        }

                 5. 关闭串口

                     使用CloseHandle()函数关闭串口句柄.

                     CloseHandle(hCom);

http://blog.csdn.net/freedom0203/archive/2008/01/20/2054503.aspx

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值