Bluetooth WS2812 Strip Code

Hallo liebes Forum :slight_smile:

Im Moment versuche ich einen Code zu schreiben, der es mir ermöglicht meinen 5 Meter WS2812 LED Strip in seiner Farbe oder Animation zu steuern. Der Code den ich geschrieben habe funktioniert einigermaßen, aber halt nicht wirklich. Mein Problem liegt daran, dass die Nachrichten, die per Bluetooth an den Arduino geschickt werden meistens nicht richtig ankommen und die ganze Sache nicht funktioniert oder der Arduino gar komplett aufhört auf Nachrichten zu hören. Ich benutze jetzt noch einen Arduino Mega und nur Teile des Strips, aber werde später einen Arduino Pro Mini benutzen, deshalb sind im jetzigen Code auch noch Serial und Serial1, welche aber zu Serial geändert werden sobald der Code funktioniert.

Hier der Code:

#include <FastSPI_LED2.h>
#define NUM_LEDS 75    // Anzahl an Leds am WS2812 Strip
#define RGBORDER GRB  // RGB Anordnung vom WS2812 Strip
#define DATA_PIN 6    // DATA Pin Arduino

CRGB strip[NUM_LEDS];

//Message stuff
char receiveBuffer[20];
char i;
boolean data = false;
long timeOut;
#define TIMEOUT_INTERVAL 5000
//

//Bools and variables for LED logic
int BRIGHTNESS = 0;
unsigned char ccr, ccg, ccb, test, id;
int ir, ig, ib;
int type;
int action;

//Fade stuff
int rCurrent, gCurrent, bCurrent;
int fadeTimer = 0;
int endTimer = 50; 
//

void setup() {
  rCurrent = gCurrent = bCurrent = 0;

  FastLED.addLeds<WS2812, DATA_PIN, RGBORDER>(strip, NUM_LEDS);
  FastLED.show(); 
  Serial.begin(57600);
  Serial1.begin(57600);
}

void loop(){
  
  if(Serial1.available() > 0)  {                           // data received from smartphone
   delay(2);
     int i=0;      
     while(Serial1.available())  {
       delay(1);
       if(i<20){
       receiveBuffer[i] = Serial1.read();
       i++;
     }
     }
     //data = true;
   }

  //if(data) {
    //data = false;
    
    if(receiveBuffer[0] == 0x0F)  { // Color command
      //Serial.println("Received Color Command");
      action = 5;

      receiveBuffer[15] = '\0';

      if (receiveBuffer[4] == ';' && receiveBuffer[8] == ';' && receiveBuffer[12] == ';' && receiveBuffer[14] == ';') {
        parseColorInput(receiveBuffer);

        if(receiveBuffer[13] == '5'){
          transition(random(0,3));
        }
        else{
          test = (receiveBuffer[13] - '0');
          transition(int(test));
        }        
      }
    }
    else if(receiveBuffer[0] == 0x01) { // Effect Command
      //Serial.println("Received Effect Command");

      receiveBuffer[5] = '\0';

      if (receiveBuffer[4] == ';') {

        id =  (receiveBuffer[1] - '0') * 100;
        id += (receiveBuffer[2] - '0') * 10;
        id += (receiveBuffer[3] - '0');

        action = int(id);
      }
    }

  doEffects();

}

//Pick right transition
void transition(int type){
  switch (type) {
  case 0:    
    setColorFade(NUM_LEDS, ir, ig, ib);
    //Serial.println("0");
    break;
  case 1:    
    setColorRunF(NUM_LEDS, ir, ig, ib);
    //Serial.println("1");
    break;
  case 2:   
    setColorRunB(NUM_LEDS, ir, ig, ib);
    //Serial.println("2");
    break;
  } 
}
//

//parse Color Input
void parseColorInput(char * serialBuffer) {
  ccr = (serialBuffer[1] - '0') * 100;
  ccr += (serialBuffer[2] - '0') * 10;
  ccr += (serialBuffer[3] - '0');
  ccg = (serialBuffer[5] - '0') * 100;
  ccg += (serialBuffer[6] - '0') * 10;
  ccg += (serialBuffer[7] - '0');
  ccb = (serialBuffer[9] - '0') * 100;
  ccb += (serialBuffer[10] - '0') * 10;
  ccb += (serialBuffer[11] - '0');

  ir = int(ccr);
  ig = int(ccg);
  ib = int(ccb);
}
//

//Change colors with running from one end to the other
void setColorRunF(int ledcount, int r, int g, int b){
  for(int led = 0; led < NUM_LEDS; led++) {
    strip[led] = CRGB(r,g,b);
    FastLED.show();
    delay(20);
  }
  rCurrent = r;
  gCurrent = g;
  bCurrent = b;
}
//and backwards
void setColorRunB(int ledcount, int r, int g, int b){
  for(int led = NUM_LEDS; led >= 0; led--) {
    strip[led] = CRGB(r,g,b);
    FastLED.show();
    delay(20);
  }
  rCurrent = r;
  gCurrent = g;
  bCurrent = b;
}
//

