Hallo,
ich arbeite gerade an einer Bluetooth Verbindung mit dem Arduino.
Genutzt wird ein Uno R3. Da der Uno aber im Gegensatz zum Mega nur eine
Serielle Schnittstelle zur Verüfung hat, war ich gezwungen, diese
Softwareseitig zu erstellen. Die eigentliche StdLib von der Arduino.cc
Seite hatte einige Probleme, zumal entwder nur abhören oder senden
möglich ist. Nun habe ich mit der AltSerialSoft eine gute bzw. bessere
Alternative gefunden. Diese fühlt sich Performancetechnisch genauso wie
die Serielle Schnittstelle an.
So, nun zu meinem Problem.
Ich möchte gerne Strings von einem Bluetooth Client an den Arduino
schicken. Das funktioniert auch schon soweit, jedoch teils nicht
effizent genug.
Das Problem ist, ich sende immer den ganzen Datensatz, welchen ich dann
in einem Array abspeicher.
Ich würde aber gerne immer nur bestimmte Werte schicken, anstatt dem
ganzen Datensatz.
Ich stell mir sowas vor.
Wenn der String "A235B\n" ankommt, soll er als Zuweisungschar das A
nehmen. Somit soll so die Position/Index im Array bestimmt werden. B
möchte ich als Terminierungszeichen senden.
Nun kann es vorkommen, dass als String auch "A234B,C232D\n" ankommt.
Hier sollte er natürlich beide Werte verarbeiten.
Bislang komme ich aber nicht mehr weiter.
So sieht meine Funktion derzeit aus. Sie liest alle Zahlen ein, welche
mit einem "," getrennt sind. Also terminierung erfolgt ein Zeichen,
welches keine Zahl und nicht "," ist.
1
// PC USB
2
if(Serial.available())
3
{
4
char ch = Serial.read();
5
// ASCII-Zeichen zwischen 0 und 9?
6
if(ch >= '0' && ch <= '9')
7
{
8
// Ja, Wert akkumulieren, solange fieldIndex gültig ist
Stefan schrieb:> Ich möchte gerne Strings von einem Bluetooth Client an den Arduino> schicken. Das funktioniert auch schon soweit, jedoch teils nicht> effizent genug.>> Das Problem ist, ich sende immer den ganzen Datensatz, welchen ich dann> in einem Array abspeicher.
Wer ist hier "ich"? Wo wird das Array abgespeichert? Auf dem BT-Client?
Auf dem Arduino?
> Ich würde aber gerne immer nur bestimmte Werte schicken, anstatt dem> ganzen Datensatz.
Dann mach das doch einfach. Wo kommen denn die Strings her? Wer erzeugt
die?
Stefan schrieb:> So sieht meine Funktion derzeit aus. Sie liest alle Zahlen ein, welche> mit einem "," getrennt sind. Also terminierung erfolgt ein Zeichen,> welches keine Zahl und nicht "," ist.
Ja und?
Ich sehe jetzt in deinem Code nirgendwo, dass das erste Zeichen (welches
ja der Buchstabe zur Identifikation ist) speziell behandelt werden
würde.
Ohne den abzutrennen geht schon mal gar nichts.
Mach dich mal mit dem Gedanken vertraut, dass eine Zeile aus mehreren
Messages besteht. Jede Message kann mit einem Buchstaben beginnen,
welche dir sagt, was mit der nachfolgenden Zahl passieren soll.
Also ich finde kein Problem bei Deiner Routine, weshalb ist Dir das
nicht effizient genug?
Man kann / braucht nicht viel mehr machen als die Zeichen einlesen und
zuordnen.
Rein strukturell könntest Du es noch in Richtung State Machine
weiterentwicklen, dann wird es etwas klarer und Du kannst noch eine
Fehlerprüfung in den Empfang einbauen, weil der State auch festlegt, was
jetzt kommen darf und dadurch eine verarbeitbare Fehlerbedinungen
entsteht.
State WAITING_FOR_DATA
warte auf Startzeichen / Startindex
-> wenn ein Zeichen kommt gibt das den Wert an, der übertragen wird.
Hier kann ein Wertebereich, eine Wertemenge hinterlegt sein, die
kommen darf, alles andere: Fehler. Dann wird alles ignoriert bis zur
Ende-Bedingung oder zu einer neuen Startbedingung: State = WAIT_FOR_END
-> wenn der richtige Index kommt -> State = RECEIVING_DATA
State RECEIVING_DATA:
erlaubte Zeichen 0...9, sonst Fehler: WAIT_FOR_END
State WAIT_FOR_END: verwerfe jedes Zeichen bis \n kommt, dann State =
WAITING_FOR_DATA
und so weiter.
Hier verarbeitest Du quasi die "Grammatik" Deiner Übertragung und hast
immer einen Pfad, der weitergeht von jedem Punkt.
Google mal nach State Machine, kann man ganz einfach aber auch ganz
aufwändig machen.
Aber im Prinzip tun es ein paar States wie die obigen und mehrere if
oder ein switch/case-Block.
Vg,
Conny
Conny G. schrieb:> Also ich finde kein Problem bei Deiner Routine, weshalb ist Dir das> nicht effizient genug?> Man kann / braucht nicht viel mehr machen als die Zeichen einlesen und> zuordnen.
Sagt er auch nicht.
Aber es ist ein wenig sinnlos, 50 Werte zu übertragen, wenn sich nur
einer geändert hat. Und genau da will er hin: anstatt ständig alle 50
übertragen zu müssen, will er sich eine Kennung einbauen, so dass er
einen einzelnen Wert samt seiner 'Adresse' auf den Weg schicken kann.
Im Grunde entdeckt er gerade, dass die ürsprüngliche
Design-Entscheidung, einfach alle 50 Werte, jeweils durch Komma getrennt
und mit einem \n abgeschlossen, nicht unbedingt die beste Wahl war. Er
ist drauf und drann zu entdecken, dass man in einem Protokoll auch
Steuerinformationen braucht, die den Empfänger bei der Interpretation
der empfangenen Daten leiten.
@rufus: Die Werte werden auf dem Arduino in settings[] abgespeichert die
ich später in meinen Funktionen wieder aufrufe.
@kbuchegg: Ja richtig. Ich weiß nicht genau, wie ich das machen soll.
Ja kbuchbegg bringt es auf den Punkt. Auch wenn es in meinem Fall nur 5
byte und 1 uint sein werden, kommt mir das teils relativ langsam vor.
Ich habe derzeit einmal die Serielle Konsole auf dem Handy. Des weiteren
habe ich eine kleine App mit dem App Inventor schnell
zusammengeschrieben. Ziel ist es später, mit den Slider mehr oder
weniger in Echtzeit den Farbton von RGBs zu bestimmen. Bei vorherigen
Versionen bekam ich irgendwann Probleme, da er bereits neue Daten
geschickt hat, ehe die alten verarbeitet/im Buffer geschrieben wurden.
Gibt es abzufragen, wievel Buchstaben noch bis zum nächsten
Steuerzeichen kommen? Dann könnte ich die Abfrage vervollständigen mit
einer for-Schleife, die so häufig die Werte 0 - 9 einliest, bis ein
Steuerzeichen kommt.
Stefan schrieb:> Was ich an der ersten Lösung von mir nicht mag ist, dass wenn ich nur> den ersten Wert ändern möchte, den kompletten String eingeben muss.
Ja, das ist klar.
Und deshalb möchtest Du etwas schicken wie A123B, also abstrakter
<Index-Angabe>(<Zeichen 0..9>{n Mal}])<Terminator>.
Aus meiner Sicht spräche auch nichts dagegen, die Syntax zu erweitern
in:
<Index-Angabe>(<Zeichen 0..9>{n Mal}])<Terminator>[;<das ganze
nochmal>[;<das ganze nochmal>]]
Und die State Machine dafür funktioniert so:
die SM wird initialisiert auf einen Startwert, der heisst "Startzeichen
empfangen".
Dann wird immer ein Zeichen eingelesen, solange bis das Startzeichen
empfangen wird (vielleicht ist auch jedes beliebige Zeichen das
Startzeichen, auch ok).
Danach weisst Du von obiger "Grammatik", dass n Zeichen 0..9 kommen
dürfen, also bist Du im Modus "n Zeichen Daten empfangen", Du füllst
also Deinen Puffer und hörst bei n Zeichen auf, wartest dann auf das
Ende-Zeichen, den Terminator.
Jede dieser Phasen hat einen "State"-Wert (wie ich schon geschrieben
hatte).
Damit hast Du eine Schleife, die immer ein einzelnes Zeichen einliest
und bewegst Dich in diesen Stati weiter.
Immer wenn was schief geht, Du etwas empfängst, was nicht passt kannst
Du auf einen State gehen, der die Situation wieder in Ordnung bringt,
üblicherweise "Warte auf Terminator" (und damit ignorierst Du alles, was
dann noch kommt) oder einfach "Warte auf Startzeichen".
Das entspricht der Schleife, die Du selbst schon gepostet hast, ist
aber etwas aufgeräumter, transparenter, flexibler. Flexibler gerade in
Fehlersituationen, weil Du frei zwischen den States springen kannst.
Genau deshalb würde ich auch keine for-Schleife, sondern lieber die
State Machine machen.