【问题标题】:Arduino DigiSpark NeoPixel BlueTooth C++ Buffer OverflowArduino DigiSpark NeoPixel 蓝牙 C++ 缓冲区溢出
【发布时间】:2020-11-10 03:09:15
【问题描述】:

在敲了大约一周的办公桌后,我能够编写以下代码,它确实有效。问题是它的响应速度不快,大多数时候我不得不向手机上的按钮发送垃圾邮件,一遍又一遍地发送相同的命令,直到它赶上。

你能帮我清理一下代码吗?

正如您将看到的,有时我似乎过于复杂的事情,但这只是因为我发现它以这种方式工作得更好,而不是看起来更“合乎逻辑”的简单版本。我将编写代码,然后我将解释并提出我的问题。

#include <Adafruit_NeoPixel.h> // NeoPixel Lib
#include <SoftSerial.h>  // Serial Lib
#define LED_PIN    2
#define LED_COUNT 30

SoftSerial bluetooth(4, 5); // RX TX
Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);

const byte numChars = 32;
char receivedChars[numChars];
char tempChars[numChars];
boolean newData = false;
boolean goLED0 = false;
boolean goLED1 = true;
boolean goLED2 = false;
boolean goLED3 = false;
boolean goLED4 = false;


int eFx = 1;
int rC1 = 255;
int gC1 = 0;
int bC1 = 0;
int xS = 20;
int xB = 125;


void setup() {

  bluetooth.begin (9600);
  strip.begin();           // INITIALIZE NeoPixel strip object (REQUIRED)
  strip.show();            // Turn OFF all pixels ASAP

}


void loop() {
  checkLedData();
  delay(50);
  runLED();
  delay(50);
}


void recvWithStartEndMarkers() {
    static boolean recvInProgress = false;
    static byte ndx = 0;
    char startMarker = '<';
    char endMarker = '>';
    char rc;
 
    while (bluetooth.available() > 0 && newData == false) {
        rc = bluetooth.read();

        if (recvInProgress == true) {
            if (rc != endMarker) {
                receivedChars[ndx] = rc;
                ndx++;
                if (ndx >= numChars) {
                    ndx = numChars - 1;
                }
            } else {
                receivedChars[ndx] = '\0'; // terminate the string
                recvInProgress = false;
                ndx = 0;
                newData = true;
            }
        }   else if (rc == startMarker) {
            recvInProgress = true;
        }
    }
}


void parseData() {      // split the data into its parts

    char * strtokIndx; // this is used by strtok() as an index

    strtokIndx = strtok(tempChars, ",");      // get the first part - the string
    eFx = atoi(strtokIndx);     // convert this part to an integer

    strtokIndx = strtok(NULL, ",");      // get the first part - the string
    rC1 = atoi(strtokIndx);     // convert this part to an integer
 
    strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
    gC1 = atoi(strtokIndx);     // convert this part to an integer

    strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
    bC1 = atoi(strtokIndx);     // convert this part to an integer

    strtokIndx = strtok(NULL, ",");
    xS = atoi(strtokIndx);     // convert this part to an integer

    strtokIndx = strtok(NULL, ",");
    xB = atoi(strtokIndx);     // convert this part to an integer

    strtokIndx = strtok(NULL, NULL);
}



void checkLedData() {
  recvWithStartEndMarkers();
  if (newData == true) {
    strcpy(tempChars, receivedChars);
    parseData();
    newData = false;
    strip.setBrightness(xB);
   if (eFx == 0) { 
     goLED0 = true;
     goLED1 = false;
     goLED2 = false;
     goLED3 = false;
     goLED4 = false;
    }
   if (eFx == 1) { 
     goLED0 = false;
     goLED1 = true;
     goLED2 = false;
     goLED3 = false;
     goLED4 = false;
    }
   if (eFx == 2) { 
     goLED0 = false;
     goLED1 = false;
     goLED2 = true;
     goLED3 = false;
     goLED4 = false;
    }
   if (eFx == 3) { 
     goLED0 = false;
     goLED1 = false;
     goLED2 = false;
     goLED3 = true;
     goLED4 = false;
    }  
   if (eFx == 4) { 
     goLED0 = false;
     goLED1 = false;
     goLED2 = false;
     goLED3 = false;
     goLED4 = true;
    }}}
    

