TTL Serial Port über einzelnen Draht

Ich habe ein Gerät welches via TTL über einen einzelnen Daten Draht in beide Richtungen kommuniziert. (Es handelt sich dabei offenbar auch nicht um RS485) Das Gerät wartet kurz gesagt darauf das ein anders Gerät Daten schickt und den Daten Draht wieder freigibt um eine Antwort zurück zu schicken. Ich habe dies zur Zeit folgendermassen auf meinem Arduino umgesetzt indem ich einfach den RX und TX Pin auf diesen einen Daten Draht verbunden habe:

void loop() {
  SoftwareSerial mySerial(11, 10); // RX, TX
  mySerial.begin(1200);
  pinMode(10, OUTPUT);

  mySerial.write(IrgendwelcheDaten);
  
  //TX Pin auf Output stellen um Daten empfangen zu können.
  pinMode(10, INPUT);
  
  byte buffer[2];
  mySerial.readBytes(buffer, 2);
  
  delay(10);
}

Dieser Code scheint zu funktionieren und ich kann Anfragen schicken und Daten empfangen. Meine Frage ist nun einfach ob dies der richtige Weg ist oder ob es eine bessere Lösung dafür gibt.

Ausserdem frage ich mich ob dies auch mit einem Hardware Serial Port umgesetzt werden könnte und ob das grundsätzlich besser oder schlechert wäre als mit der Software Emulation. (Ich habe schon mal herausgefunden das bei Hardware Serial Ports nach dem write gleich schon mal ein read gemacht werden muss da diese Serial Ports die write eigenen Befehle empfangen)

Du solltest vielleicht mit Pullup arbeiten und den Ausgang mit einer Diode entkoppeln.
Oder mit Widerständen den Strom begrenzen.
Die Gegenseite wird auch sowas tun, z.B. einen OpenDrain Ausgang haben.

Grundsatz:
Niemals dürfen 2 Treiber gegeneinander arbeiten!

//TX Pin auf Output stellen um Daten empfangen zu können.

pinMode(10, INPUT);

Diskrepanz zwischen Kommentar und Code.
Ein Schock für meine Sehnerven.

Tipp:
In solchen Fällen bitte den Code reparieren, oder den Kommentar entsorgen.

Ein einzelner Draht reicht keinesfalls aus, entweder drahtlos, oder mindestens 2 Drähte damit Strom fließen kann.

Übertragung über 1 Leitung (nicht Draht!) nennt man Halbduplex, über 2 Leitungen Vollduplex. Bei Halbduplex muß irgendwie zwischen Sender und Empfänger abgesprochen werden, wer senden und wer empfangen darf. Mit RS-485 kann man das etwas vereinfachen, wenn jede Seite zunächst nur auf Daten wartet. Dann kann eine Seite einfach anfangen zu senden, in der Hoffnung daß die Gegenseite das merkt und nicht ebenfalls anfängt zu senden.

Hi

Denke, wir reden hier von einer Art OneWire, wo (neben GND) nur ein Daten-Draht benötigt wird.

MfG

Optimist :wink:

DrDiettrich:
Ein einzelner Draht reicht keinesfalls aus, entweder drahtlos, oder mindestens 2 Drähte damit Strom fließen kann.

Übertragung über 1 Leitung (nicht Draht!) nennt man Halbduplex, über 2 Leitungen Vollduplex. Bei Halbduplex muß irgendwie zwischen Sender und Empfänger abgesprochen werden, wer senden und wer empfangen darf. Mit RS-485 kann man das etwas vereinfachen, wenn jede Seite zunächst nur auf Daten wartet. Dann kann eine Seite einfach anfangen zu senden, in der Hoffnung daß die Gegenseite das merkt und nicht ebenfalls anfängt zu senden.

Ja es muss sich hier um eine Halbduplex Übertragung handeln. Ich habe von dem Gerät das ich ansteuern will leider Dokumentation. (Gibt der Hersteller leider nicht heraus) Das ganze funktioniert ja auch bereits und ich kann Daten senden und empfangen. Ich wollte nur fragen ob es vielleicht Beispiele gibt wie man das besser Lösen kann oder ob mein Ansatz vom code her der richtige ist.

