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

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

问题描述

我有一个计算机软件,可以使用 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,其中数字以空格分隔.当发送间隔足够慢或缓冲区始终只填充一种颜色代码时,这可以正常工作,例如 255 255 255 是 11 个字节 (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);
    }
}

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

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天全站免登陆