//Change colors with smooth fading
void setColorFade(int ledcount, int r, int g, int b){
  //if new color does not equal to old color

  if(rCurrent != ir || gCurrent != ig || bCurrent != ib){

    //Serial.println("Colors need to be faded");

    for(int h = 0; h < 260; h++){ 

      if(ir < rCurrent) rCurrent--;
      else if(ir > rCurrent) rCurrent++;
      if(ig < gCurrent) gCurrent--;
      else if(ig > gCurrent) gCurrent++;
      if(ib < bCurrent) bCurrent--;
      else if(ib > bCurrent) bCurrent++;

      //Serial.println(rCurrent);

      for(int led = 0; led < ledcount; led++) {
        strip[led] = CRGB(rCurrent, gCurrent, bCurrent);
      }
      FastLED.show();
    }
  }
}
//


//fade right
void gradientRight(byte ledcount, byte rainbowWidth, byte sat, unsigned int duration) {
  memset(strip, 0, ledcount*3);
  byte hue[NUM_LEDS];

  // Farbverschiebung
  byte colorshift = (255*millis()/duration)%255;
  for(int i = 0; i < ledcount; i++)	{
    hue[i] = (i*255/rainbowWidth+colorshift)%255;
  }

  // Farbton nach rechts verschieben (1 2 3 4 5, -> 5 1 2 3 4)
  for(int led = 0; led < ledcount; led++) {
    strip[ledcount-(led+1)] = CHSV(hue[led], sat, 200);
  }
  FastLED.show();
}
//

//run Effects
void doEffects(){
  if(action == 0){
    gradientRight(NUM_LEDS, NUM_LEDS, 255, 6000);
  }
}
//

Ich hoffe Ihr könnt mir weiterhelfen.

Gruß Moritz

Wieder mal das Interrupt Problem?

FastSPI deaktiviert die Interrupts w√§hrend der Strip angesteuert wird. W√§hrend dessen kannst du also nichts √ľber Serial empfangen oder auf andere Interrupts reagieren.

Um Strings in Integer zu wandeln gibt es √ľbrigens atoi(). Das braucht auch keine Null-terminierten Teil-Strings, sondern wandelt solange um bis es auf ein Zeichen trifft das keine Ziffer ist.

Serenifly: Wieder mal das Interrupt Problem?

FastSPI deaktiviert die Interrupts. W√§hrend dessen kannst du also nichts √ľber Serial empfangen oder auf andere Interrupts reagieren.

Gibt es da ne Lösung oder ist das dann einfach so ?

Serenifly: Um Strings in Integer zu wandeln gibt es √ľbrigens atoi(). Das braucht auch keine Null-terminierten Teil-Strings, sondern wandelt solange um bis es auf ein Zeichen trifft das keine Ziffer ist.

atoi() hatte ich schon ausprobiert. Bekomme aber dann diese Fehlermeldung:

error: invalid conversion from 'unsigned char' to 'const char*'
error: initializing argument 1 of 'int atoi(const char*)'

Weil du wahrscheinlich sowas machst:

int value = atoi(serialBuffer[1]);

Geht nat√ľrlich nicht weil du eine Adresse √ľbergeben musst:

int value = atoi(&serialBuffer[1]);

Das ist genau was deine Fehlermeldung anmeckert. Die Funktion will einen char* (Zeiger auf char). Keinen char. Aber keine Ahnung wo da plötzlich ein unsigned herkommt

Super Danke :D das mit atoi() funktioniert jetzt.

Aber das mit den Interrupts kann man nicht ändern ?

Die Interrupts sind nur während show() deaktiviert. Danach geht es wieder.

Du kannst mal probieren ob du das irgendwie synchronisiert bekommst. Also z.B. ein Byte senden um zu Signalisieren dass du bereit bist was zu empfangen. Und dann ein wenig auf eine Anwort warten, bis du die nächste Animationsphase machst. Aber der Sender darf nicht ungefragt Daten senden.

Serenifly: Die Interrupts sind nur während show() deaktiviert. Danach geht es wieder.

Du kannst mal probieren ob du das irgendwie synchronisiert bekommst. Also z.B. ein Byte senden um zu Signalisieren dass du bereit bist was zu empfangen. Und dann ein wenig auf eine Anwort warten, bis du die nächste Animationsphase machst. Aber der Sender darf nicht ungefragt Daten senden.

Ach so ... also sagen wir zum Beispiel 0x05 senden und der Arduino erwartet dann nach ein wenig Zeit ein Kommando ?