Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/265.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 当接收到一定数量的字节时,串行端口触发数据已接收_C#_Serial Port - Fatal编程技术网

C# 当接收到一定数量的字节时,串行端口触发数据已接收

C# 当接收到一定数量的字节时,串行端口触发数据已接收,c#,serial-port,C#,Serial Port,我正试图编写一个程序,每当串行端口上出现新数据时更新windows窗体,但我很难理解串行端口是如何工作的,以及如何以我想要的方式使用它 我有一个外部设备以1Hz的频率向我的串行端口发送8个字节,并希望使用SerialPort类中的DataReceived事件。当我调试代码时,事件或多或少会根据程序在某个时间所做的事情随机触发。代码如下: private void port_DataReceived(object sender, SerialDataReceivedEventArgs e)

我正试图编写一个程序,每当串行端口上出现新数据时更新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());
    }
private void port\u DataReceived(对象发送方,SerialDataReceivedEventArgs e)
{
//字节[]rxbyte=新字节[1];
字节[]rxbyte=新字节[8];
字节当前字节;
读取端口(rxbyte,0,port.BytesToRead);
currentbyte=rxbyte[0];
int channel=(currentbyte>>6)&3;//3=二进制11,和最后2位
int msb_2bit=(currentbyte>>0)&255;//并比较一个字节中的所有位
currentbyte=rxbyte[1];

int val=((msb_2bit是的,您的编码不正确。您无法预测将接收多少字节。因此,在获得所有字节之前,不要处理接收到的字节。如下所示:

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
    //...
}
private byte[]rxbyte=新字节[8];
私有整数rxcount=0;
私有无效端口\u DataReceived(对象发送方,SerialDataReceivedEventArgs e)
{
rxcount+=端口读取(rxbyte,rxcount,8-rxcount);
如果(rxcount<8)返回;
rxcount=0;
//处理rxbyte内容
//...
}

将ReceivedBytestThreshold属性设置为8。如
port.receivedBytestThreshold=8;
处理此问题的有效方法是向类中添加一个计时器,该计时器可能每秒运行9次。完全消除串行端口事件处理程序

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

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

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


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

这太简单了,无法在消息帧上正确实现同步。您需要保证计数从消息的第一个字节开始。如果您遵循Hans的回答,这是错误的不需要。@sawdust-是的,根据提供的其余代码,它过于简单,并且可能是错误的。但是,post只声明“在调用读取函数之前,我希望接收缓冲区中正好有8个字节”。不包括任何关于同步的内容,尽管几乎肯定是必要的。@dbasnett-Hans的回答完全相同,只是手动。@sawdust-计时器本身是事件驱动的。由于重复事件,超时时间被测量。我可以说,从构建了许多使用串行端口的应用程序来看,此方案工作得非常好。May引用的评论对每个人来说都太强了,但对我在几十个工业生产环境中使用的应用程序来说效果很好。“请注意,这种方法是优越的……”——不是真的,你是说轮询“更好”如果延迟是可以容忍的,那么这是一个可能的解决方案。我根本不知道C,但在C中,我认为使用适当的VMIN和VTIME设置的非规范读取将是最简单的解决方案。@MichaelKaras-为什么对以1字节/秒的速度到达的数据每秒触发9次计时器?我喜欢Hans的答案。问题出在哪里避免处理程序的方法是计时器必须读取和处理数据,这些数据适用于低比特率,但不适用于高比特率。@dbasnett-我在OP给出的参数范围内工作。他说他的8字节数据束每秒到达一次。因为他显然没有将数据内容与帧信息绑定在一起重申必须使用计时来判断数据边界。这可能可以用每秒4-5个滴答声来完成,但很久以前我注意到,在每秒9个或更多滴答声时,用户通常不会注意到用户界面更新中的延迟变化。在较慢的速度下,他们会注意到。就数据读取和处理的位置而言,这没有什么区别如果这是a(续)(从上往下续),则进行此操作计算机所需的任务。事件处理程序不是中断服务例程。如果必须收集和显示数据,谁会关心它在系统中处理所有事件时可用的可用带宽中分散到哪里。当然,无论在哪里完成,都需要使工作简短而甜蜜,所以其他事情如鼠标和鼠标如果数据处理变得复杂并需要l