Serielle Kommunikation mit Ofen scheitert (RS232)

Hallo zusammen :slight_smile:
Mein Vorhaben: Mit einem Arduino UNO und einem RS232 Serial Converter (noname; sowas hier ) von einem Heratherm Ofen ├╝ber dessen serielle Schnittstelle seine aktuelle Temperatur auslesen.

Leider klappt das nicht, ich komme nicht weiter und hoffe hier etwas Unterst├╝tzung zu bekommen :slight_smile:

Der Ofen erwartet eine bestimmte Zeichenfolge, worauf er dann mit einer anderen Zeichenfolge antwortet (die dann die aktuelle Temperatur beinhaltet). Wenn ich das Ganze mit dem PC versuche, also per Python oder sogar mit dem Arduino Serial Monitor funktioniert alles reibungslos. Nur wenn der Arduino versucht mit dem Ofen zu kommunizieren klappt es gar nicht.
Arduino (inkl. RS232 Modul) oder RS232-Kabel k├Ânnen nicht das Problem sein, die habe ich bereits ausgiebig getestet.

Hier mein aktueller Sketch:

#include <SoftwareSerial.h> //fuer rs232 modul
SoftwareSerial RS232Out(10, 11); // RX, TX

const byte numChars = 50; //max Zeichenanzahl erwartet
char receivedChars[numChars];
boolean newData = false;

char messageout[] = "?:3010:00::c2"; //das erwartet der Ofen

void setup() {
    Serial.begin(57600);
    RS232Out.begin(57600);
    Serial.println("<Arduino is ready>");
}

void loop() {
    sendQuestion();
    recvWithStartEndMarkers();
    showNewData();
    delay(500); //f├╝r weniger Hektik
}

void sendQuestion() {
  RS232Out.print(messageout); 
  RS232Out.write(13);   //13: CR bzw \r  10: LF bzw \n
  //RS232Out.print("\r"); //ging auch nicht
  //RS232Out.write("?:3010:00::c2\r"); //ging auch nicht
}

void recvWithStartEndMarkers() {
    static boolean recvInProgress = false;
    static byte ndx = 0;
    char startMarker = '!';
    char endMarker = '\r';
    char rc;
 
    while (RS232Out.available() > 0 && newData == false) { 
        rc = RS232Out.read(); //Zeichenweise einlesen

        if (recvInProgress == true) {
            if (rc != endMarker) { //nur bis Endmarker einlesen
                receivedChars[ndx] = rc;
                ndx++;
                if (ndx >= numChars) {
                    ndx = numChars - 1; 
                }
            }
            else {
                //receivedChars[ndx] = '\0'; // String terminieren
                recvInProgress = false;
                ndx = 0; //Z├Ąhlen beginnt von vorne
                newData = true;
            }
        }

        else if (rc == startMarker) {
            recvInProgress = true;
            receivedChars[ndx] = rc; //Startmarker auch hinzuf├╝gen
            ndx++;                  //hochz├Ąhlen
        }
    }
}

void showNewData() {
    if (newData == true) { //NeueDaten ja? dann:
        Serial.print("Empfangene Daten:  "); //Daten ausgeben
        Serial.println(receivedChars); //ueber SerialMonitor an PC
        }
        newData = false;
    }
}

Meine Vermutung ist, dass es am Wagenr├╝cklauf liegt, denn wenn die Anfrage an den Ofen nicht als letztes Zeichen ein \r (carriage return, Wagenr├╝cklauf) enth├Ąlt, dann ignoriert er die Anfrage g├Ąnzlich, was bei mir scheinbar der Fall ist.
N├Ąhere Infos zum Ofen findet man hier: https://static.thermoscientific.com/images/D21462~.pdf (Relevante RS232 Infos sind in Abschnitt 5-11 zu finden!)

Vielen Dank schonmal :sunglasses:

