Hmm... also irgendwie liegt mir das Thema noch immer etwas schwer im Magen.
Ich habe in der Vergangenheit bereits eine Bluetooth-Kommunikation von einem Android Handy zu einem HC-05 BT-Module hinbekommen, welches wiederrum mit dem Arduino kommuniziert.
Da ich mit einem UNO angefangen habe und das HardwareSerial aus Bequemlichkeit freihalten wollte, habe ich immer das SoftwareSerial benutzt.
Bei meinen ProMini Clonen funktioniert das leider extrem instabil.
Auf den Hinweis hin, es evtl. mal mit der AltSoftSerial Library zu versuchen, bin ich gleich auf das hardware Serial gegangen um wirklich die Grenzen ausloten zu können.
Leider läuft das auch kein Stück stabil und ich denke, dass ich da wohl einiges grundlegend falsch machen muss.
Da mein Code insgesamt ca. 18KB groß ist, poste ich hier nur einen Teil, der hoffentlich alles wichtige enthält:
//Serial Monitor
#include <SerialCommand.h>
//SoftwareSerial
#include <SoftwareSerial.h>// import the serial library
SoftwareSerial softSerial(10, 11); // RX, TX
#include <string.h>
// FastSPI WS2812B
#include <FastSPI_LED2.h>
#define NUM_LEDS 50
#define DATA_PIN 13
struct CRGB leds[NUM_LEDS];
unsigned long previousMillis = 0; // speichert wie viele Sekunden seit derletzten Änderung vergangen sind
boolean gelesen = false;
int ledMode = 0;
int ledModeVorher = 0;
static unsigned long int* receivedParameter;
// Diese Funktion liest die komplette Zeichenkette die sie vom BT-Modul erhält ein und erwartet am Anfang zwei Zahlen
// Diese geben die Länge der restlichen Zeichen an
// Beispiel Zeichenkette: 012
// Bedeutung die Restzeichenkette hat eine länge von 01 Zeichen und ist 2.
// 101,0xFF00AA bedeuted 10 Zeichen kommen. Restzeichenkette ist 1,0xFF00AA (in diesem Fall ist das Komma eine Trennung der Parameter. receivedParameter[0] ist 1 => Modus ist 1 (also Farbe aus ColorWheel übernehmen), receivedParameter[1] ist 0xFF00AA => HEX Farbwert für die LEDs.
char* getText()
{
static char charArray[61];
char c;
unsigned int numberOfInts;
int stringLen;
if (Serial.available())
{
memset(charArray,0,sizeof(charArray));// Puffer vor Benutzung löschen
//die ersten beiden Bytes übergeben die maximale Länge der Zeichenkette
//da der Übertragungs-string maximal 63 Zeichen lang sein kann, reichen 2 Bytes
//einstellige Zahlen, werden mit vorangestellter 0 übertragen
//(bei 7 Zeichen ="071,345,7 bei 17 Zeichen = "171,345,789,123,567")
static char stringLenAsChar[2];
// while (Serial.available() == 0) {
// nichts machen, bis die nächsten bytes angekommen sind um sicher zu gehen, dass nichts vergessen wird
// }
//die ersten beiden Bytes einlesen
//Hier müsste man allerdings sicherstellen, dass das Arduino auch wirklich beide Bytes einliest
//mittels delay(5); wäre das wohl wieder zu primitiv oder?
Serial.readBytes(stringLenAsChar, 2);
//das eingelesene charArray in Zahlen wandeln
stringLen = atol(stringLenAsChar);
//und die verbleibenden Zeichen des strings einlesen
Serial.readBytes(charArray, stringLen);
//und dann hier zurück geben
if(stringLen>0)
{
stringLen=0;
return charArray;
}
else
{
return NULL;
}
}
}
// Die erhaltene Zeichenkette "auseinander schneiden" und in einzelene Parameter (array) speichern
unsigned long int* cutText(char* text, int* numberOfInts)
{
const int maxIntParam = 32;
static unsigned long int intArray[maxIntParam];
memset(intArray, 0, maxIntParam * sizeof(long)); //eventuell unnötig "wenn ich nicht über das array iteriere"
int count = 0;
char* pch = strtok(text, ",");
while(pch != NULL && count < maxIntParam)
{
intArray[count++] = strtol(pch, NULL, 0);
pch = strtok(NULL, ",");
}
*numberOfInts = count;
return intArray;
}
void setup()
{
// SoftSerial initiierung
softSerial.begin(57600);
softSerial.println("Bluetooth an und verbunden. Warte auf Eingabe...");
//Serial initiierung
Serial.begin(57600);
LEDS.addLeds<WS2812B, DATA_PIN, GRB>(leds, NUM_LEDS);
}
void loop()
{
while (Serial.available() > 0)
{
char* serialText = getText();
if(serialText != NULL)
{
Serial.print("Gesamter Text: ");
Serial.println(serialText);
int numberOfInts;
receivedParameter = cutText(serialText, &numberOfInts);
for (int i =0; i < numberOfInts ; i++)
{
Serial.print("Parameter ");
Serial.print(i);
Serial.print(": ");
Serial.println(receivedParameter[i]);
}
Serial.print("anzahl der Parameter: ");
Serial.println(numberOfInts);
}
}
}
Ich weiß nicht ob die geschweiften Klammern jetzt stimmen, da es doch etwas viel ist, was ich da kopiert habe.
Es sollte aber das wichtige komplett dabei sein, damit ihr sehen könnt, wie ich was genau mache.
Ich habe mich über den Seriellen Monitor aus der Arduino Entwicklungsumgebung mit dem Arduino verbunden (bei einer Baudrate von 57600) und habe die Zeichenketten manuell über diesen eingegeben.
Häufig wird dabei der "serialText", also die bereits empfangene und verarbeitete Rest-Zeichenkette, falsch angezeigt.
Falls ihr es nicht gelesen habt (in den Kommentaren im Code):
Ich sende eine Zeichenkette seriell an das Arduino. Die ersten beiden Zeichen werden direkt eingelesen und geben dann die Anzahl der folgenden Zeichen an. (bei einstelligen Zahlen haben diese eine vorangestellte Null)
Grund dafür war, dass in der Vergangenheit SoftSerial.readBytes am stabilsten und schnellsten lief und ich einfach nichts anderes hinbekommen habe...
Der gesamte Code verzichtet (bis auf das setup) komplett auf delay() und er sollte daher eigentlich keine echten Aufhänger haben.
Zum debuggen gebe ich das Empfangene auch wieder per Serial aus, damit ich es am SM prüfen kann.
Vielleicht entsteht hier nochmal zusätzlich eine Instabilität, allerdings ist das was ich bisher getestet habe ernüchternd...
Sobald ich was "etwas schneller" per SM eingebe verschluckt sich die Kommunikation und es kommt teilweise nichts an.
Doch auch wenn ich warte, kommt es teils zu Fehlern, wie bei einer Zeichenkette, die eigentlich so aussehen sollte "9,23" die dann nur nich "9," ausgibt.
Das Ganze sollte aber wirklich stabil laufen - und dabei möglichst schnell.
Es sollen später bis zu insgesamt 12 stellige Zeichenketten schnell hintereinander per BT übertragen werden (das geht auch) und dann seriell an das Arduino geschickt werden.
Momentan ist mir egal ob per SoftSerial, AltSoftSerial oder echtem hardware Serial. Hauptsache stabil und schnell.
Die Zeichenketten sehen dann etwa so aus : 101,0xFF9900 (10 Zeichen folgen welche "1,0xFF9900" lauten. Das bedeutet Modus 1: Alle LEDs mit der HEX-Farbe 0xFF9900 leuchten lassen).
Die schnelle Übertragung brauche ich, weil die App einen Farbkreis hat, über den man mit dem Finger streifen kann und die LEDs in dieser Farbe leuchten.
Das klappt auch im großen und Ganzen, aber eben nicht stabil.
Beim Benutzen des Farbkreises fällt das nicht auf.
Besonders ärgerlich ist es aber, weil man die Farbwerte dann mittels "Speichern"-Button in der App in das EEPROM speichern lassen kann (können sollte), um sie dann vom Arduino später wieder aufzurufen.
Wenn jetzt die Zeichenkette 012 ( 01 Zeichen, Modus 2: Speichern) fehlerhaft ankommt, kann man als Benutzer nicht überprüfen ob es wirklich gespeichert wurde.
Eine art Handshakeprotokoll übersteigt meine Möglichkeiten bei weitem - vor allem was das grausige Android programmieren angeht. Zumal das die Geschwindigkeit wieder um einiges senken würde.
Ich hoffe daher mal wieder auf die tatkräftige Unterstützung von uwe, stefan, jurs, serenifly und die vielen anderen Profis die sich hier so tummeln ![]()
Vielen Dank und liebe Grüße!