Anfänger braucht Erklärung zu serial mit read/write/print

Hallo,
mir will die Verwendung von serial.read() und serial.write() nicht in den Kopf.
Ich verstehe nicht welchen ich wann nehmen muss, da meine Werte nie konstant angezeigt werden.

Verwendete Komponenten:
Arduino UNO
HC-06 Bluetooth
Android Smartphone mit BlueTerm App

Das BT-Modul ist simple verkabelt:
BT(RX) an UNO(TX)
BT(TX) an UNO(RX)

  • VCC & GND

Als Code verwende ich SoftwareSerial von hier: http://arduino.cc/en/Tutorial/SoftwareSerialExample
Die Pins, die Ausgabe und die BAUD-Rate habe ich für mich ein wenig angepasst.

#include <SoftwareSerial.h>

SoftwareSerial bluetooth(0, 1); // RX, TX

void setup()  
{
  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  Serial.println("Goodnight moon!");

  // set the data rate for the SoftwareSerial port
  bluetooth.begin(9600);
  bluetooth.println("Hello, world?");
}

void loop() // run over and over
{
  if (bluetooth.available() > 0)
  {
    Serial.write(bluetooth.read());
    Serial.print("Serial: ");
    Serial.print(Serial.read());
    Serial.println("");
  }
  if (Serial.available() > 0)
  {
    Serial.print("BT: ");
    bluetooth.write(Serial.read());
    Serial.println("");
  }
}

Interessanterweise fängt das Problem schon recht oben an.
BT und Android sind verbunden.
Die App zeigt mir “Goodnight moon!” an.
Aber “Hello, world?” hingegen wird mir nicht angezeigt. Wo landet das?

Tippe ich dann in der App z.B. ein “A” ein, erscheint diese Ausgabe:

BT: A
Serial: -1

Tippe ich nochmals ein A ein regiert der Zufall und manchmal kommt diegleiche Antwort wie oben oder halt diese Ausgabe:

BT: A
Serial: -1
Serial: 65 <--> nur diese Zeile kommt dann hinzu

Kommuniziere ich einfach nur falsch mit dem BT?
Ist das read() oder write() falsch?
Ich dachte eigentlich das der Ablauf dieser wäre:

  1. Verbindung aufgebaut
  2. Tippe ein “A” in der Android App
  3. Android schickt per Bluetooth das “A” an das BT-Modul vom UNO
  4. In der loop() wird geprüft ob “bluetooth.available() > 0” ist
  5. Da ein “A” gesendet wurde stimmt 4.
  6. Das “A” wird eingelesen und eine Ausgabe erzeugt.
    Aber warum bekomme ich immer eine “-1” als Antwort und manchmal den ASCII Wert des Buchstabens “A”.
    Und warum erzeugt “Serial.available > 0” in der Ausgabe immer den übermittelten Buchstaben “A”?

Wie herum muss ich bluetooth.write und Serial.write verwenden?

Das brauchst du nicht! Über Pin 0 und 1 läuft bereits Rx und Tx. Wenn du das nutzt, darf das BT Modul während des Uploads nicht angeschlossen sein. Nutze 2 andere Pins am besten.

SoftwareSerial bluetooth(0, 1); // RX, TX

Serial.read() liest an der Seriellen Schnittstelle

Serial.write/print() schreibt an der Seriellen Schnittstelle

Liest du da nicht etwas von der USB Verbindung obwohl gar nichts eingegeben wurde:
Serial.print(Serial.read());

Dann kommt da klar -1

Sollte das nicht eher so sein:

  if (bluetooth.available() > 0)
  {
    char c = bluetooth.read();
    Serial.print("Serial: ");
    Serial.println(c);
  }

Das liest ein Zeichen von Bluetooth und schickt es an die USB Verbindung

EDIT:
Und was sschultewolter gesagt hat. Gar nicht gesehen :o

sschultewolter:
Das brauchst du nicht! Über Pin 0 und 1 läuft bereits Rx und Tx. Wenn du das nutzt, darf das BT Modul während des Uploads nicht angeschlossen sein. Nutze 2 andere Pins am besten.

SoftwareSerial bluetooth(0, 1); // RX, TX

Entschuldige, ich kann dir leider nicht ganz folgen.
Was brauche ich nicht?
Soll ich die Zeile "SoftwareSerial" weglassen? Aber wie kommuniziere ich dann mit dem Bluetooth?

Wenn ich den upload ausführe, darf ich nur über den PC kein Bluetooth aktiviert haben, ansonsten wird der Upload, selbst mit verbundenem Bluetooth zu Android, fehlerfrei ausgeführt.
Oder ergeben sich da Probleme, die nicht in der Konsole angezeigt werden?

Serenifly:
Liest du da nicht etwas von der USB Verbindung obwohl gar nichts eingegeben wurde:
Serial.print(Serial.read());

Dann kommt da klar -1

Sollte das nicht eher so sein:

  if (bluetooth.available() > 0)

{
   char c = bluetooth.read();
   Serial.print("Serial: ");
   Serial.println(c);
 }




Das liest ein Zeichen von Bluetooth und schickt es an die USB Verbindung

Öhm, nein das USB-Kabel verbinde ich nur mit dem PC wenn ich den Code erneut hochlade.
Nach dem Upload trenne ich die USB-Verbindung.

Bedeutet das, dass ich den unteren Block

  if (Serial.available() > 0)
  {
    Serial.print("BT: ");
    bluetooth.write(Serial.read());
    Serial.println(" ");
  }

überhaupt nicht gebrauchen kann, sofern ich mich über Bluetooth verbinde?

Das ist ja mein Problem, trotz Anleitung verstehe ich den Zusammenhang scheinbar nicht,
ob ich Serial überhaupt brauche und von wo Serial.read() die Daten einliest wenn ich nur über Bluetooth verbunden bin.
Ebenso Serial.write().
Macht das Sinn bei einer Bluetooth-Verbindung?
Ist das eventuell wirklich nur für eine Direktverbindung zwischen Arduino und PC mittels USB-Kabel?

Serial ist die Hardware-Schnittstelle, die an der USB Buchse und Pins 0 und 1 hängt. Da das eben fest mit der USB Buchse verbunden ist, verwendet man das i.d.R. dann nur zur PC Kommunikation.

Für Bluetooth nimmt man SoftSerial, oder besser AltSoftserial an anderen Pins. Da kannst du den Serial Kram weglassen und mit SoftSerial senden und empfangen. Zum lesen machst du dann bluetooth.read()

Äh, dann ist der ganze "Serial"-Code völlig belanglos solange ich nur über Bluetooth kommuniziere?
Oh ne! :0
Das hat mich die ganze Zeit über verwirrt, da ich dachte, dass ich mit dem Einem lesen und mit dem Anderem schreiben muss.
Also ich hab das so verstanden, dass es zwei Schritte sind. Bluetooth vom Smartphone zum Bluetooth vom Arduino und dann nochmal vom Bluetooth Arduino zum Arduino direkt. Und natürlich das Ganze wieder zurück.
Au Backe!

Ich werde das gleich mal testen.
Aber ich sag schon mal vielen Dank für die Erklärung. Das muss es ja dann sein.

Serenifly:

  if (bluetooth.available() > 0)

{
   char c = bluetooth.read();
   Serial.print("Serial: ");
   Serial.println(c);
 }

Klasse!
Ich habe einfach deinen Code-Block anstelle meines Wirrwarr eingefügt und bekomme exakt jeden Buchstaben bzw. jede Zahl die ich eintippe zurück.

Aber eine Frage bleibt jetzt doch noch. :smiley:
Wie sorgt "Serial.print()" dafür, dass das Ergebnis auf meinem Smartphone angezeigt wird?
Ich hätte dafür "bluetooth.write()" verwendet, um zu antworten. Und das hätte mich wieder Stunden gekostet, den Fehler zu finden.

Wann und wofür brauchte ich dann bluetooth.write() wenn ich die Daten auf dem Handy auch mit Serial.print bekomme?

Im Prinzip passt so grob. Aber halt nur der SoftSerial Teil wenn du nicht gleichzeitig mit dem PC kommunizieren willst.

Das Bluetooth Modul kannst du dir eigentlich wegdenken. Du kommunizierst zwischen Arduino und Handy. Das Modul setzt dann serielle Kommunikation auf Bluetooth um. Aber du bekommst davon eigentlich nichts mit. Das ist auch nicht anders als wenn man Daten zwischen Arduino und PC austauscht. Nur dass man statt an der Hardware-Schnittstelle eine Software-Emulation hat.

Wie sorgt "Serial.print()" dafür, dass das Ergebnis auf meinem Smartphone angezeigt wird?
Ich hätte dafür "bluetooth.write()" verwendet, um zu antworten. Und das hätte mich wieder Stunden gekostet, den Fehler zu finden.

Hast du immer noch das Bluetooth Modul an der Hardware Schnittstelle? Das ist falsch. Du musst RX und TX beides über SoftSerial machen! Und auf anderen Pins als 0 und 1! Dann kannst du auch mit bluetooth.write() die Daten zurück schicken.

Sowie ich das geschrieben hatte sollte das Daten vom Handy empfangen und an den PC weiterleiten. Ich hatte da dein Problem falsch verstanden. Sorry.

Dir sollte noch der Unterschied zwischen write() und print() klar sein. write() sind Binärdaten, also reine Zahlen. print() ist ASCII.

EDIT:
Du kannst das Modul theoretisch auch an an 0 und 1 betreiben. Dann aber mit Serial und ohne den ganzen SoftSerial Kram. Das Problem dabei ist aber wie gesagt, dass es dann beim Upload nicht angesteckt werden darf, da der Upload auch über diese Schnittstelle erfolgt. Deshalb ist SoftSerial hier meistens die bessere Wahl. Auch weil man dann noch die Hardware-Schnittstelle zum Debuggen nehmen kann.