正确读取或写入串行端口Windows API

correctly reading or writing serial port Windows API

本文关键字:串行端口 Windows API 读取      更新时间:2023-10-16

我读过很多关于串行端口读写的问题。到目前为止,没有一个能帮我弄清楚我的代码缺少什么。c++的msdn示例有未定义的变量和缺少的括号,所以尽管我可以添加括号,但它仍然不起作用。以下是我在这一点上得到的。看起来我可以打开端口并进行配置,但我无法读取一个字节/字符的数据。我真的只想要一个简单的异步串行读/写程序来从Arduino读取。

class MY_SERIAL
{
HANDLE serialinstance;
DWORD      dwStoredFlags;
DWORD      dwRes;
DWORD      dwCommEvent;
OVERLAPPED osStatus = {0};
BOOL       fWaitingOnStat;
//dwStoredFlags = EV_BREAK | EV_CTS   | EV_DSR | EV_ERR | EV_RING | EV_RLSD | EV_RXCHAR |      EV_RXFLAG | EV_TXEMPTY ;

DCB dcb;
COMMTIMEOUTS timeouts;
COMMCONFIG serialconfig;

public:
char inBuffer[1000];
char outBuffer[100];
PDWORD noBytes;
void close_serial()
{
    CloseHandle(serialinstance);
}
//----------------------------------------------------
bool open_serial(LPCSTR portNumber)   // serial port name use this format  "\\.\COM10"
{
    serialinstance = CreateFile(portNumber, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
    if(serialinstance == INVALID_HANDLE_VALUE)
    {
        int error = GetLastError();
        printf("ERROR opening serial port  %srn", portNumber);
        if(error == 0x2){printf("ERROR_FILE_NOT_FOUNDrn");}
        if(error == 0x5){printf("ERROR_ACCESS_DENIEDrn");}
        if(error == 0xC){printf("ERROR_INVALID_ACCESSrn");}
        if(error == 0x6){printf("ERROR_INVALID_HANDLErn");}
        printf("error code %drn", error);
        return false;
    }
    if(GetCommState(serialinstance, &dcb)!= true)
    {
        printf("ERROR getting current state of COM   %d rn", GetLastError());
        return false;
    }
    else{printf("debug   read current comstatern");}

    FillMemory(&dcb, sizeof(dcb), 0); //zero initialize the structure
    dcb.DCBlength = sizeof(dcb);      //fill in length
    dcb.BaudRate = CBR_115200;     //  baud rate
    dcb.ByteSize = 8;             //  data size, xmit and rcv
    dcb.Parity   = NOPARITY;      //  parity bit
    dcb.StopBits = ONESTOPBIT;
    if(SetCommState(serialinstance, &dcb) != true)
    {
        printf("ERROR setting new state of COM   %d rn", GetLastError());
        return false;
    }
    else{printf("debug   set new comstatern");}
    /*
    if (!BuildCommDCB("115200,n,8,1", &dcb)) //fills in basic async details
    {
        printf("ERROR getting port comstatern");
        return FALSE;
    }
    */
    if (!SetCommMask(serialinstance, EV_RXCHAR))
    {
        printf("ERROR setting new COM MASK   %d rn", GetLastError());
        return false;
    }
    else{printf("debug   commmask setrn");}
    timeouts.ReadIntervalTimeout = MAXDWORD;
    timeouts.ReadTotalTimeoutMultiplier = 20;
    timeouts.ReadTotalTimeoutConstant = 0;
    timeouts.WriteTotalTimeoutMultiplier = 0;
    timeouts.WriteTotalTimeoutConstant = 0;
    if (!SetCommTimeouts(serialinstance, &timeouts))
    {
        printf("ERROR setting timeout parametersrn");
        return false;
    }
    else{printf("debug   timeouts setrn");}
    osStatus.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
    if (osStatus.hEvent == NULL)
    {// error creating event; abort
        printf("ERROR creating Serial EVENTrn");
        return false;
    }
    else{printf("debug   event created setrn");}
    osStatus.Internal = 0;
    osStatus.InternalHigh = 0;
    osStatus.Offset = 0;
    osStatus.OffsetHigh = 0;
    assert(osStatus.hEvent);
    printf("debug   com port setting completern");



    return true;
}
//---------------------------------------------------------
bool read_serial_simple()
{
    char m[1000];
    LPDWORD bytesRead;

    if (WaitCommEvent(serialinstance, &dwCommEvent, &osStatus))
    {
        if(dwCommEvent & EV_RXCHAR)
        {
            ReadFile(serialinstance, &m, 1, bytesRead, &osStatus);
            printf("data read =   %d,       number bytes read =     %d  rn", m, bytesRead);
            return true;
        }
        else
        {
            int error = GetLastError();
            if(error == ERROR_IO_PENDING){printf(" waiting on incomplete IOrn");}
            else{printf("ERROR %drn", error);}
            return false;
        }
    }
    return false;
}
};

所以我去掉了读取功能。我现在得到一个char,它报告读取了1个字节,但char的值不正确。我得到一个48、13、10的序列,偶尔还有一个50的字节值。然而,Arduino正在发送一个系列的0,然后是一个128,这已经通过TerraTerm进行了验证。我还需要什么?

bool read_serial_simple()
{
    unsigned char m = 0;
    DWORD bytesRead;
    if(ReadFile(serialinstance, &m, 1, &bytesRead, &osStatus) == true)
    {
        printf("data read =   %d,       number bytes read =     %d  rn", m, bytesRead);
        return true;
    }
    else{
        int error = GetLastError();
        if(error == ERROR_IO_PENDING){printf(" waiting on incomplete IOrn");}
        else{printf("ERROR %drn", error);}
        return false;
    }
}

所以现在我可以读取一个字节的数据,但不能向端口写入一个字节或更多。我只得到ERROR_IO_PENDING。有人也能帮上忙吗。在下面写下我班的函数。

bool write(DWORD noBytesToWrite)
{
    if(WriteFile(serialinstance, outBuffer, noBytesToWrite, NULL, &osStatus) == true)
    {
        printf("message sentrn");
        return true;
    }
    else
    {
        int error = GetLastError();
        if(error != ERROR_IO_PENDING){LastError();}
        return false;
    }
}

我从main调用这两个函数,如下

myserial.open_serial(COM12);
myserial.outBuffer[0] = 'H';
myserial.outBuffer[1] = 'e';
myserial.outBuffer[2] = 'L';
myserial.outBuffer[3] = 'l';
myserial.outBuffer[4] = 'O';
for(int n=0; n<5; n++){printf("%c", myserial.outBuffer[n]);}
printf("rn");
while(1)
{
    myserial.read();
    myserial.write(5);
    //system("PAUSE");
}

目前,arduino被设置为读取字节并将其重复回电脑。它在arduino IDE串行监视器上做得很好,所以现在我只需要让这个电脑程序写出来。

您的bytesRead变量是一个未初始化的指针。您正在将一个无效地址传递给ReadFile()进行写入。

LPDWORD bytesRead替换为DWORD bytesRead,然后使用&bytesRead将其传递给ReadFile()

编辑:同时消除FILE_FLAG_OVERLAPPED。你没有正确处理它,如果你在阅读前WaitForSingleObject(),那么使用它是没有意义的。

对不起,我的回答有点晚,但当我检查另一个串行端口的详细信息时,我发现了这个。

原始代码中有一个小缺陷。您正在使用FILE_FLAG_OVERLAPPED标志调用CreateFile。这意味着您希望使用非阻塞调用。您需要删除此标志,或者更改ReadFile和WriteFile调用,使它们包含指向OVERLAPPED结构WriteFile的指针。

您的代码使用ReadFile,因为它将同步完成,因为有一个字符已经在等待。WriteFile将返回IO_PENDING结果,以指示写入已排队。