void runLED() {
  if (goLED0 == true) {
            
  } 
    if (goLED1 == true) {
          colorWipe(strip.Color(rC1, gC1, bC1), xS);
          delay(50);
          recvWithStartEndMarkers();
              
  } 
    if (goLED2 == true) {
          colorWipe(strip.Color(bC1,rC1,gC1), xS);
          colorWipe2(strip.Color(rC1, gC1, bC1), xS);
          delay(50);
          recvWithStartEndMarkers();
              
  } 
    if (goLED3 == true) {
          colorWipe(strip.Color(rC1, gC1, bC1), xS);
          colorWipe2(strip.Color(rC1/2, gC1/2, bC1/2), xS);
          colorWipe(strip.Color(rC1/5, gC1/5, bC1/5), xS); 
          colorWipe2(strip.Color(rC1/10, gC1/10, bC1/10), xS);
          delay(50);
          recvWithStartEndMarkers();  
  } 
      if (goLED4 == true) {
          colorWipe(strip.Color(gC1,rC1,bC1), xS);
          colorWipe2(strip.Color(bC1,gC1,rC1), xS);
          colorWipe(strip.Color(bC1,rC1, gC1), xS);
          colorWipe2(strip.Color(rC1, gC1, bC1), xS);
          delay(50);
          recvWithStartEndMarkers();
             
  }
  
  
}



void colorWipe(uint32_t color, int wait) {
  
  for(int i=0; i<strip.numPixels(); i++) { // For each pixel in strip...
    strip.setPixelColor(i, color);         //  Set pixel's color (in RAM)
    strip.show();                          //  Update strip to match
    delay(wait);                           //  Pause for a moment
  }
}

void colorWipe2(uint32_t color, int wait) {
  
  for(int i=29; i<strip.numPixels(); i--) { // For each pixel in strip...
    strip.setPixelColor(i, color);         //  Set pixel's color (in RAM)
    strip.show();                          //  Update strip to match
    delay(wait);                           //  Pause for a moment
  }
}

所以我正在做的是我从手机发送一个代码,例如: 它被 void recvWithStartEndMarkers() 拾取解析然后所有值都被 void parseData() 存储为 INT

在循环中我得到了void checkLedData(),它正在调用上面的两个函数,并根据第一个 INT 激活或停用这些布尔值,然后我有 void runLED() 检查布尔值是否为真并开始闪烁 LED

起初我通过INT eFx 激活了开关,但由于某种原因它工作得非常糟糕,所以我决定使用这部分代码来翻转布尔值,在 runLED() 中你会注意到我不断地调用这个函数recvWithStartEndMarkers();,因为这是真正让董事会做出响应的唯一方法。

我不确定发生了什么,我相信它是由于缓冲区溢出问题而起作用的,它崩溃了,然后它可以接受一个新命令,第一个版本在它接受 1 个命令之后就卡住了, void colorWipe 正在工作,因为 LED 正在打开和关闭,切换颜色等等,但是当我试图改变效果或颜色时它根本没有响应。

我在这之前使用的下一个代码:

void loop() {
  recvWithStartEndMarkers();
  if (newData == true) {
        strcpy(tempChars, receivedChars);
            // this temporary copy is necessary to protect the original data
            //   because strtok() used in parseData() replaces the commas with \0
  parseData();
  strip.setBrightness(xbrithness);
  controlLed();
  newData = false;
  }
}

void controlLed() {
         colorWipe(strip.Color(redColor, greenColor, blueColor), xSpeed);
         colorWipe(strip.Color( greenColor, redColor, blueColor), xSpeed);
}

现在这是非常敏感的,但问题是它会通过 void controlLed() 一次并且它停止了,而如果我在 recvWithStartEndMarkers(); 之外调用相同的函数,它将进入循环,就像我想要导致我正在尝试制作循环效果。

有谁知道我可以做些什么来让它响应但仍然循环函数来制作“灯光秀”?

现在我发布了我在想的所有这些,不确定 arduino 是否是多任务处理,我想知道 ATtiny85 是否是多任务处理,所以这可能是问题所在,它忙于处理代码以至于它不会在串行上监听什么是进来了,有什么办法解决吗?

【问题讨论】:

  • 现在我发布了所有我在想的东西,不确定 arduino 是否是多任务我想知道 ATtiny 是否是多任务,所以这可能是问题,它太忙于处理代码,它不会听连续剧有什么进来,有什么办法解决吗?

