Go Down

Topic: <Gelöst> Langsame Kommunikation mit 57600 Baud (Read 1 time) previous topic - next topic

Rubbernose

Mar 03, 2015, 03:32 pm Last Edit: Mar 03, 2015, 06:26 pm by Rubbernose
Hallo,

ich habe ein seltsames Problem. Ich muss 20 x pro sec einen String (80 Zeichen) übertragen.
Im Einsatz ist ein Mega mit 57600 Baud. Gemäß Oszi habe ich genügend Zeit. Nur 20% werden für die Übertragung genutzt, 80 % der Zeit verstreicht nutzlos.
Code: [Select]
#include <TimerOne.h>
 
void setup()
{
  Serial1.begin(57600); //das Gleiche bei 115200
  Timer1.initialize(50000); // 20 Hz
  Timer1.attachInterrupt( timerIsr ); // attach the service routine here
}
 
void loop()
{
  // Main code loop
  // TODO: Put your regular (non-ISR) logic here
}
 
/// --------------------------
/// Custom ISR Timer Routine
/// --------------------------
void timerIsr()
{
//Serial1.print("#X11111222223333344444444445555556666677777888889999900000111112"); // funktioniert nicht!!
  Serial1.print("#X1111122222333334444444444555555666667777788888999990000011111");  // that works!!
}

20 x 60 Zeichen sind keine 2000 Baud.
Wird der Timer entfernd und unkontrolliert gesendet dann klappt das.
Wo kann der Fehler liegen?

Serenifly

#1
Mar 03, 2015, 03:43 pm Last Edit: Mar 03, 2015, 03:45 pm by Serenifly
Serial hat in einer ISR nichts zu suchen! Eine ISR deaktiviert das globale Interrupt Enable Flag. Nimm einen "volatile bool" als Flag um zu kennzeichnen dass ein Interrupt eingetreten ist. Die kannst du dann in der ISR setzen und in loop() darauf abfragen

Bei 80 Zeichen hast du auch das Problem, dass der serielle Ausgangspuffer standardmäßig nur 64 Zeichen hat und dann erst mal blockiert. Den kannst du aber in neueren Arduino Version in x:\Arduino\hardware\arduino\avr\cores\arduino\HardwareSerial.h anpassen

Es kann sich auch anbieten auf den Timer zu verzichten und das Timing mit millis() zu machen. Siehe BlinkWithoutDelay Beispiel.

Rubbernose

Aha, jetzt sehe ich etwas klarer. Danke!
Ich denke ich werde den Timer-Interrupt brauchen, da mein Programm immer unterschiedlich schnell arbeitet.

Gibt es für den ersten Teil der Antwort ein Beispiel? (ich hab garnix verstanden!)

jurs

Wo kann der Fehler liegen?
Dead-Lock ==> Programm tot.
R.I.P. bis zum nächsten Reset.

So schnarchlangesame Schnittstellen wie Serial mußt Du vom normalen Code aus bedienen.

In den seriellen Ausgangspuffer passen nur 63 Zeichen rein, und wenn Du versuchst, bei blockierten Interrupts innerhalb eines laufenden Interrupts mehr Zeichen reinzuschieben, müssen erst Zeichen gesendet werden, bevor wieder welche in den Ausgangspuffer reinpassen. Es können aber keine gesendet werden, weil während Deiner Interruptverarbeitung alle übrigen Interrupts im System gesperrt sind. Das ist die typische Dead-Lock-Situation mit der Du das Programm effektiv anhältst.

Serenifly

#4
Mar 03, 2015, 04:06 pm Last Edit: Mar 03, 2015, 04:07 pm by Serenifly
Code: [Select]

volatile bool interruptTriggered;

void loop()
{
   if(interruptTriggered)
   {
       interruptTriggered = false;
       Serial.println("Interrupt");
   }
}

void timerISR()
{
   interruptTriggered = true;
}




Rubbernose

@jurs:
das klingt alles gut, stimmt sicher auch, bringt mich aber nix weiter ...

@serenifly:
heißt das daß ich das senden in loop verschieben soll, nur eben getriggert von einer Variable (volatile) die im Timer immer auf true gesetzt wird?

sschultewolter

@jurs:
das klingt alles gut, stimmt sicher auch, bringt mich aber nix weiter ...

@serenifly:
heißt das daß ich das senden in loop verschieben soll, nur eben getriggert von einer Variable (volatile) die im Timer immer auf true gesetzt wird?

Ja, weil wie gesagt, Serielle Ausgaben haben in einem Interrupt nichts zu suchen. Ein Interrupt sollte so schnell wie möglich abgearbeitet werden.
Orginal Atmel AVRISP mkII zu verkaufen. Anfrage per PN ;)

Serenifly

Und für maximale Geschwindigkeit solltest du den Ausgangspuffer auf 128 Bytes erhöhen. Das macht das Senden an sich nicht schneller, aber dein Programm kann dann die Daten auf einmal in den Puffer schieben und direkt weiter arbeiten ohne auf das Senden zu warten.

Rubbernose

Okay, wie kann ich den Puffer vergrößern? Hab mir die Hardwareserial.h schon angesehen. Werde aber daraus nicht schlauer...

sschultewolter

Steht doch eindeutig im Header-File.
Code: [Select]
#define SERIAL_TX_BUFFER_SIZE 64

\Arduino\hardware\arduino\avr\cores\arduino\HardwareSerial.h
Orginal Atmel AVRISP mkII zu verkaufen. Anfrage per PN ;)

Serenifly

Wobei das erst ab 1.5.7. geht. Also nicht in den alten 1.0.x Versionen

Rubbernose

Hmmm! Hab da noch nie drin rumgeschrieben.
Den Eintrag
 #define SERIAL_TX_BUFFER_SIZE 64

hab ich NICHT in HardwareSerial.h sondern ein
  #define SERIAL_BUFFER_SIZE 128
HardwareSerial.cpp gefunden.
Ist das sowas ähnliches?
Ich nutze nicht Windows sondern Linux.
Stimmt denn der Pfad?
Arduino/arduino-1.0.5/hardware/arduino/cores/arduino
Eine andere HardwareSerial.cpp habe ich nicht gefunden...

Serenifly

Ja, du hast die alte Version (1.0.5). Du kannst das mal probieren. Sollte gehen. Dann wird er wohl Sende und Empfangspuffer auf 128 erhöhen. Ist aber abgesehen vom RAM Verbrauch nicht schlimm.

Ab 1.5.7 kann man die getrennt anpassen.

Rubbernose

Saugut! Rennt wie Teufel! Wie kann ich das hier auf gelöst setzen?

sschultewolter

Einen "Gelöst" Pre/Suffix gibts im Forum nicht. Du kannst deinen obersten Beitrag editieren und den Threadtitel abändern, aber nicht zwingend nötig.
Orginal Atmel AVRISP mkII zu verkaufen. Anfrage per PN ;)

Go Up