串行端口:轮询与事件驱动的方法

时间:2014-06-23 10:08:35

标签: c# winapi serial-port pinvoke serial-communication

我正在使用Win32 API(重叠IO)进行串行端口通信。我使用PInvoke从我的C#代码调用Win32 API。

在我之前的实现中,接收器线程使用轮询机制读取数据(无限循环周期性地读取RX缓冲区)。现在,我正在尝试使用事件驱动方法来读取数据(使用WaitCommEvent API调用)。我们期望新的实现将降低CPU使用率并加快通信速度。

但是,在更改为事件驱动方法之后,与轮询机制相比,通信实际上变慢了,花费了两倍的时间来读取。

任何人都可以建议哪一种是最好的方法来提高通信速度并降低CPU使用率?

以下是我的代码段:

private void ReadDataForWindows()
{
    var data = new byte[255];

    // Specify a set of events to be monitored for the port.
    if (SetCommMask(this.Handle, EV_DEFAULT))
    {
        while (this.Handle != (IntPtr)INVALID_HANDLE_VALUE)
        {
            uint eventMask = 0;
            // Wait for an event to occur for the port.
            eventMask = this.WaitForEvent();

            if (eventMask == EV_RXCHAR)
            {
                this.ReadFromRXBuffer(data);
            }
            else if (eventMask == EV_ERR)
            {
                uint errors;
                ClearCommError(this.Handle, out errors, IntPtr.Zero);
            }

            // Re-specify the set of events to be monitored for the port.
            if (!SetCommMask(this.Handle, EV_DEFAULT))
            {
                break;
            }
        }
    }
}

private void ReadFromRXBuffer(byte[] data)
{
    uint dwBytesTransferred;
    // Loop for waiting for the data.
    do
    {
        // Read the data from the serial port.
        this.Read(data, 255, out dwBytesTransferred);

        // Display the data read.
        if (dwBytesTransferred > 0)
        {
            if (this.DataReceived != null)
            {
                var dataReceived = new byte[dwBytesTransferred];
                for (var i = 0; i < dwBytesTransferred; i++)
                {
                    dataReceived[i] = data[i];
                }

                this.DataReceived(this, new ByteDataReceivedEventArgs(dataReceived, Convert.ToInt32(dwBytesTransferred)));
            }
        }

    } while (dwBytesTransferred > 0);
}

private uint WaitForEvent()
{
    uint eventMask = 0;
    IntPtr evPtr = Marshal.AllocHGlobal(Marshal.SizeOf(eventMask));
    Marshal.WriteInt32(evPtr, 0);

    if (WaitCommEvent(this.Handle, evPtr, this.RxOvr.MemPtr) == false)
    {
        int error = Marshal.GetLastWin32Error();

        // Operation is executing in the background
        if (error == ERROR_IO_PENDING)
        {
            this.ReceiveSignal.WaitOne();
        }
        else
        {
            this.Fault = "WaitCommEvent() Failed. System Returned Error Code: " +
                error.ToString();
            return 0;
        }
    }

    eventMask = (uint)Marshal.ReadInt32(evPtr);
    return eventMask;
}

0 个答案:

没有答案