标签: c++ arduino adafruit neopixel


【解决方案1】:

我很无聊,感觉很慷慨,所以你去吧。看看你能不能遵循这个。它未经编译且未经测试,因此我不能保证它完全符合您的要求,但看看您是否能理解我在这里尝试做的事情。没有什么会停下来等待任何事情发生。没有延迟呼叫。没有等待。只是骑自行车,看看是不是该做点什么了。

我所做的一项更改不会影响这一点,只是让打字更容易,就是取出所有的 goLED 变量并用它们制作一个数组。每当您发现自己将数字放在变量名上时,请改用数组,这样编译器就可以访问这些数字,而您不必重复自己。看看 checkLedData 函数变得多么简单。

然后我创建了 colorWipe 函数,以便它们返回一个布尔值,如果它们已完成,则返回 true,否则返回 false。然后 runLED 函数可以检查是否是时候继续下一步了。对于第一种情况,这很简单,只需将 goLED 变量设置为 colorWipe 返回的任何值。只要它仍在工作,它就会返回 true 并且 goLED[1] 保持 true 并且您继续调用相同的 colorWipe 函数。对于其他我们必须使它们成为状态机,所以我添加了一个状态变量。当他们中的任何一个完成时,他们将他们的 goLED 变量设置回 false。当所有这些都为 false 时,意味着当前没有任何效果在运行,那么 runLED 会一直下降到最后一个 else 语句,然后去查看是否还有其他命令。

就像我说的那样,其中可能有一两个错误。但是看看你是否能理解我是如何写一个清单来看看需要发生什么而不是一个故事来讲述一件接一件的事情。

#include <Adafruit_NeoPixel.h> // NeoPixel Lib
#include <SoftSerial.h>  // Serial Lib
#define LED_PIN    2
#define LED_COUNT 30

SoftSerial bluetooth(4, 5); // RX TX
Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);

const byte numChars = 32;
char receivedChars[numChars];
char tempChars[numChars];
boolean newData = false;

boolean goLED[5];
    
int eFx = 1;
int rC1 = 255;
int gC1 = 0;
int bC1 = 0;
int xS = 20;
int xB = 125;


void setup() {

  bluetooth.begin (9600);
  strip.begin();           // INITIALIZE NeoPixel strip object (REQUIRED)
  strip.show();            // Turn OFF all pixels ASAP

}


void loop() {
  recvWithStartEndMarkers();
  runLED();
}


void recvWithStartEndMarkers() {
  static boolean recvInProgress = false;
  static byte ndx = 0;
  char startMarker = '<';
  char endMarker = '>';
  char rc;

  while (bluetooth.available() > 0 && newData == false) {
    rc = bluetooth.read();

    if (recvInProgress == true) {
      if (rc != endMarker) {
        receivedChars[ndx] = rc;
        ndx++;
        if (ndx >= numChars) {
          ndx = numChars - 1;
        }
      } else {
        receivedChars[ndx] = '\0'; // terminate the string
        recvInProgress = false;
        ndx = 0;
        newData = true;
      }
    }   else if (rc == startMarker) {
      recvInProgress = true;
    }
  }
}


void parseData() {      // split the data into its parts

  char * strtokIndx; // this is used by strtok() as an index

  strtokIndx = strtok(tempChars, ",");      // get the first part - the string
  eFx = atoi(strtokIndx);     // convert this part to an integer

  strtokIndx = strtok(NULL, ",");      // get the first part - the string
  rC1 = atoi(strtokIndx);     // convert this part to an integer

  strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
  gC1 = atoi(strtokIndx);     // convert this part to an integer

  strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
  bC1 = atoi(strtokIndx);     // convert this part to an integer

  strtokIndx = strtok(NULL, ",");
  xS = atoi(strtokIndx);     // convert this part to an integer

  strtokIndx = strtok(NULL, ",");
  xB = atoi(strtokIndx);     // convert this part to an integer

  strtokIndx = strtok(NULL, NULL);
}



void checkLedData() {
  if (newData == true) {
    strcpy(tempChars, receivedChars);
    parseData();
    newData = false;
    strip.setBrightness(xB);
    for (int i = 0; i < 5; i++) {
      if (i == eFx) {
        goLED[i] = true;
      } else {
        goLED[i] = false;
      }
    }
  }
}