Ich habe einen Kamera-Schwenkkopf mit Schritt Motorantrieb (Edit - Korrektur: es sind keine Schrittmotoren, sondern DC-Motoren mit Encoder) mit eingebautem Controller (das Ding heißt Merlin und ist eigentlich zur Nachführung von Fernrohren gedacht, aber es funktioniert mit Kameras bis etwa 2 kg auch sehr gut).

Jedenfalls: Dieses Ding lässt sich über eine serielle Schnittstelle (UART TTL) steuern (z.B. durch einen Arduino) und es hat auch nur einen einzigen Pin für RX/TX.
Die Pins RX und TX sind mit jeweils einem 220 Ohm Widerstand mit diesem einen Pin des Schwenkkopfs verbunden (und GND natürlich auch):
ArduinoMerlin_RXTX.png
Geliefert wird der Schwenkkopf eigentlich mit einer eigenen Steuerung. Diese habe ich aber durch einen Arduino ersetzt. Ich verwende es schon mehrere Jahre und es funktioniert ohne Probleme.

Es ist Halbduplex und der Controller des Schwenkkopfes ist auch durchaus "geschwätzig".
Das Protokoll haben nette Leute ins Netz gestellt.

Wie hilft dir das jetzt?
Ich wollte damit nur sagen, dass es bei manchen Geräte anscheinend durchaus üblich ist über die selbe Leitung sowohl zu senden als auch zu empfangen. Und das bei serieller Kommunikation (UART mit TTL-Pegel).

Interessant wäre dabei zu wissen, wie RX und TX im Merlin verbunden sind. Ohne Tristate oder offener Kollektor geht das wohl nicht.

uxomm:
Ich habe einen Kamera-Schwenkkopf mit Schrittmotorantrieb und eingebautem Controller (das Ding heißt Merlin und ist eigentlich zur Nachführung von Fernrohren gedacht, aber es funktioniert mit Kameras bis etwa 2 kg auch sehr gut).

Jedenfalls: Dieses Ding lässt sich über eine serielle Schnittstelle (UART TTL) steuern (z.B. durch einen Arduino) und es hat auch nur einen einzigen Pin für RX/TX.
Die Pins RX und TX sind mit jeweils einem 220 Ohm Widerstand mit diesem einen Pin des Schwenkkopfs verbunden (und GND natürlich auch):
ArduinoMerlin_RXTX.png
Geliefert wird der Schwenkkopf eigentlich mit einer eigenen Steuerung. Diese habe ich aber durch einen Arduino ersetzt. Ich verwende es schon mehrere Jahre und es funktioniert ohne Probleme.

Es ist Halbduplex und der Controller des Schwenkkopfes ist auch durchaus "geschwätzig".
Das Protokoll haben nette Leute ins Netz gestellt.

Wie hilft dir das jetzt?
Ich wollte damit nur sagen, dass es bei manchen Geräte anscheinend durchaus üblich ist über die selbe Leitung sowohl zu senden als auch zu empfangen. Und das bei serieller Kommunikation (UART mit TTL-Pegel).

Danke für die Info. Bei mir scheint das ganze aktuell auch ohne die Wiederstände zu funktionieren, aber ich werde noch versuchen ob es mit Wiederständen auch funktioniert. Wenn man einen Hardware Serial Port verwendet muss man einfach erst noch die gesendeten bytes auslesen da diese vom Arduino selber auch wieder empfangen werden. Danach kann erst die Antwort des Gerätes gelesen werden.

Mich würde interessieren wie du den Code in deinem Fall gebaut hast. Hast du auch einfach nach dem senden den TX pin auf INPUT gestellt um Daten empfangen zu können, die Antwort gelesen und danach den Serial port komplett neu initialisiert oder ist das bei dir nicht nötig?

Ich habe das mit SoftwareSerial realisiert (9600 Baud).
Da braucht man sich um "überhaupt nichts" zu kümmern. Denn wenn mit SoftwareSerial gerade gesendet wird, kann gleichzeitig nichts empfangen werden.
Dieses Verhalten wird gemeinhin als Nachteil angesehen, aber in diesem speziellen Fall ist das eindeutig von Vorteil, weil die "eigenen" Daten, die gesendet werden eben nicht auch empfangen werden.

Wie ich das mit Hardware Serial machen würde, sodass es bei mir funktioniert, das müsste ich mir erst überlegen und testen.
Wahrscheinlich würde ich unmittelbar nach dem Senden die entsprechende Anzahl an Bytes sofort wieder einlesen und "wegwerfen". Die Zeichen sollten sich ja im seriellen Buffer befinden. Aber das ist nur eine Idee, ich habe das nicht getestet. Hängt wohl auch davon ab wieviele Zeichen es sind (der Buffer ist nur 64 Bytes groß) und wie schnell das Gegenüber antwortet.
Wie du es beschreibst kommt mir das jedenfalls eher kompliziert vor. Aber wenn es bei dir zuverlässig funktioniert, gibt es keinen Grund daran etwas zu ändern.

Die Widerstände sind aus meiner Sicht schon aus "Sicherheitsgründen" wichtig.
Beim Gedanken, 2 Pins direkt (ohne Widerstand) zu verbinden, die eventuell beide Ausgänge sein könnten stellen sich mir die Nackhaare auf :slight_smile:
Gerade beim "Herumprobieren" kann es aus meiner Sicht durchaus passieren, dass dann mal einer HIGH und der andere LOW ist. Das tut dem Arduino nicht sehr gut :o
Aber vielleicht ist das auch nur meine Paranoia :slight_smile:

Es ist ein Nachteil wenn Kollissionen nicht erkannt werden, weil die empfangenen Bytes nicht mit den gesendeten verglichen werden können.

DrDiettrich:
Interessant wäre dabei zu wissen, wie RX und TX im Merlin verbunden sind. Ohne Tristate oder offener Kollektor geht das wohl nicht.

So etwas lässt mir ja keine Ruhe :slight_smile:
Hab also den Merlin zerlegt und mir das Controller-Board näher angeschaut:
Merlin_offen_kl.png

Merling_Platine_beschriftet_kl.png
Da ist ja einiges verbaut: Da werken, wie zu sehen, gleich 2 PIC16F886 und noch mehr ...
Die RX/TX-Leitung geht ganz direkt zu beiden PICs zu Pin 18, das ist RX (siehe Datenblatt).
Es gibt jeweils eine Diode (z.B. D3 - etwa Bildmitte) von Pin 17 (das ist TX) zu Pin 18 des PIC.
Und es gibt einen 10k Pullup bei Pin 18.
Schaltplan hab ich keinen und mehr zerlegen wollte ich auch nicht - ich möchte das Ding ja demnächst wieder verwenden :slight_smile:

Es sind übrigens keine Schrittmotoren, sondern DC-Motoren mit Encodern. Das ist auch ganz logisch, denn das Ding ist auf Batteriebetrieb ausgelegt und die Motoren sind stark untersetzt.

Wissen wir jetzt mehr? :slight_smile:

Na jedenfalls ist es schon recht off topic.

uxomm:
Ich habe das mit SoftwareSerial realisiert (9600 Baud).
Da braucht man sich um "überhaupt nichts" zu kümmern. Denn wenn mit SoftwareSerial gerade gesendet wird, kann gleichzeitig nichts empfangen werden.
Dieses Verhalten wird gemeinhin als Nachteil angesehen, aber in diesem speziellen Fall ist das eindeutig von Vorteil, weil die "eigenen" Daten, die gesendet werden eben nicht auch empfangen werden.

Wie ich das mit Hardware Serial machen würde, sodass es bei mir funktioniert, das müsste ich mir erst überlegen und testen.
Wahrscheinlich würde ich unmittelbar nach dem Senden die entsprechende Anzahl an Bytes sofort wieder einlesen und "wegwerfen". Die Zeichen sollten sich ja im seriellen Buffer befinden. Aber das ist nur eine Idee, ich habe das nicht getestet. Hängt wohl auch davon ab wieviele Zeichen es sind (der Buffer ist nur 64 Bytes groß) und wie schnell das Gegenüber antwortet.
Wie du es beschreibst kommt mir das jedenfalls eher kompliziert vor. Aber wenn es bei dir zuverlässig funktioniert, gibt es keinen Grund daran etwas zu ändern.

Die Widerstände sind aus meiner Sicht schon aus "Sicherheitsgründen" wichtig.
Beim Gedanken, 2 Pins direkt (ohne Widerstand) zu verbinden, die eventuell beide Ausgänge sein könnten stellen sich mir die Nackhaare auf :slight_smile:
Gerade beim "Herumprobieren" kann es aus meiner Sicht durchaus passieren, dass dann mal einer HIGH und der andere LOW ist. Das tut dem Arduino nicht sehr gut :o
Aber vielleicht ist das auch nur meine Paranoia :slight_smile:

Danke für die ausführlichen Infos. Ich habe das jetzt auch noch probiert mit zwei Wiederständen und habe zudem eine Diode beim TX Pin eingebaut. Damit kann ich jetzt Daten senden und empfangen ohne den PIN immer deaktivieren zu müssen. Das sollte jetzt hoffentlich eine saubere Lösung sein.

Danke nochmals für eure Hilfe!

Super, dass es dir geholfen hat und danke für die Rückmeldung!

uxomm:
Super, dass es dir geholfen hat und danke für die Rückmeldung!

Ich habe noch ein Update zu dem Thema. Ich habe einen Pull Request für den Teensy 3.2 gefunden der eine "Single Wire Serial" Funktion für den Hardware Serial Port implementiert:

Da werden einige Einstellungen seitens des Harware Chips gesetzt welche diese Funktion aktivieren. Der Pull Request wurde leider nie offiziell gemerged und kann aktuell auch nicht mehr automatisch gemerged werden. Darum habe ich den Code manuell in die aktuellste Version gemerged in meinem eigenen Fork:

Ich habe das schon ausprobiert und es scheint soweit zu funktionieren. Mit der Änderung muss nun nur noch der TX PIN und der GND verbunden werden. Ausserdem empfängt der Hardware Serial Port damit die selber gesendeten Bytes nicht mehr.

Ich habe jetzt allerdings noch ein zweites Gerät vom gleichen Hersteller wo bestimmte Bytes in der Antwort noch nicht richtig gelesen werden können. Ich werde das noch weiter analysieren müssen mit einem Oszillator. Eventuell melde ich mich nochmals falls ich noch Hilfe dabei brauche.

Edit: Ich denke ich konnte das Problem lösen. Das zweite Gerät scheint nicht so schnell zu sein beim empfangen der Bytes. Ich muss nach jedem gesendeten Byte ein flush() auf dem Serial Port auslösen, dann klappt es.

"Single Wire Serial" - interessant - so heißt das also.

Gibt es denn einen Unterschied zwischen "Single Wire" und "K-Line"?

Verwende aktuell immer einen L9637D, der aus einem K-Line Signal ein Serielles wandelt.
Im Echtbetrieb auch unabdingbar, da dieser auch die Spannung auf der Signalleitung senkt. Aber im Testaufbau sicherlich ne Alternative zu der "teuren", lieferengpässlichen SMD, die auch noch anständig verlötet werden möchte ::slight_smile:

TriB:
Gibt es denn einen Unterschied zwischen "Single Wire" und "K-Line"?

Verwende aktuell immer einen L9637D, der aus einem K-Line Signal ein Serielles wandelt.
Im Echtbetrieb auch unabdingbar, da dieser auch die Spannung auf der Signalleitung senkt. Aber im Testaufbau sicherlich ne Alternative zu der "teuren", lieferengpässlichen SMD, die auch noch anständig verlötet werden möchte ::slight_smile:

Ich kenne dieses K-Line System zwar nicht, aber laut der Beschreibung die ich gefunden habe verwendet die K-Line schon mal eine deutlich höhere Spannung. (12 bis 24 Volt) Meine Single Wire Leitung läuft nur mit 3 bis 5 Volt.

ich klinke mich mal kurz ein.
wenn man beim senden vorher den rx pin abfragt (high oder low je nach parität) und ob daten available sind und ggf. noch eine last_rx zeit, dann weiß man dass die leitung frei frei ist.
wenn man nun beim senden nach jeden byte das gesendete einliest und miteinander vergleicht, dann kann man so prüfen ob auch richtig gesendet wurde. bei misserfolg einfach wieder prüfen ob die leitung frei ist und erneut senden. natürlich mit nen counter, um kein endlos senden auszulösen.
Eindrahtleitung ist ungefähr z.B. LIN-Bus in Autos.

Nähere Infos zum Single-Wire-UART (SWART) siehe auch (letzter Absatz):