Programm dauert mit seriellen Ausgaben länger als ohne

Hallo,
ich wollte das Rad mal neu erfinden und hab mir zwei Sketche geschrieben, mit denen zwei Arduinos Daten austauschen können, auf Pin 3 und 4. Das Prinzip ist relativ einfach : Wird Pin 3 auf vom Empfänger auf HIGH gesetzt, weiß der Sender, dass er jetzt Daten schicken soll. Dies geschieht über Pin 4. Die "Daten" sind relativ einfach : Ein 16-Bit Wert wird übertragen. Zum Testen ist das der Wert 65000.
Beim Empfänger-Code habe ich zwischen dem Empfangen noch einige DEBUG-Meldungen in Form von seriellen Ausgaben hinzugefügt, um verfolgen zu können, ob die richtigen Werte empfangen werden und wie lange das ganze ungefähr dauert.
Das für mich absolut nicht nachvollziehbare ist, dass das Empfangen des 16-BIt-Wertes mit weniger seriellen Ausgaben ca. 100 ms länger dauert, als ohne.

Der Code des Empfängers liegt unten. Wenn die Präprozessordirektive DEBUG definiert ist, dauert das Empfangen rund 1380 ms. Ist DEBUG nicht definiert, dann dauert das Empfangen ca. 1480 ms.
Die Dauer der Übertragung wird mithilfe der Differenz der Variablen startTransmission und debugTime ausgewertet.

Mit definiertem DEBUG erscheint am Ende bei der seriellen Ausgabe die Zeile :
Receiver : Transmission time : 1382 ms
Ohne definiertem DEBUG (und somit ca. 5 seriellen Ausgaben weniger) erscheint am Ende die Zeile
Receiver : Transmission time : 1482 ms

Könnt ihr mir bitte den Grund dafür sagen ? Denn eigentlich müsste es doch genau anders herum sein, also so, dass der Sketch mit weniger seriellen Ausgaben schneller ist, oder ?

#define TEST
#define DEBUG
#define RECORDING
#define STARTTRANSMISSION 3
#define TRANSMISSIONLINE 4
#define TASTER 8

const unsigned long timeOutLimit = 3000;

#ifdef RECORDING
  unsigned int successful = 0;
  unsigned int total = 0;
#endif

#ifdef TEST
  const unsigned int referenceValue = 65000;
#endif

// Code für den Empfänger
unsigned long startTransmission = 0;
unsigned long debugTime = 0;
unsigned long startValue;
unsigned int value;
int receivedValues = 0;
unsigned long duration = 0;

void setup() {
  // put your setup code here, to run once:
  pinMode(STARTTRANSMISSION, OUTPUT);
  pinMode(TRANSMISSIONLINE, INPUT);
  pinMode(TASTER, INPUT);
  Serial.begin(9600);
}

void loop() {
  // Sobald der Taster an Pin 8 gedrückt wird, soll der Sender uns Daten schicken
  while(digitalRead(TASTER) == LOW);

#ifdef DEBUG
  Serial.print("Receiver : Taster gedrueckt. Sende Nachricht");
  Serial.println();
#endif

  // Jetzt möchten wir Daten vom Sender
  digitalWrite(STARTTRANSMISSION, HIGH);
  value = 0;
  // Warte, bis Sender den HIGH-Impuls schickt um zu signalisieren, dass er bereit ist
  while (digitalRead(TRANSMISSIONLINE) == LOW);

#ifdef DEBUG
  Serial.print("Receiver : Timeout-Limit is set to ");
  Serial.println(timeOutLimit, DEC);
  Serial.println("Receiver : Sender is now Online. Receiving data starts now");
#endif  

  // Timeoutzeit beginnt jetzt
  startTransmission = millis(); //1. Variable für Zeitmessung

  // Verlasse das Empfangen erst, wenn das Zeitlimit erreicht ist, oder 16 Werte empfangen wurden
  while ((millis() - startTransmission < timeOutLimit) && receivedValues < 16)
  {
    if (digitalRead(TRANSMISSIONLINE) == HIGH)
    {
      //Starte Zeitmessung
      startValue = millis();
      //Warte, bis Übertragung des Wertes beendet
      while (digitalRead(TRANSMISSIONLINE) == HIGH);
      //Werte anhand der Dauer den Wert aus     
      duration = millis() - startValue;
      // Wenn es kein Dummy-Wert ist, auswerten
      if (duration > 5)
      {
        if (duration < 45)
        {
          bitWrite(value, receivedValues, 1);
#ifdef DEBUG
          Serial.print("Receiver : I received value 1 \t ");
#endif                    
        }
        else
        {
          bitWrite(value, receivedValues, 0);
#ifdef DEBUG
          Serial.print("Receiver : I received value 0 \t ");
#endif                    
        }       
        //Anzahl der empfangenen Werte um 1 erhöhen  
        receivedValues++;                   
#ifdef DEBUG
        Serial.print("Duration of data paket was : ");
        Serial.print(duration, DEC);
        Serial.print(" ms");      
        Serial.println();  
#endif        
      }
    }
  }
  // Übertragung ist beendet, Leitung auf LOW ziehen
  digitalWrite(STARTTRANSMISSION, LOW);
  receivedValues = 0;
  debugTime = millis(); //2. Variable für Zeitmessung

#ifdef DEBUG
  // Wertausgabe zur Analyse
  Serial.print("Receiver : Transmission time : ");
  Serial.print(debugTime - startTransmission, DEC);
  Serial.print(" ms");
  Serial.println();
  Serial.print("Receiver : I received the value ");
  Serial.print(value);
  Serial.print(", b");
  for (int i=0; i<16; i++)
  {
    Serial.print(bitRead(value, i));
  }
  Serial.println();
  if (digitalRead(TRANSMISSIONLINE)==HIGH)
    Serial.println("Receiver : TRANSMISSIONLINE is HIGH");
  else
    Serial.println("Receiver : TRANSMISSIONLINE is LOW");  
#endif  

#ifdef RECORDING
#ifndef DEBUG
  Serial.println();
  Serial.print("Receiver : Transmission time : ");
  Serial.print(debugTime - startTransmission, DEC);
  Serial.println(" ms");
#endif  
  if (value == referenceValue)
  {
    Serial.println("Transmission successful");
    successful++;    
  }
  else
    Serial.println("Transmission not successful");
  total++;
  Serial.print("Transmissions (successful) : ");
  Serial.println(successful);
  Serial.print("Transmissions (total) : ");
  Serial.println(total);
  Serial.println();
  value = 0;
#endif      
  //Endlosschleife
}

Hallo

Alle verwendeten while() sind verdächtige Kandidaten.

1 Like

Wenn Du mit den seriellen Ausgaben weniger Zeit angezeigt bekommst, dann könnte es daran liegen, das Du Dich täuschen lässt.
Davon abgesehen, das der Compiler vielleicht auch mit den Ausgaben etwas anders optimieren könnte...

Um Laufzeitunterschiede zu ermitteln darfst Du den Code natürlich nicht komplett ändern, sondern nur die maßgeblichen Dinge.

1 Like

Mit den Debug Ausgaben wird startTransmission später gesetzt und täuscht eine kürzere Dauer vor. Verschiebe diese Zeile vor die Ausgaben.

1 Like

Das war auch mein erster Gedanke. Dass er, durch die seriellen Ausgaben, weniger oft den aufwändigen Schleifenkopf abfragen kann und dadurch "schneller" ist.

War ebenfalls mein Gedanke. Aber da wüsste ich auch nicht was er sich speichern sollte. Da er sich ja keine Werte zwischenspeichern kann, sondern immer wieder alles neu genullt und gelesen wird.

Das versteh ich nicht. Mit DEBUG startet die Zeitmessung nach den seriellen Ausgaben und ohne DEBUG wird der komplette Block ja "wegkompiliert". Da dürfte doch eigentlich kein Unterschied sein, oder ?

Was ich noch rausgefunden habe ist, dass das Entfernen dieser Zeilen

#ifdef DEBUG
        Serial.print("Duration of data paket was : ");
        Serial.print(duration, DEC);
        Serial.print(" ms");      
        Serial.println();  
#endif     

einen erheblichen Beitrag zum längeren Andauern des Übertragens beinhaltet. Aber ich kann mir nicht erklären, warum. Hab statt den seriellen Ausgaben mal ein delay reingemacht, aber dann hat es noch länger gedauert.

Vielen Dank für eure zahlreichen Antworten schon Mal !

Ich würde den Code vermutlich komplett anders schreiben.
Da sind mir zuviele Eventualitäten drin.

Ich hab vorgestern auch einen Code gehabt, den ich noch händisch optimieren wollte - aber irgendwann konnte ich machen wie ich will, es wurden einfach nicht mehr weniger verbrauchte bytes...

Du kannst nur das Compilat vergleichen um die Unterschiede festzustellen. Da reicht schon aus, das irgendwo ein Teil mehrfach genutzt wird und wenn Du die seriellen ausgaben rausnimmst das wieder neu geladen etc. pp....

