如何在设备发送数据帧时实现串行数据接收事件?

时间:2014-12-26 12:27:17

标签: serial-port c++-cli

我已经创建了一个从串口接收数据的应用程序,我可以很好地接收DataReceived事件的数据。

设备不发送只是字节,但它发送的帧看起来像"#" + 16字节数据+&#34 ;;"其中#是STX和;是ETX。

如何正确实施?我只想在正确接收到这样的帧时处理数据。 DataReceived事件不会帮助我实现这一点,因为它会触发每个字节,而不是一帧数据。

1 个答案:

答案 0 :(得分:1)

一些示例代码。通过将打开的SerialPort对象传递给其构造函数来初始化类。您需要订阅其DataReceived事件以接收数据。使用ErrorReceived进行诊断。如果您有一个事件,则在UI线程上引发事件。未经测试的代码,应该在球场。

public ref class SerialProtocol {
private:
    array<Byte>^ buffer;
    bool gotStx, warnStx;
    int bufcnt;
    SerialPort^ port;
    System::Threading::SynchronizationContext^ context;
    const int framesize = 16;
    const Byte STX = 2;
    const Byte ETX = 3;

public:
    SerialProtocol(SerialPort^ Port) :
        buffer(gcnew array<Byte>(framesize)),
        bufcnt(0), gotStx(false), warnStx(false),
        context(System::Threading::SynchronizationContext::Current),
        port(Port) {
        Port->DataReceived += gcnew SerialDataReceivedEventHandler(this, &SerialProtocol::DataReceivedHandler);
    }

    event ErrorReceivedHandler^ ErrorReceived;
    event DataReceivedHandler^ DataReceived;

private:
    void DataReceivedHandler(Object^ sender, SerialDataReceivedEventArgs^ e) {
        while (port->BytesToRead > 0) {
            Byte b = port->ReadByte();
            if (!gotStx) {
                // Need to see STX as start of frame now
                gotStx = b == STX;
                if (!gotStx && warnStx) OnProtocolViolated(ProtocolViolation::BadStx);
                warnStx = false;
                bufcnt = 0;
            }
            else if (bufcnt == buffer->Length) {
                // Got the frame data, need to see ETX now
                gotStx = false;
                warnStx = b == ETX;
                if (b == ETX) OnDataReceived();
                else OnProtocolViolated(ProtocolViolation::BadEtx);
            }
            else {
                // Busy receiving frame data
                buffer[bufcnt++] = b;
            }
        }
    }
    void OnProtocolViolatedHelper(Object^ state) {
        ErrorReceived(safe_cast<ProtocolViolation>(state));
    }
    void OnDataReceivedHelper(Object^ state) {
        DataReceived(safe_cast<array<Byte>^>(state));
    }

protected:
    virtual void OnProtocolViolated(ProtocolViolation error) {
        // Fires the ErrorReceived event
        if (context == nullptr) ErrorReceived(error);
        else context->Post(gcnew System::Threading::SendOrPostCallback(this, &SerialProtocol::OnProtocolViolatedHelper), error);
    }
    virtual void OnDataReceived() {
        // Fires the DataReceived event
        if (context == nullptr) DataReceived(buffer);
        else {
            // Keep the buffer threadsafe
            array<Byte>^ data = buffer;
            buffer = gcnew array<Byte>(framesize);
            context->Post(gcnew System::Threading::SendOrPostCallback(this, &SerialProtocol::OnDataReceivedHelper), data);
        }
    }
};