win32 API 串口 编程 (二) 异步方式

代码参考网页:

https://www.codeguru.com/cpp/i-n/network/serialcommunications/article.php/c2503/CSerial--A-C-Class-for-Serial-Communications.htm

该代码比较精炼,为了兼容COM10以上以及unicode编码 做了部分修改。

用VS2010 建立一个 控制台工程,
将Serial.cpp 和Serial.h 放入工程目录中的serial目录下:

测试对象: TC35 GSM/GPRS Modem 模块—- 串口设备

发送AT指令: AT\r\n 返回 AT\r\r\nOK\r\n

main文件中的代码:

// SerialTestA.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <windows.h>
#include "serial/Serial.h"


#define TIMEOUT  150

int SeriaReadData(CSerial *ptSerial,char * buf,int* ptnBufLen,int nBufSize)
{

    char rcvBuf[500];
    int nBytesRead;
    int nRet ;
    int nCnt = 0;
    int nNum = 0;
    int ret ;


    if(buf == NULL){

        return -1;
    }

    if(ptnBufLen == NULL){

        return -1;
    }

    memset(rcvBuf,0,sizeof(rcvBuf));

    nCnt = 0 ;

    while(nCnt++ < TIMEOUT){

        nRet = ptSerial->ReadDataWaiting();

        if(nRet){

            printf("nRet = %d\r\n",nRet);
            nBytesRead = ptSerial->ReadData(rcvBuf, 500);

            printf("nBytesRead = %d,%s\r\n",nBytesRead,rcvBuf); 

            if(nNum + nBytesRead >= nBufSize){

                return -2 ; //防止溢出
            }

            memcpy(buf + nNum ,rcvBuf,nBytesRead);  

            nNum = nNum + nBytesRead;

            *ptnBufLen = nNum ;

            if((nBytesRead >=1)&&(nNum >=4)){

                if(buf[nNum-1] == 0x0a){

                    if((buf[nNum-2] == 0x0d)&&(buf[nNum-3] == 'K')&&(buf[nNum-4] == 'O')){

                        break;
                    }
                }   
            }           

        }else{

            Sleep(10);//20ms
        }
    }

    if(nCnt >=TIMEOUT){
        printf("Time Out\r\n");
        return -1;
    }

    return  0 ;
}


int _tmain(int argc, _TCHAR* argv[])
{
    CSerial serial;
    BOOL bRet ;
    int nBytesRead;
    int nRet ;
    int nCnt = 0;

    char szMessage[] = "AT\r\n";

    char RecvBuf[500];

    memset(RecvBuf,0,sizeof(RecvBuf));

    bRet = serial.Open(6, 9600);

    if(bRet == FALSE){

        return 0;
    }

    printf("send data = %s\r\n",szMessage);
    printf("strlen(szMessage)= %d\r\n",strlen(szMessage));

    serial.SendData(szMessage, strlen(szMessage));


    SeriaReadData(&serial,RecvBuf,&nBytesRead,500);

    printf("AA %s\r\n",RecvBuf);


    return 0;
}

Serial.cpp 代码:

// Serial.cpp

#include "stdafx.h"
#include <windows.h>
#include "Serial.h"

CSerial::CSerial()
{

    memset( &m_OverlappedRead, 0, sizeof( OVERLAPPED ) );
    memset( &m_OverlappedWrite, 0, sizeof( OVERLAPPED ) );
    m_hIDComDev = NULL;
    m_bOpened = FALSE;

}

CSerial::~CSerial()
{

    Close();

}