Das werde ich auch machen. Das ganze in Methoden und Funktionen auslagern. Dabei werde ich das ein und andere wahrscheinlich auch noch finden. Mich ging es nur absolut nicht in den Sinn, warum das Ganze mit mehr seriellen Ausgaben länger dauert als ohne :smile:

Aehm, mach mal folgendes:
Ersetze mal die ganzen Serial.print nach folgendem

Muster
// Forensketch  
// https://forum.arduino.cc/


//#define DEBUG              // Wenn aktiviert, werden Zwischenwerte ausgegeben

#ifdef DEBUG
  #define DBG_PRINTLN(...) Serial << __VA_ARGS__ << endl
#else
  #define DBG_PRINTLN(...)
#endif


void setup()
{
  Serial.begin(115200);
#if (defined(ARDUINO_AVR_MEGA) || defined(ARDUINO_AVR_MEGA2650)) // https://github.com/arduino/Arduino/issues/10764
  delay(300);
#endif
  DBG_PRINTLN(__FILE__);
  DBG_PRINTLN( __TIMESTAMP__);
}

void  loop()

{}

und die #ifdef aus dem Code raus.

Ok, die Serial.print hab ich durch die DEBUG ersetzt.
Die Serial.println hab ich durch DEBUG("\n") ersetzt.
Nur im unwichtigen RECORDING-Teil hab ich das Ganze ungeändert gelassen.
Könntest du nochmal kurz drüberlesen, ob das so stimmt ?

#define TEST

#define DEBUG
#ifdef DEBUG
  #define DBG_PRINTLN(...) Serial << __VA_ARGS__ << endl
#else
  #define DBG_PRINTLN(...)
#endif  

#define RECORDING
#define STARTTRANSMISSION 3
#define TRANSMISSIONLINE 4
#define TASTER 8

const unsigned long timeOutLimit = 3000;

#ifdef RECORDING
  unsigned int successful = 0;
  unsigned int total = 0;
#endif

#ifdef TEST
  const unsigned int referenceValue = 65000;
#endif

// Code für den Empfänger
unsigned long startTransmission = 0;
unsigned long debugTime = 0;
unsigned long startValue;
unsigned int value;
int receivedValues = 0;
unsigned long duration = 0;

void setup() {
  // put your setup code here, to run once:
  pinMode(STARTTRANSMISSION, OUTPUT);
  pinMode(TRANSMISSIONLINE, INPUT);
  pinMode(TASTER, INPUT);
  Serial.begin(9600);
}

void loop() {
  // Sobald der Taster an Pin 8 gedrückt wird, soll der Sender uns Daten schicken
  while(digitalRead(TASTER) == LOW);

  DEBUG("Receiver : Taster gedrueckt. Sende Nachricht");
  DEBUG("\n");

  // Jetzt möchten wir Daten vom Sender
  digitalWrite(STARTTRANSMISSION, HIGH);
  value = 0;
  // Warte, bis Sender den HIGH-Impuls schickt um zu signalisieren, dass er bereit ist
  while (digitalRead(TRANSMISSIONLINE) == LOW);

  DEBUG("Receiver : Timeout-Limit is set to ");
  DEBUG(timeOutLimit, DEC);
  DEBUG("\n");
  DEBUG("Receiver : Sender is now Online. Receiving data starts now");
  DEBUG("\n");

  // Timeoutzeit beginnt jetzt
  startTransmission = millis();

  // Verlasse das Empfangen erst, wenn das Zeitlimit erreicht ist, oder 16 Werte empfangen wurden
  while ((millis() - startTransmission < timeOutLimit) && receivedValues < 16)
  {
    if (digitalRead(TRANSMISSIONLINE) == HIGH)
    {
      //Starte Zeitmessung
      startValue = millis();
      //Warte, bis Übertragung des Wertes beendet
      while (digitalRead(TRANSMISSIONLINE) == HIGH);
      //Werte anhand der Dauer den Wert aus und speichere diesen ins Array      
      duration = millis() - startValue;
      // Wenn es kein Dummy-Wert ist, auswerten
      if (duration > 5)
      {
        if (duration < 45)
        {
          bitWrite(value, receivedValues, 1);
          DEBUG("Receiver : I received value 1 \t ");                 
        }
        else
        {
          bitWrite(value, receivedValues, 0);
          DEBUG("Receiver : I received value 0 \t ");                    
        }       
        //Anzahl der empfangenen Werte um 1 erhöhen  
        receivedValues++;                   
        DEBUG("Duration of data paket was : ");
        DEBUG(duration, DEC);
        DEBUG(" ms");      
        DEBUG("\n");      
      }
    }
  }
  // Übertragung ist beendet, Leitung auf LOW ziehen
  digitalWrite(STARTTRANSMISSION, LOW);
  receivedValues = 0;
  debugTime = millis();

  // Wertausgabe zur Analyse
  DEBUG("Receiver : Transmission time : ");
  DEBUG(debugTime - startTransmission, DEC);
  DEBUG(" ms");
  DEBUG("\n");
  DEBUG("Receiver : I received the value ");
  DEBUG(value);
  DEBUG(", b");
  for (int i=0; i<16; i++)
  {
    DEBUG(bitRead(value, i));
  }
  DEBUG("\n");
  if (digitalRead(TRANSMISSIONLINE)==HIGH)
  {
    DEBUG("Receiver : TRANSMISSIONLINE is HIGH");
    DEBUG("\n");
  }
  else
  {
    DEBUG("Receiver : TRANSMISSIONLINE is LOW");  
    DEBUG("\n");
  }

#ifdef RECORDING
#ifndef DEBUG
  Serial.println();
  Serial.print("Receiver : Transmission time : ");
  Serial.print(debugTime - startTransmission, DEC);
  Serial.println(" ms");
#endif  
  if (value == referenceValue)
  {
    Serial.println("Transmission successful");
    successful++;    
  }
  else
    Serial.println("Transmission not successful");
  total++;
  Serial.print("Transmissions (successful) : ");
  Serial.println(successful);
  Serial.print("Transmissions (total) : ");
  Serial.println(total);
  Serial.println();
  value = 0;
#endif      
  //Endlosschleife
}

Jetzt habe ich es, was Du willst. :scream:
Nein, das wird nix.
Du hast auch meinen Einwurf falsch interpretiert.
Aber mal schaun..
Ich hab den Code jetzt mal übernommen und mir formatiert,d as ich sehe, was Du da vor hast.
Während Du in der Einleseroutine ohne debugausgaben sagen wir mal eine Zeit x brauchst, brauchst Du mit debugausgaben eine Zeit x+y
Das ist auch richtig so.
Denn irgendwoher muss die Zeit ja kommen, in der geschrieben wird.

Das Problem ist, das Du Dich möglicherweise selbst bescheisst.
Denn Du wartest zwingend bis Du 16 Pegel gemessen hast.
Wenn Du zwischendurch einen Pegel verlierst, dann merkst Du das nicht.
Der Sender sendet stur weiter - egal was Du auf dem Empfänger machst - bis Du 16 Pegel hast.
Und genau das fällt Dir mit der Ausgabe auf die Füsse.
Denn in der Zeit, wo Du auf dem SerMon ausgibst, hast Du keine Möglichkeit auf einen Pegelwechsel zu reagieren.
Den bekommst Du erst beim nächsten Pegelwechsel mit. Bis dahin können aber schon mal ein paar ms - und damit mehr als ein Pegel verloren gegangen sein.
Wenn Du wissen möchstest, wie schnell Deine Daten kamen, dann musst Du das anders lösen.
In jedem Fall ohne serielle Ausgaben während der Messung.
Und schon gar nicht mit nur 9600.

Las mir mal nen Moment - ich versuch mal was.

Oder ein Timeout eintritt

Der Sender ist so geschrieben, dass nach jedem geschickten HIGH-Pegel der Pegel auf LOW geht und dann 50ms gewartet wird, damit der Empfänger Zeit fürs auswerten und schreiben des Wertes hat. Die Zeit, die der Empfänger für den HIGH-Pegel auswertet, stimmt ja, +/- 2ms, mit dem überein, was der Sender ihm übermittelt (laut den seriellen Ausgaben). Des Weiteren wird auch immer der richtige Wert empfangen. Wie kann es also sein, dass ein Wert verloren geht aber das Ergebnis dennoch passt ?

P.S. Falls ich den relativ simplen Code für den Sender auch posten soll, lass es mich wissen

Aber vergessen, die Startzeit richtig zu ermitteln :frowning:
Dann suche ruhig an der falschen Stelle weiter, ich bin dann raus.

Versuch den mal.
Ich hoffe nix übersehen zu haben.
Ich speicher mir den ab, dann kann ich evtl. später nochmal drauf schaun.

#define TEST

#define DEBUG
#ifdef DEBUG
  #define DBG_PRINT(...) Serial.print(__VA_ARGS__)
  #define DBG_PRINTLN(...) Serial.println(__VA_ARGS__)
#else
  #define DBG_PRINT(...)
  #define DBG_PRINTLN(...)
#endif

#define RECORDING
#define STARTTRANSMISSION 3
#define TRANSMISSIONLINE 4
#define TASTER 8

const unsigned long timeOutLimit = 3000;

#ifdef RECORDING
  unsigned int successful = 0;
  unsigned int total = 0;
#endif

#ifdef TEST
  const unsigned int referenceValue = 65000;
#endif

// Code für den Empfänger
unsigned long startTransmission = 0;
unsigned long debugTime = 0;
unsigned long startValue;
unsigned int value;
int receivedValues = 0;
unsigned long duration = 0;
uint32_t endTransmission = 0;


void setup()
{
  // put your setup code here, to run once:
  pinMode(STARTTRANSMISSION, OUTPUT);
  pinMode(TRANSMISSIONLINE, INPUT);
  pinMode(TASTER, INPUT);
  Serial.begin(9600);
}

void loop()
{
  // Sobald der Taster an Pin 8 gedrückt wird, soll der Sender uns Daten schicken
  while (digitalRead(TASTER) == LOW);
  DBG_PRINTLN("Receiver : Taster gedrueckt. Sende Nachricht");
  // Jetzt möchten wir Daten vom Sender
  digitalWrite(STARTTRANSMISSION, HIGH);
  value = 0;
  // Warte, bis Sender den HIGH-Impuls schickt um zu signalisieren, dass er bereit ist
  while (digitalRead(TRANSMISSIONLINE) == LOW);
  DBG_PRINT("Receiver : Timeout-Limit is set to ");
  DBG_PRINTLN(timeOutLimit, DEC);
  DBG_PRINTLN("Receiver : Sender is now Online. Receiving data starts now");
  // Timeoutzeit beginnt jetzt
  // Verlasse das Empfangen erst, wenn das Zeitlimit erreicht ist, oder 16 Werte empfangen wurden
  receivedValues = 0;
  while ((millis() - startTransmission < timeOutLimit) && receivedValues < 16)
  {
    if (digitalRead(TRANSMISSIONLINE) == HIGH)
    {
      startValue = millis();                               // Starte Zeitmessung
      if (!receivedValues)                                 // Erster Wert noch nicht erfasst?
      { startTransmission = startValue; }                  // Merke wann ausgelöst
      while (digitalRead(TRANSMISSIONLINE) == HIGH);       // Warte, bis Übertragung des Wertes beendet
      duration = millis() - startValue;                    // Werte anhand der Dauer den Wert aus
      if (duration > 5)
      {
        DBG_PRINT(F("Receiver : I received value"));
        if (duration < 45)
        {
          bitWrite(value, receivedValues, 1);
          DBG_PRINTLN(1);
        }
        else
        {
          bitWrite(value, receivedValues, 0);
          DBG_PRINTLN(0);
        }
        //Anzahl der empfangenen Werte um 1 erhöhen
        receivedValues++;
        endTransmission = millis();
        DBG_PRINT("Duration of data paket was : ");
        DBG_PRINT(duration, DEC);
        DBG_PRINTLN(" ms");
      }
    }
  }
  // Übertragung ist beendet, Leitung auf LOW ziehen
  digitalWrite(STARTTRANSMISSION, LOW);
  receivedValues = 0;
  // Wertausgabe zur Analyse
  DBG_PRINT("Receiver : Transmission time : ");
  DBG_PRINT(endTransmission - startTransmission, DEC);
  DBG_PRINTLN(" ms");
  DBG_PRINT("Receiver : I received the value ");
  DBG_PRINT(value);
  DBG_PRINTLN(", b");
  for (int i = 0; i < 16; i++)
  {
    DBG_PRINT(bitRead(value, i));
  }
  DBG_PRINTLN();
  if (digitalRead(TRANSMISSIONLINE) == HIGH)
  {
    DBG_PRINTLN("Receiver : TRANSMISSIONLINE is HIGH");
  }
  else
  {
    DBG_PRINTLN("Receiver : TRANSMISSIONLINE is LOW");
  }
#ifdef RECORDING
#ifndef DEBUG
  Serial.println();
  Serial.print("Receiver : Transmission time : ");
  Serial.print(debugTime - startTransmission, DEC);
  Serial.println(" ms");
#endif
  if (value == referenceValue)
  {
    Serial.println("Transmission successful");
    successful++;
  }
  else
  { Serial.println("Transmission not successful"); }
  total++;
  Serial.print("Transmissions (successful) : ");
  Serial.println(successful);
  Serial.print("Transmissions (total) : ");
  Serial.println(total);
  Serial.println();
  value = 0;
#endif
  //Endlosschleife
}

Hey sorry, das habe ich vergessen.
War doch keine Absicht...

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.