Delay nötig bei serieller Abfrage? (Midi)

Hallo zusammen, ich habe ein kleines Problem mit dem Midi Breakoutboard, bzw. mit dem Empfang von Midi Daten. Ich hatte irgendwo gelesen das die serielle Schnittstelle auf dem Arduino 64 Bytes puffert und das ganze mit:

  if(Serial.available() > 0)
  {
    byte1 = Serial.read();
    byte2 = Serial.read();
    byte3 = Serial.read();
[..]

abgefragt werden kann. Das funktioniert bei mir aber so nicht. Keyboard ist per USB am PC und per Midikabel am Arduino. Am PC läuft Midi-Monitor zur Kontrolle welche Nachrichten gesendet werden. Benutze ich den Code oben, empfängt der Arduino anscheinend nichts. Sobald ich aber Delays einfüge, wird die Kommunikation immer stabiler.

void read_midi()
{
  if(Serial.available() > 0)
  {
    byte1 = Serial.read();
    delay(3);
    byte2 = Serial.read();
    delay(1);
    byte3 = Serial.read();

    // We pick only what we want from the stream
    switch (byte1)
    {      
      // Note on msg 
      case 0x90:
        aktnote=byte2-36;
        keycounter=keycounter+1;
        ACT_kkeys[aktnote]=keycounter;
        digitalWrite(gatepin, HIGH);
      break;

      // Note off msg 
      case 0x80:
        ACT_kkeys[byte2-36]=0;
      break;
[..]

Sobald das erste Delay unter 3ms oder das zweite entfernt wird, werden nicht mehr alle Noten empfangen. Sind beide Delays raus, geht gar nichts. Daten werden aber laut Midi-Monitor einwandfrei gesendet. Als Baudraten habe ich erst 31250 gehabt und dann von 30-33k experimentiert ob der Programmier sich einen Spaßß erlaubt hat und die Rate auf 31337 oder so eingestellt hat^^ Die Bytes hatte ich schon umgestellt, das er erst das erste überprüft, verzeigt und danach erst die beiden anderen Bytes holt. Nichts ändert sich. Die Midischnittstelle hat 3125 Bytes pro Sekunde, da sollten theoretisch 500 Noteon/Noteoff Befehle jede Sekunde durchpassen. Mit einen 4ms delay reduziert sich das auf maximal 125. Einmal am Modulationrad gedreht (60 werte rauf und wieder runter) und die Kiste steht für eine knappe Sekunde.

Wer hat eine Idee dazu und kann mir helfen? lg Smai-Lee

Natürlich braucht es eine gewisse Zeit bis die Daten übertragen sind und wo keine Daten angekommen sind kann auch nichts gelesen werden. Du könntest vor jedem Serial.read kontrollieren ob eine Byte angekommen ist oder in Serial.available() kontrollieren ob 3 byte angekommen sind. Grüße Uwe

Also, es werden auf jeden Fall Daten gesendet, sehe ich am Midi-Monitor auf dem PC. Aktuell sieht der Code so aus:

if(Serial.available() > 0)
  {
    byte1 = Serial.read();
    delay(3);

    // We pick only what we want from the stream
    switch (byte1)
    {      
      // Note on msg 
      case 0x90:
        byte2 = Serial.read();
        delay(1);
        byte3 = Serial.read();

        aktnote=byte2-36;
        keycounter=keycounter+1;
        ACT_kkeys[aktnote]=keycounter;
        digitalWrite(gatepin, HIGH);
      break;
[..]

Die Zeile if(Serial.available() > 0) wird ja nur ausgeführt, wenn tatsächlich Daten anliegen. Wenn es das richtige Byte ist, wird verzweigt und erstmal gewartet. So ist es auch logisch korrekt, da ich nicht immer von Tripletts ausgehen kann. Hatte das nur für die Lesbarkeit oben umgestellt, kann im Code nix fett markieren.

Du könntest vor jedem Serial.read kontrollieren ob eine Byte angekommen ist oder in Serial.available() kontrollieren ob 3 byte angekommen sind.

Das werde ich in Abwandlungen mal probieren. Danke für den Tip, ich werde berichten. lg Smai-Lee

So, da hat man den Baum vor lauter Blätter gar nicht gesehen:

void read_midi()
{
  if(Serial.available() > 0)
  {
    byte1 = Serial.read();

    // We pick only what we want from the stream
    switch (byte1)
    {      
      // Note on msg 
      case 0x90:
        presstime=millis();
        read_addbytes2();
        aktnote=byte2-36;
        keycounter=keycounter+1;
        ACT_kkeys[aktnote]=keycounter;
        digitalWrite(gatepin, HIGH);
      break;

      // Note off msg 
      case 0x80:
        read_addbytes1();
        ACT_kkeys[byte2-36]=0;
      break;
[..]

In einer neuen Funktion hole ich die passende Anzahl Bytes ab, die ich brauche und verwerfe den Rest.

void read_addbytes2() { read1: if(Serial.available() < 2) goto read1; byte2 = Serial.read(); byte3 = Serial.read(); }

Das goto mag zwar nicht elegant erscheinen, erfüllt aber seinen Zweck und kenne ich schon seit dem VC20 ;) Keine verlorenen Noten und keine Pitchbend Hänger mehr, klasse... Danke nochmal für den Tip. lg Smai-Lee

goto ist gänsehautig. Du kannst das gleiche mit while() machen. In C braucht man eigentlich kein goto. Du kannst kein Microsoft-Basic des VC20 mit C bzw C++ vergleichen. Grüße Uwe

Smai-Lee: void read_addbytes2() { read1: if(Serial.available() < 2) goto read1; byte2 = Serial.read(); byte3 = Serial.read(); }

?????

void read_addbytes2()
{
  while (Serial.available() < 2) ;
  byte2 = Serial.read();
  byte3 = Serial.read();
}

Ist sauberer und auch noch kürzer.