Serielle Kommunikation Rx ISR-Logikdesign

Wenn ich mich nicht irre, soll ein ISR eine minimale Verarbeitung durchführen, wenn er Daten seriell (über UART) empfängt. Ich plane die Implementierung eines solchen Protokolls für die Kommunikation zwischen 2 Systemen über UART. Dies ist eine grobe Situation, wie ich die ISR codieren möchte. Angenommen 2 System A & B, wo A eine Nachricht an B sendet: Das Schlüsselwort wird verwendet, um den Beginn der Nachricht anzugeben (festgelegte Daten/Länge kann nicht das Schlüsselwort sein). Kanal OK, Datenlänge, RxLength, RxData, Paketempfangs-Flag im Prozess von B sind standardmäßig 0. Datenlänge = nein. von (allen Daten) in Bytes (z. B. wenn alle Daten = 1, Länge der Daten = 1)

A's Process                               
 Send Keyword
 Send Length of data
 Send all data                

B's Process
 Rx Interrupt
 enter ISR
 ISR: if(Received Byte == Keyword && !ChannelOK)
      {
        Set ChannelOK 
      }

      if(ChannelOK && RxLength)
      {
       Set Length of data=received byte 
       ChannelOK=0
       RxLength=0
      }

      if(Length of data != 0 && RxData)
      {
        Store Data
        --Length of data
        if(Length of data==0)
        {
         Set Packet received flag
         RxData=0
        }
      } 

      if(ChannelOK)
      {
       Set RxLength
      } 

      if(Length of data)
      {
       Set RxData
      }
     Reset to Interrupt Again

Mein Zweifel ist: B hat im ISR so viel zu tun, während A ununterbrochen sendet. Unter der Annahme, dass A Daten mit 7,5 Mbit/s (11 Bit pro Übertragung) sendet, muss der ISR den Interrupt alle (11/7,5 Mio.) Sekunden zurücksetzen. Dies scheint sehr sehr klein. Gehen Daten verloren, wenn ich den Interrupt nicht rechtzeitig zurücksetze, oder werden sie im 16-Byte-FIFO gespeichert, sodass ein Interrupt sofort ausgelöst werden kann, sobald ich den Interrupt zurücksetze, oder muss ich einen Tx-Prozess verlangsamen, indem ich auf ein ACK warte? für jedes Byte (verlangsamt viel)???

Ich bin ein Neuling bei ISR. Bitte helfen Sie ISR-Designs oder -Protokolle für die serielle Datenkommunikation wären nützlich

Danke

Ich verstehe die zweite Hälfte Ihres ersten Absatzes nicht.
Das Schlüsselwort ist ein Hexadezimalwert wie 0x5A. Wenn der ISR nur diesen Wert sieht, wird er versuchen, die darauffolgenden Daten zu speichern. Beispiel: 1. Byte – 0x5A, 2. Byte – 3, 3. Byte – 0x12 (cmd), 4. Byte – irgendein Status, 5. Byte – Nachrichtenprüfsumme. 0x5a kann niemals ein Datum oder eine Länge sein. Es kann nur den Beginn einer Nachricht anzeigen. Sobald eine vollständige Nachricht empfangen wurde, muss sie auf 0x5a prüfen, um sie erneut zu empfangen
Sie haben 82,5 us für jedes Byte ... wie lange dauert es, bis Ihre Hauptschleife (im schlimmsten Fall) alles verarbeitet hat? Wenn es 80 us oder weniger sind, sollte es kein Problem geben. Dies ist in Assembler leicht abzuschätzen. Bei höheren Sprachen müssen Sie möglicherweise Ihren Code simulieren oder (keuchen!) Instrumentieren und die Schleifenzeit tatsächlich messen (stellen Sie sicher, dass Sie die längsten Pfade durch den Code nehmen).
Wie 82,5 us? Das ist das Problem, ich möchte nicht auf die bloße Ebene herunterkommen, wie lange jede Anweisung dauert (obwohl möglich). Ich möchte ISR so einfach wie möglich halten, damit die Zeit, die durch das einfache Halten von ISR gespart wird, woanders konzentriert werden kann

Antworten (2)

Ich werde eine Methode vorschlagen, die Sie mit einigen Modifikationen an Ihre Bedürfnisse anpassen können.

Bei diesem Verfahren ist die ISR so klein, dass sie nur Daten in einem Array für die spätere Dekodierung im Hauptprogramm speichert, zwei Zähler werden verwendet, um empfangene Daten und dekodierte Daten zu erkennen. Natürlich können Sie anstelle der Zähler Zeiger verwenden.

   ISR:
 { 
    Receivedbytes[i++]= Rxbuffer;
    dataReceived++;
    }

    main:

    void UARTdecode{

    if (dataDecoded<dataRecived)
    {
    Received byte = Receivedbytes[j++];
    ///// where routine 
    if(Received Byte == Keyword && !ChannelOK)
          {
            Set ChannelOK 
          }
    ..
    ..
    ..
    //// end of routine 

    dataDecoded+=x; (where x is the amount of data decoded or message length)
    }

    }

PS: Es ist SEHR WICHTIG, dass i und j als statische Variablen deklariert werden

Sie können auch den Quellcode der Arduino-Hardwareserienbibliothek überprüfen, es ist Open Source und verwendet ISR, um Daten „HardwareSerial.h“ im Installationsverzeichnis zu empfangen

Sie sagen also, ich kopiere einfach die Daten in ISR in einen Puffer und mache die gesamte Verarbeitung, die in meiner ISR in main () geschrieben ist?
Schließlich überprüfe ich nur, ob dataDecodiert = Länge der Daten + 2 ist
Ja ! Wenn dies die Antwort ist, nach der Sie suchen, empfehle ich Ihnen dennoch, sich die serielle Bibliothek der Arduino-Hardware anzusehen. und beachten Sie bitte, dass die erwähnten Zähler wichtig sind, weil Sie wissen müssen, welche Zeichen im Array Sie gelesen haben und welche nicht. experimentieren Sie damit und wenn Sie immer noch Zweifel haben, posten Sie sie.
Ja, ich stimme zu, dass die Zählerwerte statisch sein müssen. Danke :) Ich schaue mir die Bibliothek an. Il Post hier, wenn irgendwelche Zweifel
Dies sieht aus wie eine Ringpufferimplementierung
B hat in der ISR so viel zu tun

Nein, zumindest nicht, wenn Sie das System richtig gestalten. Ich würde jede Dekodierungslogik aus dem ISR heraushalten. Normalerweise greift mein UART-Interrupt-Handler das Byte von der Hardware, löscht die Interrupt-Bedingung und stopft das Byte in einen FIFO. Der Vordergrundcode kann es von dort übernehmen. Machen Sie den FIFO groß genug, damit der Vordergrundcode in Bursts ausgeführt werden kann und der FIFO zwischen Bursts nicht überläuft.

Wenn pro Byte einfach zu viel zu tun ist, haben Sie ein grundlegendes Problem, das die Firmware nicht beheben kann. Sie benötigen einen schnelleren Prozessor oder eine langsamere Kommunikation.

Sie sagen also, dass ich einfach die empfangenen Daten in der ISR in einen globalen Puffer {[RxBuffer [Loc++]]] kopiere und den Interrupt zurücksetze. In main() gehe ich und überprüfe, ob der Wert in RxBuffer[0] das Schlüsselwort ist. Wenn es das Schlüsselwort ist, verarbeite RxBuffer[1]--RxBuffer[FinalLoc]. Wenn nicht, lösche den RxBuffer. Aber woher wissen Sie, wann das komplette Paket angekommen ist? Indem ich so etwas wie einen Stack-Check-Algorithmus verwende, bei dem ich alle Loc des RxBuffer auf einen definierten konstanten Wert initialisiere (wie Schlüsselwort, aber Diff-Wert wie 0xa5). Wenn der Wert bei RxBuffer[Length+1] != konstanter Wert, Nachricht empfangen. Sonst vollständige Nachricht noch nicht Rxd.