1

我尝试使用 WIN32 API 在 C++ 中写入串行端口,WriteFile 不返回 ERROR_IO_PENDING 但没有任何反应,但是在我使用另一个程序(在 C# 中)写入端口后,c++ 程序可以工作,直到我重新启动 Windows 7,在这里是写代码:

static DCB dcb = {0};
static HANDLE hComm;
static int _tmain(int argc, _TCHAR* argv[])
{
    hComm = CreateFile(
    L"\\\\.\\COM3",
    GENERIC_WRITE | GENERIC_READ,
    0,
    NULL,
    OPEN_EXISTING,
    NULL,   
    NULL
    );

if (hComm == INVALID_HANDLE_VALUE) // error opening port; abort
    printf_s("INVALID_HANDLE_VALUE\n");

if (GetCommState(hComm, &dcb))// DCB is ready for use.
{
    dcb.BaudRate = CBR_19200; //19200 Baud
    dcb.ByteSize = 8; //8 data bits
    dcb.Parity = NOPARITY; //no parity
    dcb.StopBits = ONESTOPBIT; //1 stop
    printf_s("set UP DCB\n");
}
else // Error getting current DCB settings
    printf_s("ERROR getting \n"+GetLastError());

osWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

    WriteABuffer("!serialCMDtoSend\r",sizeof("!serialCMDtoSend\r");
}
static BOOL WriteABuffer(char * lpBuf, DWORD dwToWrite)
{
        // Issue write.
        if (!WriteFile(hComm, lpBuf, dwToWrite, &dwWritten, &osWrite)) 
        {
            if (GetLastError() != ERROR_IO_PENDING) { // WriteFile failed, but it isn't delayed. Report error and abort.
                fRes = FALSE;
            }
            else {
                // Write is pending.
                if (!GetOverlappedResult(hComm, &osWrite, &dwWritten, TRUE))
                    fRes = FALSE;
                else
                    fRes = TRUE;// Write operation completed successfully.
            }
        }
        else
            fRes = TRUE;        // WriteFile completed immediately.
    return fRes;
}

任何人都可以看到我的错误吗?

4

2 回答 2

2

这是偶然的。您忘记在 CreateFile 调用中指定 FILE_FLAG_OVERLAPPED,因此您永远不会得到重叠的 I/O。您可能不知道这一点,因为您的错误处理被破坏了,当 GetLastError 不返回 ERROR_IO_PENDING 时,您不知道错误代码是什么样的。当 WriteFile 不必阻塞时,它会意外工作,因为数据适合驱动程序的传输缓冲区。正如 Ben 解释的那样,对握手设置取模。

使用重叠 I/O 并立即调用 GetOverlappedResult(TRUE) 毫无意义。您不妨使用非重叠 I/O,这样更容易上手。仅当您有其他有用的事情要做并且可以调用 WaitForMultipleObjects() 来检查写入是否完成时才使用它。这在编写的情况下通常很难处理,编写异步代码并不容易。

于 2013-04-13T16:30:43.157 回答
0

有时从干净的 DCB 开始比使用GetCommState. 例如,您没有关闭流控制,因此行为取决于最后一个程序如何离开它。

您肯定需要正确设置流控制字段:

fOutxCtsFlow
fOutxDsrFlow
fDtrControl
fDsrSensitivity
fOutX
fInX
fRtsControl

一般来说,GetCommState如果您不希望您的程序依赖于先前的设置,我建议不要使用。相反,从零开始:

DCB dcb = { sizeof dcb };
dcb.fBinary = TRUE;
dcb.BaudRate = 19200; //19200 Baud
dcb.ByteSize = 8; //8 data bits
dcb.Parity = NOPARITY; //no parity
dcb.StopBits = ONESTOPBIT; //1 stop

除了您对先前设置的依赖之外,GetCommState由于您没有设置而失败DCBlength(文档清楚地说明这必须由您设置,调用者。 GetCommState如果不先检查您提供的大小,就无法填充缓冲区。)。

于 2013-04-13T15:36:25.220 回答