RS485 - Auslesen eines Laserabstandssensor

Hallo Zusammen,

ich habe einen Laser-Abstandssensor mit einer Genauigkeit von 0,5mm (Bereich 250mm-750mm (Sensopart FT 80 RLA-S1L8)
Dieser wird zwischenzeitlich über einen PC ausgelesen, der PC soll aber weg kommen.

Da nur das Abstandssignal benötigt wird langt auch ein einfaches "2x16 Zeichen LCD-Display" zum anzeigen, das auslesen des Sensors über das Analog-Signal (4-20mA) mit hilfe eines 250-Ohm Widerstands+Arduino UNO funktioniert.
(Arduino Analogeingang 0-5V, deswegen 250-OHM)

->Problem: der AD-Wandler vom Arduino UNO hat nur eine Auflösung von 10Bit (1024 Steps),
d.h. beim Messbereich von 500mm hätte ich nur eine Schrittbreite von 500 / 819 = 0,61.
Außerdem ist das Ergebnis beim Auslesen per Analogsignal nicht immer gleich.

Deswegen ist mein Plan das RS485 Signal per Arduino auszulesen, aber leider bin ich im Bereich RS485 + Arduino blutiger Anfänger deswegen hoffte ich hier auf Hilfe.

Die wichtigen Seiten des Handbuchs sind S.23/24 + 36 (siehe Anhang oder (Link) )
Es sind bereits fertige Befehle + Beispieltelegramme für die RS485 Schnittstelle gegeben.(Befehl: "Abstandsmesswert" siehe 8.5.18 (S.36) im PDF)
Das folgenden MAX485 Board habe ich auch bereits hier: Link

Meine Frage: Kann mir bitte jemand erklären wie ich über Arduino+RS485 den Befehl zum Sensor schicken kann und dann die Antwort so bearbeite das ich nur den Abstand als Wert in einer Variable zum weiterbearbeiten habe.

Parameter RS485 sensopart FT80RLA.pdf (158 KB)

RS-485 ist ein Standard für die physische Übertragung von seriellen Daten. Er wird meist in der half-duplex-Variante eingesetzt, d.h. für beide Richtungen (Senden und Empfangen) wird der gleiche Kanal eingesetzt. Die Daten werden auf einem Leitungspaar als Spannungsdifferenz übertragen. Dies macht die Übertragung praktisch immun gegen Störeinstrahlung von benachbarten Leitungen.
Das Half-Duplex-Verfahren setzt voraus, dass immer geregelt ist, wer gerade den Kanal zur Übertragung nutzen darf, weshalb meist Master-Slave-Protokolle darauf zur Anwendung kommen. D.h. einer hat das Sagen, die anderen reagieren nur auf dessen Befehle. Dein Messgerät ist nun so ein Slave, somit kannst Du ihm Befehle schicken und es wird Antworten zurückschicken. Wie genau die aufgebaut sind, erklärt das Handbuch. Da mehrere Gerät an einem Bus hängen können, werden sie adressiert, damit jedes weiss, ob es gerade angesprochen wird. Da Du nur eines anschliessen willst, ist die Adresse in Deinem Fall weniger wichtig, richtig übertragen muss sie aber trotzdem werden.
Ich rate dringend, nicht die häufig in Beispielen verwendeten SoftwareSerial-Code-Varianten zu nehmen, sondern die RS-485-Schnittstelle über die (eine) Hardware-Serielle-Schnittstelle des Arduinos zu führen. Da Du keinen PC angeschlossen hast und die Daten auf ein LCD-Display ausgibst, sollte das auch auf einem UNO keine Probleme bereiten.
Die Bus-Treiber (MAX485) haben ein bzw. zwei Leitungen, die bestimmen, ob gesendet oder empfangen wird. Die zwei Leitungen können zusammengehängt werden, da sie komplementär verschaltet sind, also in einem Fall bei Masse aktiv sind, im anderen bei Vcc.
Wenn Du also Daten verschickst, setzt Du den Steuerpin auf HIGH, sendest die Daten mit Serial.print() (oder ähnlichem) und wartest dann mit Serial.flush() darauf, dass sie wirklich vollständig übertragen wurden. Dann wird der Steuerpin auf LOW gesetzt, damit die Antwort empfangen werden kann.

Ich hoffe, das genügt für einen ersten Einstieg in die RS-485-Welt.

Für den RS485 Part habe ich ins blaue hinein was geschrieben. In

 Antwort.Daten1 = Serial.read();
 Antwort.Daten2 = Serial.read();

stehen jetzt deine Roh Daten drin die noch zusammenpacken in ein int und dann kannst du es auf dem Display ausgeben.

#define RXTXPin 3

boolean RCV_ready = LOW;
boolean SND_ready = HIGH;

struct {
  byte Adresse;
  byte Laenge;
  byte Antwort;
  byte Daten1;
  byte Daten2;
  byte Pruefsumme;
} Antwort;


void setup() {
  pinMode (RXTXPin, OUTPUT);
  Serial.begin(38400);
}

void loop() {
  if (SND_ready == HIGH) {
    sendRequest();
  }
  if (Serial.available() > 0) {
    Antwort.Adresse = Serial.read();  // Daten empfangen
    Antwort.Laenge = Serial.read();
    Antwort.Antwort = Serial.read();
    Antwort.Daten1 = Serial.read();
    Antwort.Daten2 = Serial.read();
    Antwort.Pruefsumme = Serial.read();
    SND_ready = HIGH;
  }
}



void sendRequest() {
  digitalWrite(RXTXPin, HIGH); // Senden aktivieren
  Serial.print(81, HEX);  // 1 Byte aus Doku
  Serial.print(04, HEX);  // 2 Byte aus Doku
  Serial.print(41, HEX);
  Serial.print(44, HEX);
  Serial.flush();          // Waten bis alles raus ist
  digitalWrite(RXTXPin, LOW); // Empfang aktivieren
  SND_ready = LOW;
 }

Beispiele für LCD Sketche gibt es zuhauf im Internet. Ein bisschen einarbeiten und testen dann sollte es schon klappen. Hier wird geholfen aber selten auf "Bestellung" gearbeitet.
Grundprinzip es bei RSS485 muss man zwischen Senden und empfangen umschalten also zum Senden HIGH an !RE/DE ein LOW an diesen schaltet auf "Empfang".
Bei deinem Sensor muss man auf keine Block zwischen Senden der Anfrage und Empfang der Daten habe da er Sensor ziemlich zackig Antwortet

Der Sensor beginnt mit dem Antworttelegramm innerhalb 400 bis 800 μs nach Empfang des Befehltelegramms.ch

Gruß
DerDani

Danke für die schnelle Hilfe,

habe den Code etwas geändert und bereits getestet, das Auslesen funktioniert einwandfrei!

Nun ist das letzte Problem das umwandeln der beiden Daten Bytes in ein 12bit-Datenwort...
Dazu müssen die jeweils ersten 6 bits der beiden Datenbytes zusammengeknüpft werden.

Ich habe es bis jetzt mit folgenden Code versucht(Beispielzahlen):

byte Daten1 = 0b11111111;
byte Daten2 = 0b00000000;

unsigned int Data;

Data = Daten1;
Data = (Data<<6) | Daten2;   //Ergebnis ist 0b11111111000000

Das Ergbnis ist fast richtig, die beiden bits von Daten2 werden überschrieben durch das bitshift, aber mir fällt nichts ein wie ich die letzten beiden Bits vom Daten1 nullsetzten/löschen könnte.

Hättet ihr eine Idee?

Probier mal

Data = Daten1 >> 2; // Die unteren 2 Bits von Daten1 raus schieben

Ich hoffe, ich habe Dich richtig verstanden. Deine Testdaten sind nicht ideal.

Gruß Tommy

Dazu müssen die jeweils ersten 6 bits der beiden Datenbytes zusammengeknüpft werden.

Verstehe ich das richtig, die 6 höchstwertigen Bits sollen verwendet werden? Das gibt's zwar auch, aber viel häufiger werden die sechs tiefstwertigen Bits gebraucht.

Dann wäre Dein Code:

uint16_t Data = Daten1 & 0x3F;
Data = (Data << 6) | (Daten2 & 0x3F);

Habe die Frage schlecht formuliert.

Sollte heißen: wie kann ich die 2 höchstwertigen Bits nullen/entfernen damit ich nur die 6 tiefwertigsten zur Verwendung habe und dann mit den 6 anderen verknüpfen kann

Dann wäre Dein Code:

[NICHT  UND    ODER  SHIFT] in der passenden Anordnung und Reihenfolge

Im Zweifelsfall die Rechnung und Zwischenschritte in HEX oder BIN anzeigen lassen.

Dass0x3F eine Maske für die niederwertigen 6 Bits eines Werts ist, sollte klar sein, oder?

wie kann ich die 2 höchstwertigen Bits nullen/entfernen damit ich nur die 6 tiefwertigsten zur Verwendung habe und dann mit den 6 anderen verknüpfen kann

Das ist genau, was mein Code im letzten Post macht.