EDIT: die L├Âsung(!): Tauschen von Tx und Rx beim RS232-Kabel (Pin 2 und 3; obwohl man das laut Anleitung eben nicht tun sollte)

Rein von der Idee her w├╝rde ich das anders angehen.

Aus der hohlen Hand und ungetestet - kommt die Ausgabe auf dem SerMon, die ich erzwinge?

void recvWithStartEndMarkers()
{
  static boolean recvInProgress = false;
  static byte ndx = 0;
  char startMarker = '!';
  char endMarker = '\r';
  char rc;
  while (RS232Out.available() > 0)
  {
    rc = RS232Out.read();
    if (!recvInProgress)              // Pr├╝fen auf false
    {
      // ... wenn ja ...
      if (rc == startMarker)          // ... ist StartZeichen?
      {
        recvInProgress = true;
        receivedChars[ndx] = rc;
        ndx++;
      }
    }
    else                             // ... wenn nein ...
    {
      if (isControl(rc))             // ... ist Steuerzeichen?
      {
        Serial.println(F("Ende erkannt!"));
        Serial.println(receivedChars);
        recvInProgress = false;      // -> dann ist schluss
        ndx = 0; //Z├Ąhlen beginnt von vorne
        newData = true;
      }
      else                           // ... kein Steuerzeichen?
      {
        receivedChars[ndx] = rc;     // dann Puffer vollschreiben
        ndx++;
      }
    }
    if (ndx >= numChars)             // Laengenpr├╝fung
    {
      ndx = numChars - 1;
    }
  }
}

PS: Nachtrag...

  RS232Out.print(messageout); 

Warum machst Du nicht println

Hallo,
ich h├Ątte mal 3 Vorschl├Ąge.

  1. bau mal ein delay zwischen senden und empfangen ein.
  2. schau Dir auf dem PC hex an was der Arduino sendet ( vergleich mit dem Datenblatt ). Das kannst Du auch erst mal mit der normalen Serial und dem Monitor in der IDE machen.
  3. Vertausche mal irgendwo RX und TX je nach Kabel k├Ânnte das ja einmal zu viel gedreht sein.
    Heinz

Ich vermute das Problem hier drin:

sendQuestion()

offensichtlich scheint aber nichts falsch daran zu sein.

Also erstmal danke f├╝r das schnelle Feedback my_xy_projekt.

Aus der hohlen Hand und ungetestet - kommt die Ausgabe auf dem SerMon, die ich erzwinge?

Danke, der Code gef├Ąllt mir besser. Direkt getestet, ├Ąndern tut sich dadurch leider nichts. Der Ofen ignoriert die Anfrage.

Warum machst Du nicht println

Nunja der Ofen erwartet als letztes Zeichen der Anfrage eben ein CR und kein NL - habs trotzdem mal getestet :relieved: bringt leider auch nichts

Die n├Ąchsten Vorschl├Ąge wurden nat├╝rlich auch direkt getestet. Leider ohne Erfolg @Rentner

  1. Das delay zwischen 'send' und 'recv' habe ich von 20 bis 2000 ms getestet.
  2. Rx und Tx m├╝ssen richtig sein, denn genau mit diesem Aufbau kann ich auch problemlos mit diversen PCs (zwei getestet) kommunizieren

(zu 2. und 3.) au├čerdem habe ich auch ein Pythonskript f├╝r den PC das mir quasi den Ofen simuliert, damit klappt es auch problemlos. Daraus folgere ich, dass mindestens die Verkablung stimmen muss. Python jedoch verzeiht mir evtl Fehler die mir der Ofen nicht verzeiht....nur welche!? :thinking:

schau Dir auf dem PC hex an was der Arduino sendet

Ja also wenn ich mir das als Text ansehe, dann stimmt es perfekt mit dem ├╝berein was ich erwarte. Habe schon ├╝berlegt ob die Zeichen dann zwar richtig aussehen, aber der Ofen doch eine andere Codierung erwartet....├Ąhm hier endet mein Fachwissen :upside_down_face:

kann
SoftwareSerial.h
so schnelle Baudraten?

Teste es mal mit einem MEGA oder Leonardo mit Hardwareschnittstelle.

Gr├╝├če Uwe

kann SoftwareSerial.h so schnelle Baudraten?

w├Ąre komisch wenn nicht, immerhin kann ich per PC (Python, Arduino SerMon, Linux-Terminal) problemlos mit dem Teil "sprechen", mit genau dieser Baudrate.

Teste es mal mit einem MEGA oder Leonardo mit Hardwareschnittstelle.

Danke f├╝r die Idee, leider ist mir nicht ganz klar wie du das meinst. Wenn ich statt dem UNO den MEGA nehme wo ist der Unterschied?

Das println macht \r\n.
Der Ofen erwartet als Abschlu├č ein \r und springt erst wieder drauf an, wenn er ein ?: bekommt.
Alles was dazwischen ist, ignoriert er geflissentlich.
So wie ich auch :wink:

Was heisst der Ofen reagiert nicht.
In der Tabelle 5.1 sehe ich nur, das er selbst auf eine Anfarge antworten kann, aber mehr auch nicht.
Oder gibt es noch mehr Codes, die z.B. Einstellungen vornehmen, die man dann am Ofen selbst kontrollieren kann?

Dann muss man logisch ran gehen.
Kurzsketch:
Bitte beachten: Serieller Monitor vom Arduino auf 115200 stellen.
Zwischen senden und empfangen hab ich eine Pause von 200ms drin. Da die Antwort recht kurz ist, sollte das passen. ggfls. k├╝rzer machen in 20ms Schritten.
Gibts ne Reaktion?
Wenn nicht, nochmal Kabel pr├╝fen vom Arduino zum Modul.

#include <SoftwareSerial.h> //fuer rs232 modul
SoftwareSerial RS232Out(10, 11); // RX, TX

const byte numChars = 50; //max Zeichenanzahl erwartet
char receivedChars[numChars];

char messageout[] = "?:3010:00::c2"; //das erwartet der Ofen

void setup()
{
  Serial.begin(115200);
  RS232Out.begin(57600);
  Serial.println("<Arduino is ready>");
}

void loop()
{
  sendMessage();
  delay(100);
  receiveMessage();
}

void sendMessage()
{
  Serial.print(F("Starte Senden: "));
  for (uint8_t i = 0; i < (sizeof(messageout) - 1); i++)
  {
    RS232Out.print(messageout[i]);
    Serial.print(messageout[i]);
  }
  RS232Out.println();
  Serial.println();
}

void receiveMessage()
{
  const unsigned long abbruchzeit = 5000;
  unsigned long lastmillis = millis();
  Serial.println(F("Starte Empfang:"));
  while (RS232Out.available() > 0)
  {
    if ( millis() - lastmillis < abbruchzeit)
    {
      char c = RS232Out.read();
      if (!isControl(c)) // Kein Steuerzeichen
      {
        Serial.print(c);
      }
      else               // Steuerzeichen
      {
        Serial.print(c, HEX);
        return (-1);
      }
    }
    else
    {
      Serial.println(F("Zeit├╝berschreitung!"));
      return (-1);
    }
  }
}

[edit: dem return noch einen Parameter mitgegeben sonst meckerts]

Der Mega hat 4 Serielle Hardwareschnittstellen, 3 davon ungenutzt.

Gr├╝├če Uwe

ach wie sch├Ân man lernt auch neue Vokabeln hier :nerd_face:

Was dein Kurzsketch angeht, so sch├Ân er auch sein mag - da tut sich nichts.
Kabel gepr├╝ft alles OK (btw: tausch von Tx u. Rx f├╝hrt zum Totalausfall @Rentner ; auch direkt nochmal gepr├╝ft: ja der Ofen reagiert immernoch genau so wie er soll wenn ich ihn per Arduino SerMon anspreche)

Wenn ich nun statt des Ofens ans andere Ende der Leitung ein Pythonskript h├Ąnge, dann empf├Ąngt es folgendes (von deinem Kurzsketch!):

Raw: 
b'\n?:3010:00::c2\r'
UTF-8 decoded: 

?:3010:00::c2

Raw: 
b'\n?:3010:00::c2\r'
UTF-8 decoded: 

?:3010:00::c2

habe spa├česhalber in deinem Sketch mal das println durch ein write(13) ersetzt, dann emfp├Ąngt Python das hier:

Raw: 
b'?:3010:00::c2\r'
UTF-8 decoded: 
?:3010:00::c2

....sieht in beiden F├Ąllen richtig aus oder....!?
Den Ofen interessiert das aber (geflissentlich :sunglasses:) nicht .... ich wei├č echt nicht weiter :pensive:

Ab einer (unbestimmten) Menge aufgenommener Informationen kann einiges auch abgek├╝rzt wiedergegeben werden :slight_smile:

Also der Kurzsketch macht in jedem Fall, was er soll.
Die Ausgabe stimmt auch mit der Aufgabenstellung.

Dann mal das ganze noch erweitert.
Was passiert:
Ich sende einmal.
Dann frage ich 5 Sekunden lang den Empfang ab.
Ohne jegliche Pause.

#include <SoftwareSerial.h> //fuer rs232 modul
SoftwareSerial RS232Out(10, 11); // RX, TX

const byte numChars = 50; //max Zeichenanzahl erwartet
char receivedChars[numChars];
char messageout[] = "?:3010:00::c2"; //das erwartet der Ofen

bool sending = false;

void setup()
{
  Serial.begin(115200);
  RS232Out.begin(57600);
  Serial.println("<Arduino is ready>");
}

void loop()
{
  sendMessage();
  receiveMessage();
}

void sendMessage()
{
  if (!sending)
  {
    messageout[sizeof(messageout)] = '\r';
    Serial.print(F("Starte Senden: "));
    RS232Out.write(messageout, (sizeof(messageout)));
    Serial.write(messageout, (sizeof(messageout)));
    Serial.println();
    sending = true;
  }
}

void receiveMessage()
{
  const unsigned long abbruchzeit = 5000;
  static unsigned long lastmillis = millis();
  static bool empfang = false;
  if ( millis() - lastmillis < abbruchzeit)
  {
    if (Serial.available() > 0)
    {
      Serial.println(F("Starte Empfang:"));
      char c = RS232Out.read();
      if (!isControl(c)) // Kein Steuerzeichen
      {
        Serial.print(c);
      }
      else               // Steuerzeichen
      {
        Serial.print(c, HEX);
        return (-1);
      }
    }
  }
  else
  {
    Serial.println(F("Zeit├╝berschreitung!"));
    lastmillis = millis();
    sending = false;
    empfang = false;
    return (-1);
  }
}

Den Code ├╝berarbeitet - wegen der Laufzeit.

also wenn ich dich jetzt richtig verstanden habe soll das Modul mit dem MEGA sprechen....und ich die Hardware richtig verstehe: Alles nach dem TTL RS232 Converter l├Ąuft auf 12V, dann w├╝rde ich damit doch meinen MEGA braten...

ich w├╝rde es eh gerne dabei belassen, denn die Kommunikation scheint ja mit anderen Ger├Ąten und gleicher Baudrate zu klappen, dann m├╝sste ich das jetzt nicht nochmal testen - irgendwelche Einw├Ąnde?

Weiter gehts @my_xy_projekt
Dein Kurzsketch aus Posting #8 rauscht einfach so durch, daraus folgere ich das Modul scheint niemals 'ready', die while Schleife

while (RS232Out.available() > 0)

startet nie. Oder:

      else               // Steuerzeichen
      {
        Serial.print(c, HEX);
        return (-1);
      }

es kommen nur Steuerzeichen raus.

Jetzt teste ich gleich mal Posting #11

Ich hab den nochmal nacheditiert. Dann gehts auch mit nem Halt :wink:

Ja.
der HardwareSerial TX1/TX2 vom MEGA an das Modul - und dann ganz normal weiter.
Frage: Hast Du einen zur Verf├╝gung?

Du sollst einen Leonardo oder Mega verwenden da diese eine freie Hardwareserielle Schnittstelle besitzen an die Du den RS232 Wandler anschlie├čt. Dadurch mu├čt Du die Schnittstelle nicht via Software emulieren.

Gr├╝├če Uwe

Ich hab den nochmal nacheditiert. Dann gehts auch mit nem Halt

ja hatte ich ber├╝cksichtigt, mit durchrauschen meinte ich der SerMon gibt das hier aus:

Starte Senden: ?:3010:00::c2
Starte Empfang:
Starte Senden: ?:3010:00::c2
usw usw usw usw.....

wichtiger: Sketch aus Posting #11 produziert nur "Zeit├╝berschreitung!" in regelm├Ą├čigen Abst├Ąnden.

├ähhh ja wie es der Zufall so will hab ich hier tats├Ąchlich einen MEGA 'rumliegen' :sunglasses:

Ok aber diese Vorgehensweise ist mir neu....also einfach Rx,Tx vom Mega an Tx,Rx vom RS232 Modul anschlie├čen und dann...

Ja, weil er nichts empf├Ąngt.
Hm...
Hinweis: Mach mal bitte im SerMon den Zeitstempel mit an. Dann sehe ich ggfls. auch Logikfehler wenn die Zeiten nicht passen.

Am MEGA dann nicht 10/11 sondern TX1/RX1 benutzen und umschreiben:

const byte numChars = 50; //max Zeichenanzahl erwartet
char receivedChars[numChars];
char messageout[] = "?:3010:00::c2"; //das erwartet der Ofen

bool sending = false;

void setup()
{
  Serial.begin(115200);
  Serial1.begin(57600);
  Serial.println("<Arduino is ready>");
}

void loop()
{
  sendMessage();
  receiveMessage();
}

void sendMessage()
{
  if (!sending)
  {
    messageout[sizeof(messageout)] = '\r';
    Serial.print(F("Starte Senden: "));
    Serial1.write(messageout, (sizeof(messageout)));
    Serial.write(messageout, (sizeof(messageout)));
    Serial.println();
    sending = true;
  }
}

void receiveMessage()
{
  const unsigned long abbruchzeit = 5000;
  static unsigned long lastmillis = millis();
  static bool empfang = false;
  if ( millis() - lastmillis < abbruchzeit)
  {
    if (Serial.available() > 0)
    {
      Serial.println(F("Starte Empfang:"));
      char c = Serial1.read();
      if (!isControl(c)) // Kein Steuerzeichen
      {
        Serial.print(c);
      }
      else               // Steuerzeichen
      {
        Serial.print(c, HEX);
        return (-1);
      }
    }
  }
  else
  {
    Serial.println(F("Zeit├╝berschreitung!"));
    lastmillis = millis();
    sending = false;
    empfang = false;
    return (-1);
  }
}

na klar!
das kommt heraus dabei:

18:05:15.601 -> 	<Arduino is ready>
18:05:17.241 -> Starte Senden: ?:3010:00::c2
18:05:22.241 -> Zeit├╝berschreitung!
18:05:22.241 -> Starte Senden: ?:3010:00::c2
18:05:27.241 -> Zeit├╝berschreitung!
18:05:27.241 -> Starte Senden: ?:3010:00::c2
18:05:32.241 -> Zeit├╝berschreitung!
18:05:32.241 -> Starte Senden: ?:3010:00::c2
18:05:37.241 -> Zeit├╝berschreitung!
18:05:37.241 -> Starte Senden: ?:3010:00::c2

jetzt mache ich mal den Mega startklar und teste damit....kann nicht lange dauern :partying_face:

Nein
Du schlie├čt den Adapter an TX1 bzw RX1 an und benutzt Serial1.begin() ecc.

Gr├╝├če Uwe

Alles klar, jetzt ist der Mega dran....

oh sorry da hab ich mich wohl unklar ausgedr├╝ck, genau so hab ich das gemeint :slight_smile:

Direkt mal eine Seltsamkeit...ich musste f├╝r diese Verkabelung Mega <-> Rs232-Modul anders anschlie├čen als es ├╝berall (auch hier) steht. Geklappt hat es erst mit Tx<->Tx und Rx<->Rx . Fast egal, hauptsache es hat geklappt....aber auch nur bis hierhin.

Der Ofen Antwortet noch immer nicht!
Hier meine Ausgabe des SerMon bei Verbindung mit Ofen:

18:29:01.232 -> <Arduino is ready>
18:29:01.232 -> Starte Senden: ?:3010:00::c2
18:29:06.232 -> Zeit├╝berschreitung!
18:29:06.232 -> Starte Senden: ?:3010:00::c2
18:29:11.232 -> Zeit├╝berschreitung!
18:29:11.232 -> Starte Senden: ?:3010:00::c2
18:29:16.232 -> Zeit├╝berschreitung!
18:29:16.232 -> Starte Senden: ?:3010:00::c2
18:29:21.232 -> Zeit├╝berschreitung!
18:29:21.232 -> Starte Senden: ?:3010:00::c2

Weitere Seltsamkeit, ich habe nochmal mit Python gelauscht was jetzt vom Mega gesendet wird:

Raw: 
b'?:3010:00::c2\x00'
UTF-8 decoded: 
?:3010:00::c2

Also ein Hex 0 statt des gew├╝nschten \r ....

ok ich konnte 'den Schuldigen' ausfindig machen (Natürlich hab ich keine Ahnung wo das \x00 überhaupt herkam :see_no_evil: [EDIT2: leere Elemente eines Array werden mitgesendet als \x00 - mehr konnte ich nicht herausfinden]), durch die folgende Änderung verschwindet das \x00 und es taucht stattdessen das gewünschte \r auf:

void sendMessage()
{
  if (!sending)
  {
    //messageout[sizeof(messageout)] = '\r';
    Serial.print(F("Starte Senden: "));
    //Serial1.write(messageout, (sizeof(messageout)));
    Serial1.write(messageout);
    Serial1.write(13);
    Serial.write(messageout, (sizeof(messageout)));
    Serial.println();
    sending = true;
  }
}

EDIT: es war eine weitere ├änderung n├Âtig (f├╝r den Fall, dass ich mich irre habe ich nat├╝rlich auch alles ohne meine ├änderungen durchgetestet) - um mit dem Sketch ├╝berhaupt Daten empfangen zu k├Ânnen:

void receiveMessage()
{
  const unsigned long abbruchzeit = 5000;
  static unsigned long lastmillis = millis();
  static bool empfang = false;
  if ( millis() - lastmillis < abbruchzeit)
  {
//************ÄNDERUNG HIER***********
// if (Serial.available() > 0) // 1 Hinzugef├╝gt!
    if (Serial1.available() > 0)
    {
      Serial.println(F("Starte Empfang:"));
      char c = Serial1.read();
      if (!isControl(c)) // Kein Steuerzeichen
      {
        Serial.print(c);
      }
      else               // Steuerzeichen
      {
        Serial.print(c, HEX);
        return (-1);
      }
    }
  }
  else
  {
    Serial.println(F("Zeit├╝berschreitung!"));
    lastmillis = millis();
    sending = false;
    empfang = false;
    return (-1);
  }
}

Was den Ofen angeht, dem ist das alles weiterhin egal :angry: