-1

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

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

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

#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
  }
}

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

在我得到的循环内部void checkLedData()调用上面的 2 个函数,并根据第一个 INT 激活或停用这些布尔值,然后我void runLED()检查哪些布尔值是真的并开始闪烁 LED

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

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

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

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 是否是多任务处理,所以这可能是问题所在,它正忙于处理代码,以至于它不会在串行上监听进来的内容,有什么办法可以解决吗?

4

1 回答 1

1

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

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

然后我创建了 colorWipe 函数,以便它们返回一个布尔值,如果它们已经完成,则返回 true,否则返回 false。然后 runLED 函数可以检查它是否是时候继续下一步了。对于第一种情况很简单,只需将 goLED 变量设置为 colorWipe 返回的任何值。只要它仍在工作,它就会返回 true 并且 goLED[1] 保持 true 并且您继续调用相同的 colorWipe 函数。对于其他我们必须使它们成为状态机,所以我添加了一个状态变量。当他们中的任何一个完成时,他们将他们的 goLED 变量设置回 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;
}
于 2020-07-20T22:24:08.987 回答