void runLED() {
  static int whichStep = 0;
  if (goLED[0] == true) {
    goLED[0] = false;
  }
  else if (goLED[1] == true) {
    goLED[1] = !colorWipe(strip.Color(rC1, gC1, bC1), xS)
  }

  else if (goLED[2] == true) {
    if (whichStep == 0) {
      if (colorWipe(strip.Color(bC1, rC1, gC1), xS)) {
        whichStep = 1;
      }
    }
    else if (whichStep == 1) {
      goLED[2] = !colorWipe2(strip.Color(rC1, gC1, bC1), xS));

    }
  }

  else if (goLED[3] == true) {

    if (whichStep == 0) {
      if ((colorWipe(strip.Color(rC1, gC1, bC1), xS)) {
      WhichStep = 1;
      }
    }
    else if (whichStep == 1) {
      if ((colorWipe2(strip.Color(rC1 / 2, gC1 / 2, bC1 / 2), xS)) {
        whichStep = 2;
      }
    }
    else if (whichStep == 2) {
      if ((colorWipe(strip.Color(rC1 / 5, gC1 / 5, bC1 / 5), xS)) {
        whichStep = 3;
      }
    }
    else if (whichStep == 3) {
      if ((colorWipe2(strip.Color(rC1 / 10, gC1 / 10, bC1 / 10), xS)) {
        goLED[3] = false;
      }
    }
  }
  
  else if (goLED[4] == true) {
    // You write this one
    goLED[4] = false;
  }
  else {
    checkLedData();  // get next command
    whichStep = 0;
  }

}



boolean colorWipe(uint32_t colot, int wait) {
  static unsigned long lastMillis = millis();
  static int state = 0;
  static int ledIndex = 0;

  if (state == 0) {
    lastMillis = millis();
    ledIndex = 0;
    strip.setPixelColor(ledIndex, color);
    strip.show();
    state = 1;
  }
  if (state == 1) {
    if (millis() - lastMillis >= wait) {
      lastMillis = millis();
      ledIndex++;
      strip.setPixelColor(ledIndex, color);
      strip.show();
      if (ledIndex == strip.numPixels() - 1) {
        state = 0;
        return true;
      }
    }
  }
  return false;
}


boolean colorWipe2(uint32_t colot, int wait) {
  static unsigned long lastMillis = millis();
  static int state = 0;
  static int ledIndex = 0;

  if (state == 0) {
    lastMillis = millis();
    ledIndex = strip.numPixels() - 1;
    strip.setPixelColor(ledIndex, color);
    strip.show();
    state = 1;
  }
  if (state == 1) {
    if (millis() - lastMillis >= wait) {
      lastMillis = millis();
      ledIndex--;
      strip.setPixelColor(ledIndex, color);
      strip.show();
      if (ledIndex == 0) {
        state = 0;
        return true;
      }
    }
  }
  return false;
}

【讨论】:

  • 对不起,我的真假倒退了,只是编辑使它正确。因此,当 colorWipe 返回 true 时,它​​通过一次擦除完成,并且 runLED 函数可以将其 goLED 设置为 false 或者可以继续执行该效果的下一步。
  • 我也不确定 colorWipe2 应该做什么。因为它会永远运行。我认为您的 for 循环错误。我认为您想将它们向后点亮,但这并不是您所拥有的。
  • 重要的一点是,我们从 colorWipe 示例代码中保留的只是将像素设置为正确颜色的行。这就是向您展示的所有示例代码。对于示例代码,使用 for 循环以阻塞方式执行此操作很好,但正如您刚刚了解到的,如果您希望代码能够执行其他任何操作,它就不起作用。
  • wwwwoooowwww,非常感谢,我会在一个小时左右检查它,我刚刚注意到你回答了!非常感谢 Delta_G
  • 我清理了代码,这里和那里缺少一些东西或额外的类似; ) 上限和其他阻止编译的东西 / 使用了 5390 字节 (89%)。虽然我正在深入研究它以查看是否可以找到问题,但它不起作用。
猜你喜欢
  • 2012-02-05
  • 1970-01-01
  • 2011-09-07
  • 1970-01-01
  • 2015-12-16
  • 1970-01-01
  • 2010-11-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多