更快地读取串口 [英] Reading serial port faster

查看:118
本文介绍了更快地读取串口的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个计算机软件,可以使用USB将RGB颜色代码发送到Arduino.当它们被缓慢发送时,它工作正常,但是每秒发送数十条时,它会吓跑.我认为发生的事情是Arduino串行缓冲区的填充速度如此之快,以致于处理器无法按照我读取它的方式来处理它.

I have a computer software that sends RGB color codes to Arduino using USB. It works fine when they are sent slowly but when tens of them are sent every second it freaks out. What I think happens is that the Arduino serial buffer fills out so quickly that the processor can't handle it the way I'm reading it.

#define INPUT_SIZE 11

void loop() {
  if(Serial.available()) {
    char input[INPUT_SIZE + 1];
    byte size = Serial.readBytes(input, INPUT_SIZE);
    input[size] = 0;

    int channelNumber = 0;

    char* channel = strtok(input, " ");
    while(channel != 0) {
      color[channelNumber] = atoi(channel);

      channel = strtok(0, " ");
      channelNumber++;
    }

    setColor(color);
  }
}

例如,计算机可能会发送 255 0 123 ,其中数字之间用空格分隔.当发送间隔足够慢或缓冲区始终仅填充一种颜色代码(例如11个字节的 255 255 255 ( INPUT_SIZE ))时,此方法会很好地工作.但是,如果颜色代码的长度不超过11​​个字节,并且立即发送了第二个代码,则该代码仍会从串行缓冲区读取11个字节,并开始组合颜色并将其弄乱.如何避免这种情况,但要使其尽可能高效?

For example the computer might send 255 0 123 where the numbers are separated by space. This works fine when the sending interval is slow enough or the buffer is always filled with only one color code, for example 255 255 255 which is 11 bytes (INPUT_SIZE). However if a color code is not 11 bytes long and a second code is sent immediately, the code still reads 11 bytes from the serial buffer and starts combining the colors and messes them up. How do I avoid this but keep it as efficient as possible?

推荐答案

这不是快速读取串行端口的问题,而是当输入数据的长度可变时,不读取固定的11个字符的块的问题.

It is not a matter of reading the serial port faster, it is a matter of not reading a fixed block of 11 characters when the input data has variable length.

您告诉它读取直到接收到11个字符或发生超时,但是如果第一组少于11个字符,并且紧随其后的第二组将没有超时,并且您将部分读取第二组.您似乎理解了这一点,所以我不确定您如何得出结论认为更快阅读"会有所帮助.

You are telling it to read until 11 characters are received or the timeout occurs, but if the first group is fewer than 11 characters, and a second group follows immediately there will be no timeout, and you will partially read the second group. You seem to understand that, so I am not sure how you conclude that "reading faster" will help.

使用现有的ASCII十进制空格分隔的三元组的数据编码,一种解决方案是一次读取输入一个字符,直到读取整个三元组,但是您可以更简单地使用Arduino ReadBytesUntil()函数:

Using your existing data encoding of ASCII decimal space delimited triplets, one solution would be to read the input one character at a time until the entire triplet were read, however you could more simply use the Arduino ReadBytesUntil() function:

#define INPUT_SIZE 3

void loop()
{
    if (Serial.available())
    {
        char rgb_str[3][INPUT_SIZE+1] = {{0},{0},{0}};

        Serial.readBytesUntil( " ", rgb_str[0], INPUT_SIZE );
        Serial.readBytesUntil( " ", rgb_str[1], INPUT_SIZE );
        Serial.readBytesUntil( " ", rgb_str[2], INPUT_SIZE );

        for( int channelNumber = 0; channelNumber < 3; channelNumber++)
        {
            color[channelNumber] = atoi(channel);
        }

        setColor(color);
    }
}

请注意,由于 Stream 类已经为您完成了定界工作,因此该解决方案不需要重量级的 strtok()处理.

Note that this solution does not require the somewhat heavyweight strtok() processing since the Stream class has done the delimiting work for you.

但是,有一个更简单,更有效的解决方案.在您的解决方案中,您将发送ASCII十进制字符串,然后要求Arduino花费不必要的CPU周期来提取字段并转换为整数值,此时您可以直接发送字节值-如有必要,可以使用功能强大得多的PC来进行任何必要的处理从而打包数据.那么代码可能很简单:

However there is a simpler and even more efficient solution. In your solution you are sending ASCII decimal strings then requiring the Arduino to spend CPU cycles needlessly extracting the fields and converting to integer values, when you could simply send the byte values directly - leaving if necessary the vastly more powerful PC to do any necessary processing to pack the data thus. Then the code might be simply:

void loop()
{
    if( Serial.available() )
    {
        for( int channelNumber = 0; channelNumber < 3; channelNumber++)
        {
            color[channelNumber] = Serial.Read() ;
        }

        setColor(color);
    }
}

请注意,我尚未测试以上任何代码,例如,在某些情况下,关于返回值的描述缺少Arduino文档.您可能需要对代码进行一些调整.

Note that I have not tested any of above code, and the Arduino documentation is lacking in some cases with respect to descriptions of return values for example. You may need to tweak the code somewhat.

以上两种方法都不能解决同步问题-即,当颜色值在流式传输时,您如何知道RGB三联体的起始位置是什么?您必须依靠获取第一个字段值并在此后保持计数和同步-这很好,直到在数据流开始后启动Arduino或将其重置,或者PC进程终止并异步重启为止.但是,这对于您最初的实现也是一个问题,因此也许是其他地方需要解决的问题.

Neither of the above solve the synchronisation problem - i.e. when the colour values are streaming, how do you know which is the start of an RGB triplet? You have to rely on getting the first field value and maintaining count and sync thereafter - which is fine until perhaps the Arduino is started after data stream starts, or is reset, or the PC process is terminated and restarted asynchronously. However that was a problem too with your original implementation, so perhaps a problem to be dealt with elsewhere.

这篇关于更快地读取串口的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