C程序与Win32 Api的串行连接



我写了一个小C程序,用于监控串行端口流量(信号和输入)。我使用的应用程序是一个同步的、事件驱动的应用程序。我同步调用WaitCommEvent函数(因此不使用使用OVERLAPPED结构)。

在我的应用程序中监视以下COM事件:

  • EV_CTS:CTS(清除发送)信号改变状态
  • EV_RLSD:RLSD(接收线信号检测)信号改变状态
  • EV_RXCHAR:接收到一个字符并将其放入输入缓冲区

我的问题是,如果上面提到的信号之一改变了它的状态,那么WaitCommEvent(第二参数)的输出掩码要么具有它的值(如果信号被设置,则为EV_CTS0x0008)或EV_RLSD0x0020)),要么具有EV_RXCHAR的值(当信号被清除时为0x0001)。换句话说:如果这些信号中的一个被清除;清除事件";我收到一个EV_RXCHAR,所以我的软件无法区分";字符接收";以及";信号清除";事件

请帮我找到一个想法,让我的软件能够区分";字符接收";以及";信号清除";事件。对于这两种情况,WinApi都返回事件掩码值0x0001

更新:

为了更好地理解我的问题,我发布了程序的代码和控制台输出。

以下情况发生在串行总线上(我的应用程序也应该检测到):

  1. RLSD信号被设置
  2. 数据已发送(因此我的应用程序应读取/接收数据)
  3. RLSD信号被清除

事件处理的代码如下:

if(TRUE == WaitCommEvent(hComPort, &dwEvtMask, NULL))
{
    PrintCurrentDateTime();
    printf("the dwEvtMask = 0x%04Xrn", dwEvtMask);
    GetCommModemStatus(hComPort, &dwModemState);
    PrintCurrentDateTime();
    printf("the dwModemState = 0x%04Xrn", dwModemState);
    if(dwEvtMask & EV_CTS) // Clear-to-send signal changed
    {
        PrintCurrentDateTime();
        printf("EV_CTS triggered.rn");
    }
    if(dwEvtMask & EV_RLSD) // Data-carrier-detect signal changed
    {
        PrintCurrentDateTime();
        printf("EV_RLSD triggered.rn");
    }
    if(dwEvtMask & EV_RXCHAR) // Data received
    {
        ReadSerial(hComPort, portNum, readBuff, READ_BUFF_MAX_LENGTH);
    }
}

我在控制台上得到的输出如下:

2015.11.26 11:51:03:578 dwEvtMask=0x0020

2015.11.26 11:51:03:593 dwModemState=0x0080

2015.11.26 11:51:03:593 EV_RLSD触发。

2015.11.26 11:51:03:656 dwEvtMask=0x0020

2015.11.26 11:51:03:656 dwModemState=0x000

2015.11.26 11:51:03:656 EV_RLSD触发。

2015.11.26 11:51:03:671 dwEvtMask=0x0001

2015.11.26 11:51:03:671 dwModemState=0x000

2015.11.26 11:51:03:671在端口COM1:07 01 06 上接收到3个字符

2015.11.26 11:51:03:671 dwEvtMask=0x0001

2015.11.26 11:51:03:671 dwModemState=0x000

2015.11.26 11:51:03:671在端口COM1:上收到0个字符

也许WinApi的行为不像MSDN上写的那样,谁知道呢。。。

更新2:

正如Hans Passant在下面所写的,问题是,我总是在EV_RLSD之后接收事件EV_RXCHAR,这导致了误解。我必须使用的协议定义,数据应该只在RLSD信号设置期间接收。事实确实如此,所以总线的操作是正确的,但由于接收需要一些时间(由于序列化等原因,有关详细信息,请参阅Hans Passant在上面的文章)。

我可以通过检查EV_RLSD上接收到的数据(通过调用ReadFile)来解决这个问题;下降";(1->0)。

区分"字符接收"one_answers"信号清除"事件

这不是EV_CTS和EV_RLSD的意思,它们只是表示信号改变了状态,而不是说它被"清除"。您可以使用该事件来调用GetCommModemStatus()并获得实际的信号状态。所以得到0x0001只意味着收到了一个字节,信号没有改变。

事件掩码可以帮助您最大限度地减少需要进行的函数调用的数量。因此,不需要为每个事件调用GetCommModemStatus()。请注意,您可能会同时收到多个事件的信号。

在您对预期获得的事件进行排序的方式中,还有另一个问题的迹象。您希望在EV_RXCHAR之后获得EV_RLSD。与它的工作方式不同,握手信号的变化会立即生效。但是发送和接收一个字节需要时间。字节必须由设备上的UART串行化,通常需要10倍于波特时钟的时间。PC上的UART将字节放入FIFO缓冲区,FIFO缓冲区最终产生一个中断,告诉驱动程序将字节复制到其接收缓冲区。然后得到EV_RXCHAR事件。

因此,使用DCD作为某种"门"信号是没有用的。设备不可能知道PC何时接收到字节,它总是过早地关闭DCD。你可以用握手信号玩很多游戏,但它们通常不会那么好。DCD是一种调制解调器信号,只用于协商连接,将其用于其他用途会产生一种巴洛克式的协议,很少有程序员知道如何正确实现。

相关内容

  • 没有找到相关文章

最新更新