BOOL CSerial::Open( int nPort, int nBaud )
{

    if( m_bOpened ) return( TRUE );

    TCHAR szPort[15];
    TCHAR szComParams[50];
    DCB dcb;

    wsprintf( szPort, TEXT("\\\\.\\COM%d"), nPort );

    m_hIDComDev = CreateFile( szPort, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL );
    if( m_hIDComDev == NULL ) return( FALSE );

    memset( &m_OverlappedRead, 0, sizeof( OVERLAPPED ) );
    memset( &m_OverlappedWrite, 0, sizeof( OVERLAPPED ) );

    COMMTIMEOUTS CommTimeOuts;
    CommTimeOuts.ReadIntervalTimeout = 0xFFFFFFFF;
    CommTimeOuts.ReadTotalTimeoutMultiplier = 0;
    CommTimeOuts.ReadTotalTimeoutConstant = 0;
    CommTimeOuts.WriteTotalTimeoutMultiplier = 0;
    CommTimeOuts.WriteTotalTimeoutConstant = 5000;
    SetCommTimeouts( m_hIDComDev, &CommTimeOuts );

    wsprintf( szComParams, TEXT("COM%d:%d,n,8,1"), nPort, nBaud );

    m_OverlappedRead.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
    m_OverlappedWrite.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );

    dcb.DCBlength = sizeof( DCB );
    GetCommState( m_hIDComDev, &dcb );
    dcb.BaudRate = nBaud;
    dcb.ByteSize = 8;
    unsigned char ucSet;
    ucSet = (unsigned char) ( ( FC_RTSCTS & FC_DTRDSR ) != 0 );
    ucSet = (unsigned char) ( ( FC_RTSCTS & FC_RTSCTS ) != 0 );
    ucSet = (unsigned char) ( ( FC_RTSCTS & FC_XONXOFF ) != 0 );
    if( !SetCommState( m_hIDComDev, &dcb ) ||
        !SetupComm( m_hIDComDev, 10000, 10000 ) ||
        m_OverlappedRead.hEvent == NULL ||
        m_OverlappedWrite.hEvent == NULL ){
        DWORD dwError = GetLastError();
        if( m_OverlappedRead.hEvent != NULL ) CloseHandle( m_OverlappedRead.hEvent );
        if( m_OverlappedWrite.hEvent != NULL ) CloseHandle( m_OverlappedWrite.hEvent );
        CloseHandle( m_hIDComDev );
        return( FALSE );
        }

    m_bOpened = TRUE;

    return( m_bOpened );

}

BOOL CSerial::Close( void )
{

    if( !m_bOpened || m_hIDComDev == NULL ) return( TRUE );

    if( m_OverlappedRead.hEvent != NULL ) CloseHandle( m_OverlappedRead.hEvent );
    if( m_OverlappedWrite.hEvent != NULL ) CloseHandle( m_OverlappedWrite.hEvent );
    CloseHandle( m_hIDComDev );
    m_bOpened = FALSE;
    m_hIDComDev = NULL;

    return( TRUE );

}

BOOL CSerial::WriteCommByte( unsigned char ucByte )
{
    BOOL bWriteStat;
    DWORD dwBytesWritten;

    bWriteStat = WriteFile( m_hIDComDev, (LPSTR) &ucByte, 1, &dwBytesWritten, &m_OverlappedWrite );
    if( !bWriteStat && ( GetLastError() == ERROR_IO_PENDING ) ){
        if( WaitForSingleObject( m_OverlappedWrite.hEvent, 1000 ) ) dwBytesWritten = 0;
        else{
            GetOverlappedResult( m_hIDComDev, &m_OverlappedWrite, &dwBytesWritten, FALSE );
            m_OverlappedWrite.Offset += dwBytesWritten;
            }
        }

    return( TRUE );

}

int CSerial::SendData( const char *buffer, int size )
{

    if( !m_bOpened || m_hIDComDev == NULL ) return( 0 );

    DWORD dwBytesWritten = 0;
    int i;
    for( i=0; i<size; i++ ){
        WriteCommByte( buffer[i] );
        dwBytesWritten++;
        }

    return( (int) dwBytesWritten );

}

int CSerial::ReadDataWaiting( void )
{

    if( !m_bOpened || m_hIDComDev == NULL ) return( 0 );

    DWORD dwErrorFlags;
    COMSTAT ComStat;

    ClearCommError( m_hIDComDev, &dwErrorFlags, &ComStat );

    return( (int) ComStat.cbInQue );

}

int CSerial::ReadData( void *buffer, int limit )
{

    if( !m_bOpened || m_hIDComDev == NULL ) return( 0 );

    BOOL bReadStatus;
    DWORD dwBytesRead, dwErrorFlags;
    COMSTAT ComStat;

    ClearCommError( m_hIDComDev, &dwErrorFlags, &ComStat );
    if( !ComStat.cbInQue ) return( 0 );

    dwBytesRead = (DWORD) ComStat.cbInQue;
    if( limit < (int) dwBytesRead ) dwBytesRead = (DWORD) limit;

    bReadStatus = ReadFile( m_hIDComDev, buffer, dwBytesRead, &dwBytesRead, &m_OverlappedRead );
    if( !bReadStatus ){
        if( GetLastError() == ERROR_IO_PENDING ){
            WaitForSingleObject( m_OverlappedRead.hEvent, 2000 );
            return( (int) dwBytesRead );
            }
        return( 0 );
        }

    return( (int) dwBytesRead );

}

Serial.h

// Serial.h

#ifndef __SERIAL_H__
#define __SERIAL_H__

#define FC_DTRDSR       0x01
#define FC_RTSCTS       0x02
#define FC_XONXOFF      0x04
#define ASCII_BEL       0x07
#define ASCII_BS        0x08
#define ASCII_LF        0x0A
#define ASCII_CR        0x0D
#define ASCII_XON       0x11
#define ASCII_XOFF      0x13

class CSerial
{

public:
    CSerial();
    ~CSerial();

    BOOL Open( int nPort = 2, int nBaud = 9600 );
    BOOL Close( void );

    int ReadData( void *, int );
    int SendData( const char *, int );
    int ReadDataWaiting( void );

    BOOL IsOpened( void ){ return( m_bOpened ); }

protected:
    BOOL WriteCommByte( unsigned char );

    HANDLE m_hIDComDev;
    OVERLAPPED m_OverlappedRead, m_OverlappedWrite;
    BOOL m_bOpened;

};

#endif

运行结果1:

send data = AT

strlen(szMessage)= 4
nRet = 9
nBytesRead = 9,AT
OK

AA AT
OK

请按任意键继续. . .

运行结果2:

send data = AT

strlen(szMessage)= 4
nRet = 7
nBytesRead = 7,AT
OK
nRet = 2
nBytesRead = 2,

OK
AA AT
OK

请按任意键继续. . .

由于是使用的:力特的FT232 USB 转串口 ,可以通过 BUS HOUND,监控发送的数据

这里写图片描述

这里写图片描述
Bus Hound 6.01 capture on Windows Vista Service Pack 1 (x64). Complements of www.perisoft.net

Device - Device ID (followed by the endpoint for USB devices)
(13) USB Serial Port (COM6)
Phase - Phase Type
IN Data in transfer
OUT Data out transfer
Data - Hex dump of the data transferred
Descr - Description of the phase
Delta - Elapsed time from the previous phase to the current phase
Cmd… - Position in the captured data
Driver - Driver that submitted the command

Device Phase Data Description Delta Cmd.Phase.Ofs(rep) Driver


13 OUT 41 A 23mn 258.1.0 unknown
13 OUT 54 T 1.0ms 259.1.0 unknown
13 OUT 0d . 951us 260.1.0 unknown
13 OUT 0a . 1.0ms 261.1.0 unknown
13 IN 41 54 0d 0d 0a 4f 4b 0d 0a AT…OK.. 85ms 262.1.0 unknown

备注:

Preface

This class is meant as a very simple alternative to the more robust, feature-rich CSerialPort class presented by Remon Spekreijse. In other words, if you need a very simple class to read or write data to the serial port, then this class might be perfect for you. However, if you need more control over just how the serial communications is to be conducted, then Remon’s very fine class will probably be what you want.

CSerial class member functions

CSerial::CSerial() -
CSerial::CSerial() - Basic c’tor that takes no arguments.
CSerial::Open(int nPort = 2, int nBaud = 9600 ) - This member function is used to open the serial port. It takes two interger arguments. The first argument contains the port number where the valid entries are 1 through 4. The second argument is the baud rate. Valid values for this argument are 1200, 2400, 4800, 9600, 19200, 38400 and 76800. This function returns TRUE if successful. Otherwise, it returns a value of FALSE.
CSerial::Close() - While the d’tor will automatically close the serial port for you, this function has been added just in case there is a reason that you need to explicit close the port.
CSerial::SendData(const char , int) - This function writes data from a buffer to the serial port. The first argument it takes is a const char to a buffer that contains the data being sent. The second argument is the number of bytes being sent. This function will return the actual number of bytes that are succesfully transmitted.
CSerial::ReadDataWaiting(void) - This function simply returns the number of bytes that waiting in the communication port’s buffer. It basically allows you to “peek” at the buffer without actually retrieving the data.
CSerial::ReadData(void*, int) - This function reads data from the port’s incoming buffer. The first argument that it takes is a void* to a buffer into which the data will be placed. The second argument is an integer value that gives the size of the buffer. The return value of this function contains the number of bytes that were successfully read into the provided data buffer.

完整的vs2010 控制台工程下载地址:
https://download.csdn.net/download/wowocpp/10452708

猜你喜欢

转载自blog.csdn.net/wowocpp/article/details/80538432