Interrupt benötigt?

Hallo zusammen,

ich habe in meinem vorherigen Topic gerade berichtet, dass ich Bluetooth verwenden möchte. Die anfänglichen Hardwareprobleme habe ich gelöst und die Kommunikation zwischen beiden BT-Modulen läuft nun.
Allerdings gibt es mit dem Quellcode des Herstellers das Problem, dass er mir den Arduino lahm legt. Das heißt im Klartext, wenn die Abfrageroutine des Bluetooth läuft akzeptiert er keine anderen Eingaben mehr und scheint nur noch mit dieser Routine beschäftigt zu sein.

Das scheint an einer verwendeten while-Schleife zu liegen.

Esplizit geht es um diesen Teil des Codes

    while(1)
    {
      if(blueToothSerial.available()){//check if there's any data sent from the remote bluetooth shield
        recvChar = blueToothSerial.read();
        Serial.print(recvChar);
      }
      if(Serial.available()){//check if there's any data sent from the local serial terminal, you can add the other applications here
        recvChar  = Serial.read();
        blueToothSerial.print(recvChar);
      }	
     }

Den kompletten Sketch hänge ich als Anhang ran. Ich habe versucht das ganze mit einem Timer zu umgehen, klappt aber auch nicht.

Wie kann ich die Abfrage laufen lassen, ohne das der rest der Anwendung blockiert wird?

Flashcontroller_Userinterface.zip (6.21 KB)

Hallo,

ich habe den Code mal modifiziert indem ich das While auskommentiert habe. Funktioniert in Soweit, dass ich den Controller wieder bedienen kann. Der Code sieht jetzt so aus

 void BluetoothWork()
 {
  char recvChar;
  if(CTR_timer(Alarm_timer, 150))
  {
    //while(1)
    //{
      if(blueToothSerial.available()){//check if there's any data sent from the remote bluetooth shield
        recvChar = blueToothSerial.read();
        Serial.print(recvChar);
      }
      if(Serial.available()){//check if there's any data sent from the local serial terminal, you can add the other applications here
        recvChar  = Serial.read();
        blueToothSerial.print(recvChar);
      }  
     //} 
  }
 }

Ich habe aktuell aber mehrere Probleme mit dem Code.

1) Serial Monitor läuft voll So wie der Code aktuell ist empfängt der Arduino die ganze Zeit 0. Der Monitor läuft damit voll. So soll da sicher nicht sein. Ich kann nicht prüfen, ob Nachrichten vom Slave an den Master richtig ankommen. Anders herum geht es prima

2) Reset läuft nicht sauber. Wenn ich Empfänger oder Sender ausschalte und wieder anschalte geht der jeweils andere davon aus, dass er noch verbunden ist. Ein Reconnect funktioniert nur wenn ich beide aus und einschalte. Wie kann ich das lösen

Mit dem Timer läuft es, ist aber nicht sauber Ich steuere später eine Leistungselektronik mit dem Empfänger, eine Übertragung ohne Delay wäre wünschenswert.

Das wird wohl an while(1) liegen.
Aus der Schleife kommt der niemals wieder raus …

Das ist eine Endlosschleife. Da kommst du nur mit break wieder raus.

Du kannst ein break am Ende der if-Abfrage machen. Dann bricht er ab wenn etwas empfangen wurde. Man kann auch auf den Empfang eines bestimmten Zeichens abfragen. Kommt darauf an wie du das überhaupt willst. Idealerweise gibt es da einen EventHandler der nur aufgerufen wird wenn etwas ankommt (so ist es beim normalen Serial).

Ok dann schein meine Idee mit der Schleife ja richtig zu sein.

wie kann ich das sauber mit einem Eventhandler lösen? Die While(1) scheint sich auf den BT-Status zu beziehen. Heißt also ... solange das Ding empfangsbereit ist passiert was.

Wenn ich eure Beiträge richtig deute, dann habe ich die möglichkeit nur nach einem bestimmten Zeichen zu suchen, da er immer empfängt, oder ich kann einen Eventhandler bauen. Ist das richtig?

Rtdler: Die While(1) scheint sich auf den BT-Status zu beziehen. Heißt also ... solange das Ding empfangsbereit ist passiert was.

Nein, while(1) ist vollkommen losgelöst von Bluetooth oder sonstwas. Alles nachfolgende in der geschweiften Klammer wird einfach dauerhaft wiederholt, ähnlich wie alles in der loop permanent wiederholt wird. Begründung für das while-Konstrukt: 1 ist immer. XD

ok heißt im Klartext, kann ich eigentich auflösen?

ich würde durch meinen Timer im 50 MS Takt abfragen und gut ist. Der Rest des Steuerteils sollte dann noch laufen.

Für den Reconnect habe ich mir folgendes überlegt.

Ausgangslage Die Controller schalten sich beim Start über die Funktion setupBlueToothConnection() in den Paarungsmodus und warten bis sie sich verbinden. Fällt einer der Controller aus merkt der andere das nicht.

Lösungsansatz Wenn beide Controller alle 5 Sekunden oder alle 10 Sekunden den anderen kurz ansprechen und dieser bestätigt hat man eine permanente Überwachung. Beide prüfen sich gegenseitig. Merkt einer, dass der andere ausgefallen ist, schaltet er in den Paarungsmodus.

Umsetzung Da ich die eingehenden Strings eh prüfen und auswerten muss baue ich einfach eine Schleife ein, die da sinngemäß heißt

Master prüft Slave: !Slave Keep alive$ (von Master an Slave) !Slave Heartbeat$ (Anwort von Salve an Master)

Salve prüft Master: !Master Keep alive$ (von Slave an Master) !Master Heartbeat$ (Anwort von Master an Salve)

Was haltet ihr davon?

Du solltest das vielleicht in einer Art Ping-Pong-Verfahren machen, bei dem der Master den Ton/Takt angibt. Sprich der Master sendet eine (An-) Frage und der Slave antwort in Zeitspanne X. Z.B auf ein "Hallo ? Wach ?" vom Master gibt der Slave ein konkretes "JEIN". :D

Ebenso wenn du von Slave Daten in irgendeiner Form haben willst. Master fragt an "Hass mal ne Mark ?" - Slave sagt "Ne, leider aus" oder "Frag in ner Stunde noch mal".

Wenn Master und Slave unkontrolliert sich gegenseitig fragen, kann das zu Kollisionen und Datenverlust führen. Da gibt es zwar auch Protokolle für, aber es soll ja einfach sein, oder ?

Das sollte eigentlich reichen, wenn du das mit "blueToothSerial.available()" auf beiden Seiten in der Loop abfragst und ein evtl. Timeout nicht zu klein machst. Sklaven sind auch nur ....

Hallo auf einem so ähnlichen Weg versuche ich das gerade, aber ich befürchte ich seh den Wald vor lauter Bäumen nicht.

Ich habe jetzt eine schöne Routine zum Auswerten implementiert, aber bekomme nun sofort nach dem ersten Verbinden die Meldung zum wiederverbinden

Master is inquiring!
Connecting to slave:0,13,EF,0,7,5C;SeeedBTSlave
Connect again!
Connect again!
Connect again!
Connect again!
Connect again!
Connect again!
Connect again!
Connect again!

Der Slave hingegen zeigt mir an, dass er verbunden ist. Auch die LED´s zeigen dass an. Evtl habe ich auch alles zu kompliziert aufgebaut.

Mein Ansatz ist der, dass nach fünf Sekunden der Slave vom Master gefragt wird bist du da und der Slave den Master nach 6 Sekunden fragt bist du da.
Nachdem ich die Routine eingebaut habe frist sich auch der Arduino wieder in einer Endlosschleife fest. Ich hab echt keine Ahung wie ich es anders machen soll.

Bitte schaut in meinen Code (siehe Anlage) und sagt mir was ich falsch gemacht habe.

Die Datei Slave ist für den slave und die Flashcontroll für den Master.

Ich habe für die einzelnen Programmteile immer einzelne Tabs aufgebaut. Ich will es so strukturiert und übersichtlich halten. Bitte helft mir.

Danke vorab

Flashcontroller_Userinterface.zip (7.57 KB)

Slave.zip (2.62 KB)

Hallo,

nach einer weiteren Stunde Knobbeln bin ich soweit, dass die Verbindung untereinander steht.
Ich kann auch die Seriellen Monitore ansprechen und sehe was passiert.

Scheinbar scheint sowhl auf dem Slave als auch auf dem Master meine Auswertung einen Fehler hervorzurufen.

Auf dem Master kann ich die Einstellungen am Terminal wieder vornehmen, aber im Serial Monitor werde ich mit 0en gefluttet. Eingaben am seriellen Monitor werden scheinbar nicht genommen oder gesendet.

Auch beim Slave kann ich eingaben scheinbar nicht versenden.

Ich stehe nun also vor dem Problem eine Verbindung zu haben, welche aber nicht sauber funktioniert. Auf dem Master erscheinen tausende 0en und auf dem Slave tut sich nix und ich kann keine Eingaben machen.

Wo liegt mein Fehler?

Den aktuellen Sketch hänge ich nochmal dran.

Flashcontroller_Userinterface.zip (7.13 KB)

Slave.zip (2.64 KB)

Hallo zusammen,

viele Stunden Arbeit später und es war erfolgreich. Ich habe die BT zum Laufen bekommen.

Folgende Infos möchte ich weiter geben, damit nachfolgende evtl nicht ganz viele Probleme haben.

BT-Lib Die Lib läuft an und für sich gut, aber es gibt ein paar Probleme. Die enthaltene While-Schleife in der Auswertung des Loop ist ein Thread-Blocker. Läuft diese Schleife wird kein anderer Thred mehr. Dies kann man umgehen indem man einfach die while rausnimmt. Reconnects bei Verbindungsabbruch sind sehr langwierig. Hier brauche ich etwas Anderes bzw. Schnelleres. Sobald ich ein Ergebnis habe werde ich berichten. Eine Keep Alive Signal gibt es in der Lib nicht. Dieses muss man sich selber bauen (beschreibe ich gleich noch).

Auswerten des BT-Signals Es ist ein serielles Signal. Daher kann man sich hier prima eine Auswertroutine schreiben. Meine sieht so aus

void BTAuswertung()
{
  while (blueToothSerial.available() > 0) 
  {
    char c = blueToothSerial.read();
    if(currentState==STATE_UNDEFINED)
    {
      if(c == ';')
      {
        currentState = STATE_READING_KEY;
        Serial.println("Key erkannt");
      }
      else if (c == '%')
      {
        CallStatus();
      }
    }
    else if(currentState== STATE_READING_KEY)
    {
      if(c == '=')
      {
        currentState = STATE_READING_VALUE;
        Serial.println("Value erkannt");
        Temp_BTReceiveValue = "";
      }
      else
      {
        Temp_BTReceiveParameter= Temp_BTReceiveParameter + c; 
        //Serial.print("Keybezeichnung zusammensetzen "); 
        //Serial.println(Temp_BTReceiveParameter);
      }
    }
    else if(currentState== STATE_READING_VALUE)
    {
      if(c == '|')
      {
        //PROCESS KEY AND VALUE NOW
        BTReceiveParameter = Temp_BTReceiveParameter;
        BTReceiveValue = Temp_BTReceiveValue;

        //Hier muss der Absprung zur Verarbeitung hin

        //Reset für nächsten Durchlauf
        currentState = STATE_UNDEFINED;
        Temp_BTReceiveParameter = "";
        BTReceiveValue = Temp_BTReceiveValue;
        Serial.print("fertig heisst es "); 
        Serial.print(BTReceiveParameter); 
        Serial.print(": ");
        Serial.println(BTReceiveValue);
      }
      else 
      {
        Temp_BTReceiveValue = Temp_BTReceiveValue + c; 
        //Serial.print("Value zusammensetzen "); 
        //Serial.println(Temp_BTReceiveValue);
      }
    }
    break;
  }
}

Keep Alive Es ist mir wichtig, dass die Reconnects schnell und sauber laufen. Daher muss der Controller auch schnell wissen, wenn sein BT weg ist. In der Netzwerktechnik bei Clustern (große Rechnerverbunde) wird in schnellen Abständen geprüft, ob der andere Server noch lebt. Diesen Grundgedanken habe ich hier aufgegriffen und eingesetzt. Im Sekundentakt senden beide Geräte ein Lebenssignal (in meinem Fall ser Salve ein % und der Master ein ?). Kommt das Signal in Auswertroutine an wird ein Zeitstempel in eine Variable gesetzt. Eine weitere funktion prüft alle 2,1 Sekunden ob das Signal noch da ist. Somit darf sich auch mal ein Signal mit einem anderen Überschneiden ohne, dass sofort ein Reconnect eingeleitet wird Am seriellen Monitor lasse ich mir das alle 15 Sekunden anzeigen. Wichtig ist, dass ihr jeweils eigene Timer definiert, denn sonst heben sie sich gegenseitig auf und es wird ein Disconnect erkannt.

void checkHeartbeat()
{
  long aktuell = millis();
  if (aktuell - KeepAlive > 2100)
  {
    if(CTR_timer2(Alarm_timer2, 15000))
    {Serial.println("Slave broken");}
    //Funktion für Reconect
  } 
  else
  {
    if(CTR_timer2(Alarm_timer2, 15000))
    {Serial.println("Slave connected");}
  }
}

void SlaveAlive()
{
  if(CTR_timer3(Alarm_timer3, 1000))
  {
    blueToothSerial.print("?");
    //Serial.print("Call for Slave is alive");
  } 
}

void CallStatus()
{
KeepAlive = millis(); 
currentState = STATE_UNDEFINED;
}

So nun habt Spaß damit. Ich hoffe es hilft dem ein oder anderen mit gleichen Vorhaben.