0

我正在尝试编写一个程序,每次新数据进入串行端口时都会更新 Windows 窗体,但是我在努力理解串行端口的工作原理以及如何以我想要的方式使用它。

我有一个外部设备以 1Hz 的频率向我的串行端口发送 8 个字节,并希望使用来自 SerialPort 类的 DataReceived 事件。当我调试我的代码时,事件或多或少会根据程序在特定时间执行的操作随机触发。代码如下:

    private void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
    {
        //byte[] rxbyte = new byte[1];
        byte[] rxbyte = new byte[8];
        byte currentbyte;
        port.Read(rxbyte, 0, port.BytesToRead);

        currentbyte = rxbyte[0];

        int channel = (currentbyte >> 6) & 3; //3 = binary 11, ANDS the last 2 bits
        int msb_2bit = (currentbyte >> 0) & 255; //AND compare all bits in a byte
        currentbyte = rxbyte[1];
        int val = ((msb_2bit << 8) | (currentbyte << 0));

        //Extra stuff

        SetText_tmp1(val.ToString());
    }

在调用 Read 函数之前,我希望能够在接收缓冲区中恰好有 8 个字节,但我不确定如何做到这一点(以前从未使用过 SerialPort 类),并且只想在我有的时候才对数据进行所有操作整个 8 个字节。仅当缓冲区中有一定数量的字节时,是否有内置方法来切换事件?或者是否有另一种方法只获取 8 个字节,而不是更多,并将剩余的字节留给下一个实例?

4

3 回答 3

2

是的,你没有正确编码。您无法预测您将收到多少字节。所以在你得到所有字节之前不要处理接收到的字节。像这样:

private byte[] rxbyte = new byte[8];
private int rxcount = 0;

private void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
    rxcount += port.Read(rxbyte, rxcount, 8 - rxcount);
    if (rxcount < 8) return;
    rxcount = 0;
    // Process rxbyte content
    //...
}
于 2013-06-24T23:41:26.207 回答
0

将 ReceivedBytesThreshold 属性设置为 8。如port.ReceivedBytesThreshold = 8;

于 2013-06-24T23:41:53.107 回答
0

处理此问题的一种有效方法是在类中添加一个计时器,该计时器每秒可能会计时 9 次。彻底消除串口事件处理程序。

在每个计时器滴答声中,让代码检查串行端口是否有从串行端口接收到的字节。如果那里有一些,则将它们从串行端口中取出并将它们附加到作为数据成员在类中维护的缓冲区的末尾。

当缓冲区中有八个或更多字符时,计时器滴答逻辑将从缓冲区中取出前 8 个字节并使用它们来更新用户界面窗口。缓冲区中的任何剩余字节都可以向上移动到缓冲区的头部。

定时器滴答例程还可以维护一个计数器值,每次滴答进入并且在此滴答时串行端口没有准备好数据时递增。当此计数器达到 3 或 4 的值时,代码会将数据缓冲区重置为空并将计数器重置为零。当实际从串行端口看到数据时,此计数器将重置为零。这种计数器机制的目的是使数据接收缓冲区与传入的 1Hz 数据流同步,这样接收过程就不会与代表 8 字节消息开始的数据不同步。

请注意,此方法优于串行端口接收数据事件,因为它允许您的程序保持对事物的控制。我已经描述了与数据流突发同步的能力——试图将串行端口接收数据阈值设置为 8 这样的计数是不可能的。另一个优点是定时器滴答代码可以包含额外的处理函数例如,如果在 2 或 3 秒内没有数据从串行端口到达,则发出超时信号。

于 2013-06-25T00:14:02.970 回答