Pages: [1] 2   Go Down
Author Topic: Gerät per RS232 ansteuern  (Read 1954 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
God Member
*****
Karma: 11
Posts: 599
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hallo,

ich würde gerne ein Bedienteil für ein videotechnisches Gerät bauen. Das Bedienteil soll zwischen verschiedenen Eingängen umschalten und mir den entsprechenden aktiven Eingang am Bedienteil per LED anzeigen.

Mit dem Befehl "RTE 1" und "RTE 2" kann ich zum jetzigen Zeitpunkt bereits zwischen Eingang 1 und 2 umschalten.

Ich möchte aber nicht nur zwischen den verschiedenen Eingängen umschalten können, sondern möchte auch für den Fall, dass direkt am Gerät (also nicht über das geplante Bedienteil) der Eingang umgeschaltet wird dafür sorgen, dass mir am Bedienteil trotzdem der richtige aktive Eingang angezeigt wird.


Das senden des Befehls "RTE?" bewirkt folgende Rückmeldung:

"=3" (bei aktiviertem Eingang 3)

Man kann also abfragen, welcher Eingang momentan aktiv ist.


Leider sendet das Gerät nicht einfach von sich aus eine Meldung, wenn am Gerät umgeschaltet wird.


Nun zu meinem Problem:

Ich weiss beim besten Willen nicht, wie ich den Code aufbauen soll.

Theoretisch müsste ja kontinuierlich "RTE?" gesandt werden.

Ich bekomme die zeitliche Abfolge irgendwie nicht in meine Birne.

Wann frage ich was ab? Sende ich eine "RTE?"-Abfrage zusätzlich mit jedem Druck auf einen Taster am Bedienteil,.. steh echt im Wald. smiley-sad

Gruß Chris
« Last Edit: August 15, 2013, 01:06:24 pm by Chris72622 » Logged


Germany S-H
Offline Offline
Faraday Member
**
Karma: 172
Posts: 3252
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Leider sendet das Gerät nicht einfach von sich aus eine Meldung, wenn am Gerät umgeschaltet wird.

Nun zu meinem Problem:

Ich weiss beim besten Willen nicht, wie ich den Code aufbauen soll.

Theoretisch müsste ja kontinuierlich "RTE?" gesandt werden.

Ich bekomme die zeitliche Abfolge irgendwie nicht in meine Birne.

Wenn sich am Gerät auch keine Funktion aktivieren läßt, die die gesuchten Daten bei Änderung unaufgefordert sendet, mußt Du die Abfrage "pollen", also in zeitlichen Abständen immer wieder die Daten anfordern und die Rückantwort auswerten. Zwischen zwei Anfragen an das Gerät müßte mindestens so viel Zeit vergehen, dass die Zeit ausreicht, um die Daten zum Gerät zu senden, das Gerät die Anfrage verarbeitet und darauf reagiert und um die Daten vom Gerät zu empfangen.

Bei einem Gerät, das einige Zeichen über eine serielle Schnittstelle erhält und zurücksendet z.B. einmal pro Sekunde "RTE?" senden und die eintreffende Antwort auswerten.
Logged

Offline Offline
God Member
*****
Karma: 11
Posts: 599
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Ok.

Leider hab ich keine Ahnung, wie ich nach "=x" suchen soll.

Selbst dieser Thread hat es noch nicht geschafft meinen Knoten im Kopf zu lösen:

http://forum.arduino.cc/index.php?topic=142928.msg1075606#msg1075606

Hat mir vielleicht jmd. noch einen Tipp?

Gruß Chris

PS: So kann ich das "=" ja leider nicht mitberücksichtigen:

Code:
if(Serial3.available() > 0)
{
  incomingByte = Serial3.parseInt();
  if(incomingByte == '1')
  {
    digitalWrite(LED_1, HIGH);
    Serial.println("Eingang 1 geschaltet!");
  }
}
« Last Edit: August 18, 2013, 05:44:23 am by Chris72622 » Logged


Germany S-H
Offline Offline
Faraday Member
**
Karma: 172
Posts: 3252
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hat mir vielleicht jmd. noch einen Tipp?

Code:
void setup() {
  Serial.begin(9600);
}

void perRS232ansteuern()
{
  static unsigned long letzteSekunde;
  boolean gleichheitsZeichenGelesen=false;
  char c;
  if (millis()/1000==letzteSekunde) return; // nichts zu tun weil noch keine Sekunde vergangen
  letzteSekunde=millis()/1000;
  if (letzteSekunde%2==0) // in geraden Sekunden Befehl senden
  {
    Serial.println("RTE?");
  }
  else // in ungeraden Sekunden die Antworten auslesen
  {
    while (Serial.available())
    {
      c=Serial.read();
      Serial.write(c);
      if (gleichheitsZeichenGelesen) // das nächste Zeichen ist was wir suchen
      {
        Serial.println();
        if (c=='1') Serial.println("Eingang 1");
        else if (c=='2') Serial.println("Eingang 2");
        else if (c=='3') Serial.println("Eingang 3");
        else if (c=='4') Serial.println("Eingang 4");
      }
      else if (c=='=') gleichheitsZeichenGelesen=true;
    }
  }
}


void loop() {
  perRS232ansteuern();
}

Das ist jetzt nur mal ein Testcode für den "Seriellen Monitor" von Arduino, bei dem Du die simulierte Antwort selbst über die Eingabezeile eingeben kannst. Für die Ansteuerung eines seriellen Geräts anstelle des seriellen Monitors müßten folgende Änderungen vorgenommen werden.

Entweder Du schreibst diese Zeile:
Serial.println("RTE?");
und alle read() Anweisungen auf eine andere serielle Schnittstelle um, an der das externe Gerät angeschlossen ist.
Entweder eine zweite serielle Hardwareschnittstelle (hat z.B. ein MEGA) oder eine Software-Serial.

Oder Du löschst alle anderen print()-Ausgaben (außer der Zeile Serial.println("RTE?"); ) aus dem Programm heraus, damit sie das Kommando-Interface des angeschlossenen Geräts nicht irritieren. Und machst Kontrollausgaben z.B. auf einem angeschlossenen LCD-Display.
« Last Edit: August 18, 2013, 07:02:10 am by jurs » Logged

Offline Offline
God Member
*****
Karma: 11
Posts: 599
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hallo,

kann mir jmd. erklären, welche Funktion das return hier hat, bzw. ob ich es auch einfach weglassen könnte?

Code:
if (millis()/1000==letzteSekunde) return;
  letzteSekunde=millis()/1000;

Danke.

Gruß Chris
Logged


Germany
Offline Offline
Edison Member
*
Karma: 48
Posts: 2338
Arduino rocks
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Sogar auf deutsch: http://arduino.cc/de/Reference/Return

Die Funktion wird wenn die if-Bedingung erfüllt ist einfach abgebrochen, alles nachstehende wird nicht ausgeführt.
Ist diese Bedingung nicht erfüllt, geht es unmittelbar mit den nachfolgenden Codezeilen weiter.
Logged

Mein Arduino-Blog: http://www.sth77.de/ - letzte Einträge: Teensy 3.0 - Teensyduino unter Window 7 - Teensyduino unter Windows 8

Germany S-H
Offline Offline
Faraday Member
**
Karma: 172
Posts: 3252
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

kann mir jmd. erklären, welche Funktion das return hier hat, bzw. ob ich es auch einfach weglassen könnte?

Code:
  if (millis()/1000==letzteSekunde) return;
  letzteSekunde=millis()/1000;

"return" beendet eine Funktion vorzeitig und falls "return" ausgeführt wird, wird sämtlicher nachfolgender Code nicht mehr ausgeführt. Die Ausführung von "return" stellt also das Ende der Funktion dar.

Der Ausdruck "(millis()/1000" bildet ein Zähler, der alle 1000 Millisekunden um 1 hochzählt. Solange die Funktion immer wieder mit demselben Stand des Sekundenzählers ausgeführt wird wird die aufgerufene Funktion sofort wieder verlassen. Dadurch wird der nachfolgende Code der Funktion nur ein einziges mal pro Sekunde ausgeführt, egal wieviel zigtausendmal in einer Sekunde die Funktion aufgerufen wird.

In der nächsten Zeile wird dann mit "letzteSekunde=millis()/1000;" der aktuelle Stand des Sekundenzählers in einer statischen Variablen festgehalten, damit die Funktion weiß, welches die letzte Sekunde war, in der der Code ausgeführt wurde und in der der Code daher auf keinen Fall nochmals ausgeführt werden soll.

Läßt Du das "return" in der ersten Zeile weg oder sogar die ganze erste Zeile, dann wird der nachfolgende Code nicht mehr einmal pro Sekunde ausgeführt, sondern so oft, wie die Funktion aufgerufen wird. Also unter Umständen zigtausende male pro Sekunde.
Logged

Offline Offline
God Member
*****
Karma: 11
Posts: 599
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

(Erst) jetzt leuchtet mir ein, warum ich das Konstrukt nicht verstanden habe!!!!

Juhuuu- endlich hab ich es kapiert. smiley

Vielen, vielen Dank!!

Werd mir in den nächsten Wochen wohl mal die komplette Reference durchlesen.

Gruß Chris
Logged


Offline Offline
God Member
*****
Karma: 11
Posts: 599
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hallo,

da sich die Anforderungen geändert haben, muss ich mittlerweile nicht nur nach einer Zahl suchen, sondern nach einer Zeichenabfolge.

Um es mir so einfach wie möglich zu machen (sprich ohne Arrays, Zeigern usw.) dachte ich mir, ich löse das so:

Code:
void rueckmeldungen()
{
  if(Serial3.available() == 10)
  {
    if(Serial3.find("RTE 1\r\n\r\n#") == 1)
    {
      Serial.println("blabla");
    }
  }
}

Leider scheint es nicht zu funktionieren. Da ich nirgends im Netz ein Tutorial zu Serial.find finden kann, stecke ich mal wieder fest.

Vielleicht könnte sich ja nochmals jmd. erbarmen..  smiley-roll-sweat

Zum Einsatz kommt übrigens ein Arduino Mega.

Gruß Chris
Logged


Germany
Offline Offline
Faraday Member
**
Karma: 59
Posts: 3072
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Serial.find() sieht interessant aus, hab ich aber noch nie verwendet.

Quote
The function returns false, if it times out.
Wenn also z.B. "RTE1" statt "RTE 1" kommt, bleibt das Ganze erstmal im Serial.find() hängen, fürchte ich.
Wenn der Sender andauernd irgendwas sendet, hängt find() evtl. ewig.
Wie lang ist das Timeout ?

Tutorials zu "Arduino: Texte von Serial lesen und auswerten" benutzen nicht die Funktion find(),
sondern werten entweder jedes Zeichen direkt aus oder lesen die erwartete Anzahl Zeichen und machen dann strcmp oder so

Quote
Um es mir so einfach wie möglich zu machen (sprich ohne Arrays, Zeigern usw.)...
Es ist wohl auf Dauer einfacher mit "Arrays, Zeigern usw. ". Nur Mut, dabei können wir helfen.
Logged

Offline Offline
God Member
*****
Karma: 11
Posts: 599
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

So- jetzt hab ich es endlich!

Konnte einen Codefetzen aus diesem Thread.. http://forum.arduino.cc/index.php/topic,137669.0.html ..auf meine Anforderungen hin umbauen.

Serial.find() konnte ich nicht verwenden, da es mir alles ausgebremst hat.

Das Ganze sieht nun (ohne den restlichen Code) so aus:

Code:
char commandbuffer[7];
char c;
int i=0;

void setup()
{
  Serial.begin(9600);                                    
  Serial3.begin(19200);
  Serial3.setTimeout(0);
}

void loop()
{
  
//  <- An dieser Stelle steht mein kompletter restlicher Code, der auch noch verarbeitet werden muss.
  
  if (Serial3.available())
  {
    c=Serial3.read();
    commandbuffer[i] = c;
    i++;
  }
  if (strcmp(commandbuffer,"Libelle")==0)
  {
    Serial.println("Libelle gefunden");
    i = 0;
    memset(commandbuffer,0,sizeof(commandbuffer));
  }
}

Der Vorteil ist, dass ich nach der Aufnahme des ersten Zeichens nicht abwarte (und Zeit verliere), bis das nächste Zeichen eintrifft, sondern einfach mit dem Code weitermache.

Mein Problem ist nun jedoch, dass mir beim Eintreffen falscher Zeichen das commandbuffer-Array mit Müll vollgeschrieben wird und es keine sinnvollen Befehle mehr aufnehmen kann.

Wie könnte ich das umgehen, ohne das aktuell eingehende Zeichen nur darauf hin zu kontollieren, ob es ein L ist. Würd ich das machen, hätte ich ja spätestens dann ein Problem, wenn die Zeichenabfolge "Libellle" reinkommen würde.

Gruß Chris
« Last Edit: August 21, 2013, 09:31:26 am by Chris72622 » Logged


Germany
Offline Offline
Faraday Member
**
Karma: 59
Posts: 3072
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Mehrere Möglichkeiten:
a) es gibt ein Endezeichen ( z.B. '\n' ) : dann wird auch der Puffer gelöscht und neu angefangen
b) Du prüfst gleich jedes Zeichen auf den passenden Partner im Vergleichsstring
Dann erkennst du auch z.B. "xLibyzLibelle"

Code:
const char comparevalue[]="Libelle";
if (Serial3.available())
{
    c=Serial3.read();
    commandbuffer[i] = c;
    if (commandbuffer[i] == comparevalue[i])
    {
        i++;
        if (i == sizeof(comparevalue))
        {  
            //OK
             Serial.println("Libelle gefunden");
              i = 0;
              memset(commandbuffer,0,sizeof(commandbuffer));
        }
   }
   else
   {
         // BAD
          Serial.print(commandbuffer); Serial.println ("  ist falsch");
          i = 0;
          memset(commandbuffer,0,sizeof(commandbuffer));
   }
}

im Beispiel "xLibyzLibelle" erhältst du
x ist falsch
Liby ist falsch
z ist falsch
Libelle gefunden


aber damit LibLibelle funktioniert, musst du noch ein bisschen feilen, denn so gibts
LibL ist falsch
i ist falsch
b ist falsch
e ist falsch
...



Aber du willst sicher gar nicht so was, sondern lieber mit festen (Zeilen-)Anfängen arbeiten.

edit: besser, aber immer noch ungetestet; die Idee sollte aber klar sein smiley-wink
« Last Edit: August 21, 2013, 10:31:36 am by michael_x » Logged

Offline Offline
God Member
*****
Karma: 11
Posts: 599
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Siehst Du- das Problem ist rel. schnell beschrieben, eine Lösung (für mich bis dato) nicht in Sicht.

Insbesondere dann, wenn auf verschiedenste Tiernamen (um bei dem Libellenbeispiel zu bleiben) reagiert werden soll, wird weder a) noch b) wirklich funktionieren.

Trotzdem vielen Dank für Deine Mühen!

Gruß Chris
Logged


Germany
Offline Offline
Faraday Member
**
Karma: 59
Posts: 3072
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

a) ( Text von Anfang bis Zeilenende mit einer Liste von Texten vergleichen, und die Elementnummer der Vergleichstabelle, oder -1 falls nicht gefunden, liefern ) ist einfach.
Noch einfacher wäre es, wenn es nicht um Tiernamen, sondern um Kommandos mit fester Länge geht.
Etwas mühsamer wird es, wenn die konstante Vergleichsliste nicht im RAM, sondern aus Optimierungsgründen im FLASH liegen soll...

Vielleicht erbarmt sich jurs und liefert eine Musterlösung smiley-wink

Logged

Germany S-H
Offline Offline
Faraday Member
**
Karma: 172
Posts: 3252
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

So- jetzt hab ich es endlich!
...
Mein Problem ist nun jedoch, dass mir beim Eintreffen falscher Zeichen das commandbuffer-Array mit Müll vollgeschrieben wird und es keine sinnvollen Befehle mehr aufnehmen kann.

Wie denn nun: "Du hast es endlich" oder "Du hast ein Problem".

Oder "Du hast endlich ein Problem"?  smiley-mr-green

Wenn Du empfangene Zeichen auswerten möchtest, dann müßtest Du das genaue serielle Protokoll kennen, mit dem gesendet wird.

Insbesondere kannst Du nicht endlos immer einen Befehl empfangen, sondern es muß irgendeine Abbruchbedingung geben;
a) entweder ein abschließendes Zeichen, z.B. Zeilenende-Zeichen als Zeichen dafür, dass eine Befehlszeile zuende ist oder
b) eine Timeout-Zeit, nach der man einen ggf. unvollständig oder falsch empfangenen Befehl abbricht und einen neuen Lesevorgang beginnt

Ohne das genaue serielle Protokoll zu kennen, nach dem empfangen (und ggf. auch gesendet) werden soll, mit allen verschiedenen Befehlen, Befehlstypen, Sendeschemas und Optionen, kannst Du auch sinnvollerweise keine Ausleseroutine programmieren.

Weiter oben las es sich so, als wenn Du immer nur "RTE?" senden und als Antwort "=1" oder "=2" empfangen wolltest. Heute schreibst Du, dass sich die Anforderungen geändert haben. Aber wie hat es sich geändert? Was soll gesendet, was empfangen werden, und nach welchem Sendeschema?
Logged

Pages: [1] 2   Go Up
Jump to: