通过串口Windows发送和接收

时间:2014-12-30 10:39:58

标签: windows visual-c++ serial-port uart

我有一个在Windows上运行的应用程序,它将通过串行端口发送数据。 这是代码:

m_hCommPort= ::CreateFile(L"\\\\.\\COM3",
        GENERIC_READ|GENERIC_WRITE, 0, 0, OPEN_EXISTING,0,0);

    if(m_hCommPort == INVALID_HANDLE_VALUE) 
    {
        printf("COM error: %d\n", GetLastError());
    }
    config.DCBlength = sizeof(config);


    if((GetCommState(m_hCommPort, &config) == 0))
    {
        CloseHandle(m_hCommPort);
        printf("Get configuration port has a problem.\n");
        return FALSE;
    }

    config.BaudRate = 9600;
    config.StopBits = ONESTOPBIT;
    config.Parity = PARITY_NONE; 
    config.ByteSize = DATABITS_8;
    config.fDtrControl = 0;
    config.fRtsControl = 0;

    if (!SetCommState(m_hCommPort, &config))
    {
        CloseHandle(m_hCommPort);
        printf( "Failed to Set Comm State Reason: %d\n",GetLastError());
        return E_FAIL;
    }

以下是仅发送(工作)(连续发送)

的代码
while(1)
    {
        Sleep(5000);
        int isWritten = WriteFile(m_hCommPort, txData, 9/*(DWORD)sizeof(txData)*/, &dwBytesWritten, NULL);
            printf("isWritten: %d, dwBytesWritten: %d \n", isWritten, dwBytesWritten);

    }

在此之后我也添加了接收数据的代码,然后发送不工作。我的意思是无法通过UART发送数据。 WriteFile()似乎没有被执行,它被卡住了。 在这里我添加了一个线程来接收数据,是线程导致问题吗?还是我需要做别的事?

void ReceiverThread(void *param)
{
    DWORD dwRead=0;
    BOOL fWaitingOnRead = FALSE;
    OVERLAPPED osReader = {0};

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

    if (osReader.hEvent == NULL)
        printf("Error creating overlapped event; abort.\n");
    while(1)
    {
        if (!ReadFile(m_hCommPort, &Byte, 1, &dwRead, &osReader)) {
            if (GetLastError() != ERROR_IO_PENDING)     // read not delayed?
                printf("Error in communications; report it.\n");
            else
                fWaitingOnRead = TRUE;
        }
        else {    

            rxData[rxHeadIndex++]= Byte;
            rxHeadIndex = (rxHeadIndex) & QUEUE_MASK;
        }


    }

}


SetCommMask (m_hCommPort, EV_RXCHAR/ | EV_ERR); //receive character event


    _beginthread(ReceiverThread,0,NULL); 


    while(1)
    {
        Sleep(5000);
        int isWritten = WriteFile(m_hCommPort, txData, 9/*(DWORD)sizeof(txData)*/, &dwBytesWritten, NULL);
            printf("isWritten: %d, dwBytesWritten: %d \n", isWritten, dwBytesWritten);

    }

提前致谢。 阿肖克

2 个答案:

答案 0 :(得分:2)

我前一段时间遇到过类似的问题。

我发现如果串行端口当前正在进行WriteFile(..)ReadFile(..)会阻止。如果ReadFile(..)阻塞,如果没有要读取的数据,那么这就是一个问题。

我通过使用函数ClearCommError(..)检查串行缓冲区中是否有可用数据来解决问题。这可确保ReadFile(..)可以立即读取内容并且不会不必要地阻止设备。尝试将ReceiverThread更改为以下内容:

void ReceiverThread(void *param)
{
    DWORD dwRead=0;
    COMSTAT comStat;
    char buffer[1024];

    while (m_hCommPort != INVALID_HANDLE_VALUE)
    {
        if ((ClearCommError(m_hCommPort, NULL, &comStat) != FALSE) && (comStat.cbInQue > 0))
        {
            /* todo: ensure buffer is big enough to contain comStat.cbInQue bytes! */

            if (ReadFile(m_hCommPort, buffer, comStat.cbInQue, &dwRead, NULL) != FALSE)
            {
                /* do something with data in buffer */
            }
        }

        /* avoid busy-wait */
        if (comStat.cbInQue == 0)
        {
            SleepEx(1, FALSE);
        }
    }
}

这种方式ReadFile(..)仅在数据可用时调用,同时WriteFile(..)可以发送数据而不会被阻止。

很遗憾,我无法阻止ClearCommError(..)阻止,所以我使用SleepEx(1, FALSE);解决方法来避免忙碌等待,从而使ReceiverThread吃掉了{{1}} CPU。

答案 1 :(得分:1)

  config.fDtrControl = 0;
  config.fRtsControl = 0;

这些设置会关闭DTR和RTS握手线。大多数串行设备都会关注这些信号。假设机器未通电,他们在DTR信号关闭时不会发送任何内容。假设机器未准备好接收任何数据,并且在RTS信号关闭时不会发送任何内容。

所以你观察到的是完全正常的。

由于该设备似乎是正常的"并且 注意握手线,您要配置DCB让设备驱动程序自动控制这些信号。修正:

  config.fDtrControl = DTR_CONTROL_ENABLE;
  config.fRtsControl = RTS_CONTROL_HANDSHAKE;

也是Putty和HyperTerminal等终端模拟器的默认设置。首先使用这样的程序以确保接线和设备正常工作。如果您无法在此类程序中显示任何设备数据,那么它也无法使用您的程序。如果全部检出,则还将fDsrSensitivity,fOutxCtsFlow和fOutxDsrFlow属性设置为TRUE,以便您反过来注意设备的握手信号。