读取时串行通信丢失字符(MTTY 示例让我困惑)

问题描述 投票:0回答:1

我一直在尝试与Arduino Nano(实际上是一个廉价的中文版本)建立通信。

板每秒发送3个字符,我只收到最后2个字符

我发现此文档引用了 MTTY 示例。我继续下去,找到了它作为例子。

我有兴趣了解阅读部分是如何完成的(在 READSTAT.C 中)

这部分让我困惑:

    while ( !fThreadDone ) {

        //
        // If no reading is allowed, then set flag to
        // make it look like a read is already outstanding.
        //
        if (NOREADING( TTYInfo ))
            fWaitingOnRead = TRUE;
        
        //
        // if no read is outstanding, then issue another one
        //
        if (!fWaitingOnRead) {
            if (!ReadFile(COMDEV(TTYInfo), lpBuf, AMOUNT_TO_READ, &dwRead, &osReader)) {
                if (GetLastError() != ERROR_IO_PENDING)   // read not delayed?
                    ErrorInComm("ReadFile in ReaderAndStatusProc");

                fWaitingOnRead = TRUE;
            }
            else {    // read completed immediately
                if ((dwRead != MAX_READ_BUFFER) && SHOWTIMEOUTS(TTYInfo))
                    UpdateStatus("Read timed out immediately.\r\n");

                if (dwRead)
                    OutputABuffer(hTTY, lpBuf, dwRead);
            }
        }

        //
        // If status flags have changed, then reset comm mask.
        // This will cause a pending WaitCommEvent to complete
        // and the resultant event flag will be NULL.
        //
        if (dwStoredFlags != EVENTFLAGS(TTYInfo)) {
            dwStoredFlags = EVENTFLAGS(TTYInfo);
            if (!SetCommMask(COMDEV(TTYInfo), dwStoredFlags))
                ErrorReporter("SetCommMask");
        }

        //
        // If event checks are not allowed, then make it look
        // like an event check operation is outstanding
        //
        if (NOEVENTS(TTYInfo))
            fWaitingOnStat = TRUE;
        //
        // if no status check is outstanding, then issue another one
        //
        if (!fWaitingOnStat) {
            if (NOEVENTS(TTYInfo))
                fWaitingOnStat = TRUE;
            else {
                if (!WaitCommEvent(COMDEV(TTYInfo), &dwCommEvent, &osStatus)) {
                    if (GetLastError() != ERROR_IO_PENDING)   // Wait not delayed?
                        ErrorReporter("WaitCommEvent");
                    else
                        fWaitingOnStat = TRUE;
                }
                else
                    // WaitCommEvent returned immediately
                    ReportStatusEvent(dwCommEvent);
            }
        }

        //
        // wait for pending operations to complete
        //
        if ( fWaitingOnStat && fWaitingOnRead ) {
            dwRes = WaitForMultipleObjects(NUM_READSTAT_HANDLES, hArray, FALSE, STATUS_CHECK_TIMEOUT);
            switch(dwRes)
            {
                //
                // read completed
                //
                case WAIT_OBJECT_0:
                    if (!GetOverlappedResult(COMDEV(TTYInfo), &osReader, &dwRead, FALSE)) {
                        if (GetLastError() == ERROR_OPERATION_ABORTED)
                            UpdateStatus("Read aborted\r\n");
                        else
                            ErrorInComm("GetOverlappedResult (in Reader)");
                    }
                    else {      // read completed successfully
                        if ((dwRead != MAX_READ_BUFFER) && SHOWTIMEOUTS(TTYInfo))
                            UpdateStatus("Read timed out overlapped.\r\n");

                        if (dwRead)
                            OutputABuffer(hTTY, lpBuf, dwRead);
                    }

                    fWaitingOnRead = FALSE;
                    break;

                //
                // status completed
                //
                case WAIT_OBJECT_0 + 1: 
                    if (!GetOverlappedResult(COMDEV(TTYInfo), &osStatus, &dwOvRes, FALSE)) {
                        if (GetLastError() == ERROR_OPERATION_ABORTED)
                            UpdateStatus("WaitCommEvent aborted\r\n");
                        else
                            ErrorInComm("GetOverlappedResult (in Reader)");
                    }
                    else       // status check completed successfully
                        ReportStatusEvent(dwCommEvent);

                    fWaitingOnStat = FALSE;
                    break;

                //
                // status message event
                //
                case WAIT_OBJECT_0 + 2:
                    StatusMessage();
                    break;

                //
                // thread exit event
                //
                case WAIT_OBJECT_0 + 3:
                    fThreadDone = TRUE;
                    break;

                case WAIT_TIMEOUT:
                    //
                    // timeouts are not reported because they happen too often
                    // OutputDebugString("Timeout in Reader & Status checking\n\r");
                    //

                    //
                    // if status checks are not allowed, then don't issue the
                    // modem status check nor the com stat check
                    //
                    if (!NOSTATUS(TTYInfo)) {
                        CheckModemStatus(FALSE);    // take this opportunity to do
                        CheckComStat(FALSE);        //   a modem status check and
                                                    //   a comm status check
                    }

                    break;                       

                default:
                    ErrorReporter("WaitForMultipleObjects(Reader & Status handles)");
                    break;
            }
        }
    }

我认为这段代码很可能会调用

ReadFile
而不调用
WaitCommEvent
,这样继续下去是否正确?我也一直尝试:

  • 致电
    WaitCommEvent
  • 致电
    ReadFile
  • 致电
    WaitForSingleObject
  • 致电
    GetOverlappedResult
  • 回想一下
    ReadFile
    实际获取数据,但似乎没有必要

我尝试使用这个例子而不调用

WaitCommEvent
,它有点工作,读取操作总是错过第一个字符。

我使用

GENERIC_WRITE
GENERIC_READ
OPEN_EXISTING
FILE_FLAG_OVERLAPPED
打开端口,并使用
SetCommMask
标志适当地调用
EV_RXCHAR

DWORD WINAPI read(LPVOID param) {
    CUSTOM_DATA* params = (CUSTOM_DATA*)param;
    HANDLE hComm = params->hComm;
    OVERLAPPED ov = { 0 };
    bool waitingOnStat = FALSE;
    int i = 1;
    while (1) {
        char* buffer = (char*)malloc(100 * sizeof(char));
        ZeroMemory(buffer, 100);
        DWORD bufferSize = 100;
        DWORD nbRead;
        DWORD evtMask;
        DWORD res;
        if (!waitingOnStat) {
            ZeroMemory(&ov, sizeof(OVERLAPPED));
            ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

            if (!ReadFile(hComm, buffer, bufferSize, &nbRead, &ov)) {
                if (GetLastError() != ERROR_IO_PENDING) {
                    printf("ERROR_IO NOT PENDING\n");
                }
                waitingOnStat = true;
            }
            else {
                std::cout.write(buffer, nbRead) << std::endl;
                waitingOnStat = FALSE;
            }
        }

        if (waitingOnStat) {
            printf("Waiting");
            DWORD res = WaitForSingleObject(ov.hEvent, INFINITE);
            switch (res) {
            case WAIT_OBJECT_0:
                waitingOnStat = FALSE;
                DWORD nbBytesTransfered;
                if (!GetOverlappedResult(hComm, &ov, &nbBytesTransfered, TRUE)) {
                        printf("error reading %d\n", GetLastError());
                } else {
                    std::cout.write(buffer, nbRead);
                }
                break;
            default:
                printf("waiting read error %d\n", GetLastError());
                break;
            }
        }
        i++;
    }
}

为什么

ReadFile
不断返回true?

需要打电话吗

WaitCommEvent

c windows serial-port
1个回答
0
投票

在@Ian Abbott 的帮助下,我摆弄了

COMMTIMEOUTS
的参数。 该文档指定了一些行为,例如:

如果应用程序将 ReadIntervalTimeout 和 ReadTotalTimeoutMultiplier 设置为 MAXDWORD 并将 ReadTotalTimeoutConstant 设置为大于零的值,并且 小于 MAXDWORD,当 ReadFile 函数为 称为: 如果输入缓冲区中有任何字节,ReadFile 立即返回 缓冲区中的字节。 如果输入缓冲区中没有字节,则 ReadFile 会等待直到有字节 到达然后立即返回。 如果在 ReadTotalTimeoutConstant 指定的时间内没有字节到达, 读取文件超时。

问题在于我的代码:

  • 调用
    GetOverlappedResult
    然后忽略
    nbBytesRead
    参数(因为我读过使用
    OVERLAPPED IO
  • 时应该忽略它)

采取以下措施似乎解决了我的问题:

  • 在拨打

    nbBytesTransfered
    后的时间使用
    GetOverlappedResu
    。虽然如果我将超时设置为:

  • timeouts.ReadIntervalTimeout = 4294967295;

  • 超时.ReadTotalTimeoutConstant = 4294967294;

  • 超时.ReadTotalTimeoutMultiplier = 4294967295;

    对于最终由

    ReadFile

     显示的第一个字符,
    FALSE
    将返回
    GetOverlappedCall
    ,然后
    ReadFile
    将返回
    TRUE
    并显示其余字符(我还没有高速测试过) ).

如果我将超时设置如下:

  • timeouts.ReadIntervalTimeout = 10;
  • timeouts.ReadTotalTimeoutConstant = 100;
  • timeouts.ReadTotalTimeoutMultiplier = 10;
    ReadFile
    不返回
    TRUE
    并且
    GetOverlappedResult
    读取所有字符(我还没有高速测试过)。
最新问题
© www.soinside.com 2019 - 2025. All rights reserved.