adinxu
by adinxu
2 分钟 阅读用时

分类

标签

WIN32API串口接收数据简单测试

 

ReadFile:

BOOL ReadFile (
   HANDLE hFile, //用CreateFile获得的文件句柄
   LPVOID lpBuffer, //输入缓冲区首址
   DWORD nNumberOfBytesToRead,//设定读入字节数
   LPDWORD lpNumberOfByteRead, //实际读入字节数
   LPOVERLAPPED lpOverlapped //重叠操作方式数据结构地址
   );

在同步方式下,调用ReadFile或WriteFile后,当实际读写操作完成或发生超时时才返回调用程序。而异步方式函数在启动接收或发送过程后立即返回,程序继续向下执行(实际上是开启了另一线程来等待完成读写操作)。程序在调用ReadFile和WriteFile时必须提供一个Overlapped数据结构指针,(若通过激发事件来接收数据。则该结构中中的hevent需要创建,其后的程序必须借助于该事件同步对象,完成数据的接收和发送过程。若通过串口句柄来接收数据,可以不创建hevent。)如果你要求一个文件操作为overlapped,而操作系统把这个“操作请求”放到队列中等待执行,那么ReadFile()和WriteFile()都会传回FALSE表示失败。你必须调GetLastError()并确定它传回ERROR_IO_PENDING,那意味着“overlapped  I/O请求”被放进队列之中等待执行。

另外有这样一段:For an hFile that supports byte offsets, if you use this parameter you must specify a byte offset at which to start reading from the file or device. This offset is specified by setting the Offset and OffsetHigh members of the OVERLAPPED structure. For an hFile that does not support byte offsets, Offset and OffsetHigh are ignored.

即:对于支持字节偏移的hFile,如果使用此参数,则必须指定要从文件或设备开始读取的字节偏移量。通过设置OVERLAPPED结构的Offset和OffsetHigh成员 来指定此偏移量 。对于不支持字节偏移的 hFileOffset和 OffsetHigh将被忽略。

我本来想读串口时直接读帧尾,结果实验了一下,好像读串口就是不支持字节偏移的 hFile==

SetCommMask:

BOOL WINAPI SetCommMask(
 __in  HANDLE hFile,// 串口句柄
 __in  DWORD dwEvtMask//事件,可通过位或的方式指定多个事件

);

事件屏蔽 含义 
EV_BREAK  检测到一个输入中断 
EV_CTS  CTS信号发生变化 
EV_DSR  DSR信号发生变化 
EV_ERR  发生行状态错误 
EV_RING  检测到振铃信号 
EV_RLSD  RLSD(CD)信号发生变化 
EV_RXCHAR  输入缓冲区接收到新字符 
EV_RXFLAG  使用SetCommState()函数设置的DCB结构中的等待字符已被传入输入缓冲区中。 
EV_TXEMPTY  发送缓冲区为空

设置你关心的事件,当此事件发生时,将得到事件通知

EV_RXCHAR 每当一个新字符到达都会收到一次通知。。。

EV_RXFLAG特定字符到达收到通知

WaitCommEvent:

BOOL WINAPI WaitCommEvent(
 __in  HANDLE hFile,// 串口句柄
 __out LPDWORD lpEvtMask,// Out型指针,接收事件标志
 __in  LPOVERLAPPED lpOverlapped);//接收事件信息事件状态

当由SetCommMask函数所指定的事件产生时这个函数将返回TRUE。

 

 如果hfile是以FILE_FLAG_OVERLAPPED即异步方式打开,而且lpOverlappedis 即指向串口异步结构体overlapped的指针不为空,waitcommevent将表现为异步操作。在这种情况下,异步结构体OVERLAPPED 必须有一个由人工复位的事件的句柄hevent(用CreateEvent创建 )。

如果异步操作没有立即完成,WaitCommEvent返回FALSE ,用GetLastError可以得到返回值 ERROR_IO_PENDING,这表明操作在后台执行。当不能立即返回时,系统把hevent设置成无信号状态,而当等待事件发生,或一个错误产生,函数会返回,而hevent被设置为有信号。运行线程可以调用等待函数(如waitforsingleobject等) 来确定执行状态,然后用GetOverlappedResult 来确定WaitCommEvent操作的结构

<pre>SetCommMask(fd,EV_RXCHAR);//设定串口接收事件</pre><pre>if(!WaitCommEvent(fd,&Event,&m_ov))//等待事件没有立即发生

        {
            switch(GetLastError())
            {
            case ERROR_IO_PENDING: std::cout&lt;&lt;"pending...\n";break;
            default :
                return ;
            }
        }
        WaitForSingleObject(m_ov.hEvent,INFINITE);
        std::cout&lt;&lt;"data is arrived\n";
        ReadFile(fd,ch,1,&amp;read,&amp;m_ov);
        std::cout&lt;&lt;"read complete\n";
        //ResetEvent(m_ov.hEvent);
        WaitForSingleObject(m_ov.hEvent,INFINITE);
        std::cout&lt;&lt;"function leave\n";</code></pre>hevent被设置为必须人工置位,通过上面测试程序可知,wait和read都不会将hevent置为无信号,必须手动置位。指定串口监视事件后,hevent被用作保存监视事件激发状态,此时readfile用串口句柄通知是否异步操作完成。

GetOverlappedResult:

BOOL GetOverlappedResult(
HANDLE hFile, //用CreateFile获得的文件句柄

LPOVERLAPPED lpOverlapped,//指向一个在启动重叠操作时指定的OVERLAPPED结构(即读写函数中指定的OverLapped结构)

LPDWORD lpNumberOfBytesTransferred,//实际传输的字节数
 BOOL bWait, //是否等待悬挂的重叠操作完成,若为TRUE,则此函数直到操作完成后才返回
     );

还未完成异步传输返回0

WaitForSingleObject:

DWORD WaitForSingleObject(

  HANDLE hHandle,// 一个事件的句柄,可以是串口句柄,也可以是事件句柄

  DWORD dwMilliseconds//时间间隔

  );

如果事件是有信号状态返回WAIT_OBJECT_0,如果时间超过dwMilliseconds值但时间事件还是无信号状态则返回WAIT_TIMEOUT。

WaitForSingleObject函数用来检测hHandle事件的信号状态,在某一线程中调用该函数时,线程暂时**挂起,如果在挂起的dwMilliseconds毫秒内,线程所等待的对象变为有信号状态,则该函数立即返回;如果超时时间已经到达dwMilliseconds毫秒,但hHandle所指向的对象还没有变成有信号状态,函数照样返回。可根据返回值确定函数执行 情况。参数dwMilliseconds有两个具有特殊意义的值:0和INFINITE。若为0,则该函数立即返回;若为INFINITE,则线程一直被挂起**,直到hHandle所指向的对象变为有信号状态时为止。

MsgWaitForMultipleObjects function

#include &lt;windows.h&gt;
#include &lt;iostream&gt;
#define use_hfile 0//使用文件(串口)句柄
#define use_hevent 1//使用事件   可用SetEvent(m_ov.hEvent)来查看GetOverlappedResult确实根据hevent判定

#define use_WaitForSingleObject 0
#define use_GetOverlappedResult 1
int com_open();
int com_read();
    HANDLE hCom;//串口句柄
    OVERLAPPED m_ov;//异步读写所需结构体
    char* buf=new char[128];//读取数据存储
    DWORD read;//读取字节数
int com_open()
{
            hCom=CreateFile(
                           "COM5",
                           GENERIC_READ|GENERIC_WRITE,
                           0,
                           NULL,
                           OPEN_EXISTING,
                           FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED,
                           NULL
                           );
    if(hCom == INVALID_HANDLE_VALUE)  return -1;
    else std::cout&lt;&lt;"COM5 OPEN SUCCESS\n";
    if(!SetupComm(hCom,1024,1024)) return -2;
    else std::cout&lt;&lt;"COM5 setup SUCCESS\n";
    COMMTIMEOUTS cto = {0,0,0,0,0};//第一个参数为0表示无限等待下一字节,为MAXDWORD表示立即激活相应句柄
    if(!SetCommTimeouts(hCom,&amp;cto)) return -3;
    else std::cout&lt;&lt;"COM5 SetCommTimeouts SUCCESS\n";
    DCB dcb;
    memset(&amp;dcb,0,sizeof(dcb));//DCB初始化
    dcb.DCBlength = sizeof(dcb);
    GetCommState(hCom, &amp;dcb);
    dcb.BaudRate =600;
    dcb.Parity = NOPARITY;
    dcb.StopBits = ONESTOPBIT;
    dcb.ByteSize = 8;
    /*dcb.fBinary = 1;//指定是否允许二进制模式
    dcb.fOutxCtsFlow=false;
    dcb.fDtrControl=false;
    dcb.fRtsControl = RTS_CONTROL_DISABLE;
    dcb.fOutX=false;
    dcb.fInX=false;
    dcb.XoffChar = 0x13;
    dcb.XonChar = 0x11;
    dcb.XonLim = (1024 &gt;&gt; 2) * 3;
    dcb.XoffLim = (1024 &gt;&gt; 2) * 3;*/
    if(!SetCommState(hCom,&amp;dcb)) return -4;
    else std::cout&lt;&lt;"COM5 setCommState SUCCESS\n";
    PurgeComm(hCom,PURGE_TXCLEAR|PURGE_RXCLEAR);

    return 0;
}
int com_read()
{
    memset(&amp;m_ov,0,sizeof(OVERLAPPED));
    #if use_hevent
    m_ov.hEvent = CreateEvent(NULL,// LPSECURITY_ATTRIBUTES lpsa不可被继承
						    TRUE, // BOOL fManualReset 是否人工复位
						    false,//TRUE, // BOOL fInitialState 初始状态 有无信号
						    NULL); // LPTSTR lpszEventName 匿名
    if(m_ov.hEvent == INVALID_HANDLE_VALUE) return -1;
    else std::cout&lt;&lt;"ovevent creat success\n";
    #endif
    if(!ReadFile(hCom,buf,50,&amp;read,&amp;m_ov))
    {
        if(GetLastError()==ERROR_IO_PENDING)
        {
            std::cout&lt;&lt;"reading...\n";
            return 0;
        }
        else
        {
          return -2;
        }
    }
    else return -3;
}
int main()
{
    int i=0;
    i=com_open();
    if(!i)
    {
        i=com_read();
        if(!i)
        {
            #if use_hfile
            #if use_WaitForSingleObject
            WaitForSingleObject(hCom,INFINITE);//通过串口句柄
            #endif

            #if use_GetOverlappedResult
            GetOverlappedResult(    hCom,
                                    &amp;m_ov,
                                    &amp;read,
                                    true
                                );
            #endif
            #endif

            #if use_hevent
            #if use_WaitForSingleObject
            WaitForSingleObject(m_ov.hEvent,INFINITE);//通过串口句柄
            #endif
            #if use_GetOverlappedResult
            GetOverlappedResult(
                                    hCom,
                                    &amp;m_ov,
                                    &amp;read,
                                    true
                                );
            #endif
            #endif // use_hevent
            std::cout&lt;&lt;buf;
            delete[] buf;
            return 0;
        }
        else std::cout&lt;&lt;"start read err\n";
        delete[] buf;
        return i;
    }
    else std::cout&lt;&lt;"open com5 err\n";
    delete[] buf;
    return i;
}


ClearCommError: