Serial Monitor (USB) gibt erst nach Eingabe Daten wieder

Moin.

Es kommunizieren 2 Arduinos miteinander, 1xUno, 1xMEGA.
Serial (Uno) <-> Serial2 (Mega)
Serial vom Mega ist an USB und diesen beobachte ich über den Serial Monitor der Arduino IDE

Der Uno schickt immer wieder:

1\n
2\n
3\n
4\n
5\n

auf dem Mega läuft folgendes:

String inData;

void setup() {
  //initialize serial connections
  Serial.begin(9600);
  Serial2.begin(9600);
}


void loop() {

}


void serialEvent() {
  char receivedChar;
  bool transmissionEnd = false;

  if (Serial2.available()){
    receivedChar = Serial2.read();
    inData += receivedChar;
  }

  //check, if '\n' (new line command) was received and set variable "transmissionEnd"
  int newLineFound = inData.indexOf('\n');
  
  if(newLineFound >= 0){
    transmissionEnd = true;
  }
  else{
    transmissionEnd = false;
  }
    
    //When '\n' is found, return content of inData
  if (transmissionEnd){         //when newline was received and so the transmission is complete
      inData.replace("\n","");  //delete new-line Character from end of buffer
      Serial.print("Arduino wiederholt: ");
      Serial.print(inData);
      

      inData = "";              //clear inData buffer
      receivedChar = NULL;      //clear lastchar
      Serial.print('\n');
      //transmissionEnd = false;
    }
    
}

Der Mega soll nur einfach das empfangene wiederholen.
Dies tut er jedoch erst, wenn ich IRGENDetwas per Serial an den Mega sende. Ganz egal was.

Dann zeigt er mir schlagartig die letzten Wiederholungen und nimmt den von mir gewünschten Betrieb auf.

Bevor ich etwas an den Mega sende, blinkt auch nicht die TX Led (welche ja die Kommunikation mit USB signalisiert).

So wie ich das einschätze, funktioniert der Uno und der Serial Monitor aufm Rechner einwandfrei.
Das Problem scheint am Mega zu liegen.
Warum sendet dieser erst per Serial, wenn er über selbige wenn er über selbige irgendetwas bekommen hat? Und wie kann ich dafür sorgen, dass er dies sofort, ohne ein eingreifen, tut?
Einen Workaround hätte ich schon im Kopf, allerdings muss es ja auch so gehen.

Danke im Voraus!

Im Beispiel zu SerialEvent wird Serial.print in loop ausgeführt, nicht in serialEvent. Das würde ich mal entsprechend ändern, ob es dann geht.

agmue:
Im Beispiel zu SerialEvent wird Serial.print in loop ausgeführt, nicht in serialEvent. Das würde ich mal entsprechend ändern, ob es dann geht.

Das hat mich auf den richtigen Weg gebracht.
Sobald ich den Code in die Loop packe, fängt er automatisch an. Also fehlt wohl der "Trigger", dass die Funktion "serialEvent" anfängt. Kann mir einer sagen, warum?

legolas136:
Kann mir einer sagen, warum?

Nö, war nur eine Vermutung, daß es sich um einen "Interrupt in einem Interrupt" handelt.

In Hints for writing ISRs lese ich: "the Arduino IDE uses interrupts for Serial reading and writing" und "Don't do serial prints". Das werte ich mal als Bestätigung meiner Vermutung :slight_smile:

Anders gesagt, SerialEvent ist eine Interrupt Service Routine (ISR), innerhalb der andere Regeln gelten als in einer Funktion.

Hallo,

Du rufst die Funktion serialEvent ja gar nicht auf. Wenn du diese in der loop Funktion einbindest, sollte die Funktion gehen. Momentan macht dein Programm ja nichts außer die Seriellen Ports einrichten oder sehe ich das falsch?

Gruß,
Ludwig

SerialEvent() wird automatisch einmal pro loop() aufgerufen wenn Daten vorhanden sind:

#if defined(HAVE_HWSERIAL0)
  void serialEvent() __attribute__((weak));
  bool Serial0_available() __attribute__((weak));
#endif

int main(void)
{
   ...
   
   setup();
    
   for (;;) 
   {
      loop();
      if (serialEventRun) serialEventRun();
   }
        
   return 0;
}

void serialEventRun(void)
{
#if defined(HAVE_HWSERIAL0)
  if (Serial0_available && serialEvent && Serial0_available()) serialEvent();

...
}

Aus irgendeinem Grund verhält sie sich aber wie eine ISR, auch wenn das eigentlich nicht der Fall sein sollte.

Am besten ist man verzichtet darauf und schreibst seine eigene Funktion die ständig in loop() aufgerufen wird

Aus irgendeinem Grund verhält sie sich aber wie eine ISR, auch wenn das eigentlich nicht der Fall sein sollte.

Am besten ist man verzichtet darauf und schreibst seine eigene Funktion die ständig in loop() aufgerufen wird
[/quote]

mein serial event wurde mit kleinem "s" geschrieben...

Ludwig98Mueller:
Hallo,

Du rufst die Funktion serialEvent ja gar nicht auf. Wenn du diese in der loop Funktion einbindest, sollte die Funktion gehen. Momentan macht dein Programm ja nichts außer die Seriellen Ports einrichten oder sehe ich das falsch?

Gruß,
Ludwig

und du hast recht. Das erklärt natürlich einiges.

jetzt läuft es auf jeden Fall :slight_smile:

Danke!

legolas136:
Aus irgendeinem Grund verhält sie sich aber wie eine ISR, auch wenn das eigentlich nicht der Fall sein sollte.

Das ist natürlich Quatsch.

serialEvent ist eine ganz normale Funktion, die aber nur aufgerufen wird, wenn Serial.available() true ist,
nicht wenn Serial1, Serial2 oder Serial3 etwas zu verarbeiten habe.

Also fehlt wohl der "Trigger", dass die Funktion "serialEvent" anfängt. Kann mir einer sagen, warum?

Wenn man zum Bäcker geht und Brötchen möchte, dann muss man ihm das auch sagen.
:smiling_imp: :smiling_imp: :smiling_imp:

Falsch:

void serialEvent() {
  char receivedChar;
  bool transmissionEnd = false;

  if (Serial2.available()){
    receivedChar = Serial2.read();
    inData += receivedChar;
  }

Besser:

void serialEvent2() {
  char receivedChar;
  bool transmissionEnd = false;

  if (Serial2.available()){
    receivedChar = Serial2.read();
    inData += receivedChar;
  }

ungetestet

Ich korrigiere leicht irritiert meine Vermutungen aus #1 und #3, denn so funktioniert es bei mir (getestet):

// Uno
void setup() {
  Serial.begin(9600);
}

void loop() {
  static byte j = 0;
  j++;
  Serial.println(j);
  j = j % 9;
  delay(500);
}
// Mega2560
String inData;

void setup() {
  Serial.begin(9600);
  Serial2.begin(9600);
}

void loop() {}

void serialEvent2() {
  char receivedChar;
  bool transmissionEnd = false;

  if (Serial2.available()) {
    receivedChar = Serial2.read();
    inData += receivedChar;
  }

  //check, if '\n' (new line command) was received and set variable "transmissionEnd"
  int newLineFound = inData.indexOf('\n');

  if (newLineFound >= 0) {
    transmissionEnd = true;
  }
  else {
    transmissionEnd = false;
  }

  //When '\n' is found, return content of inData
  if (transmissionEnd) {        //when newline was received and so the transmission is complete
    inData.replace("\n", ""); //delete new-line Character from end of buffer
    Serial.print("Arduino wiederholt: ");
    Serial.print(inData);
    inData = "";              //clear inData buffer
    receivedChar = NULL;      //clear lastchar
    Serial.print('\n');
    //transmissionEnd = false;
  }
}

Ob es enpfehlenswert ist, Serial.print() in serialEvent() oder serialEvent2() zu verwenden, vermag ich nicht zu beurteilen.

Wie schon in #5 vorgeschlagen, würde ich neu eingetroffenen Zeichen in loop() abfragen.

combie:
Wenn man zum Bäcker geht und Brötchen möchte, dann muss man ihm das auch sagen.

Nicht zwingend, denn wenn ich beim Bäcker meines Vertrauens reingehe, greift die nette Dame automatisch zur Tüte, um diese zu füllen :slight_smile: Aber Arduinos muß man halt jede Kleinigkeit mitteilen.

Normal sollte print() gehen. Siehe der Code in #5. Das ist keine ISR. Der Trick ist eben dass die Funktion als "weak" deklariert ist. Das heißt dass sie wenn sie nicht definiert wird auch nicht gelinkt wird. Die Adresse ist dann 0, worauf man abfragen kann.

Wenn man natürlich Serial2 verwendet dann muss man auch serialEvent2() verwenden. Jede serielle Schnittstelle hat ihre eigene Version davon.

Kommt serialEvent ( oder auch serialEvent2 ) häufig genug dran, dass du in jedem Aufruf nur einen Buchstaben lesen kannst?

Kannst ja mal den Sender schneller und/oder dicker machen, und den Event - Empfänger langsamer:

void loop() {delay(1000);}

Ich vergaß, die Funktion in der Loop aufzurufen... Also dem Bäcker zu sagen, was ich wollte :smiley:

Danke, für eure Hilfe :slight_smile: