Guten Tag allerseitz, ich programmiere derzeit einen PIC16F873 in MPLAB und dem xc8-compiler und nutze seine UART-Schnittstelle um diesen selbst zu parametrisieren, bzw. zu steuern. Nun habe ich aber eine grundlegende Frage: Die Verarbeitung der Bytes, welche über die UART-Schnittstelle eintreffen geschieht derzeit bei mir in der Interrupt-Routine und zum einfachen Debuggen schicke ich mir die empfangenen Bytes einfach zurück, was auch im Einzelfall klappt. Nun möchte ich allerdings dauerhaft Nachrichten bzw. mehrere Bytes hintereinander empfangen (siehe Protokoll unten) und das bereitet mir Probleme. Es werden Bytes verschluckt und falsch zurückgesendet. Ich denke Schuld daran ist die Verarbeitung in der ISR. Ich habe mir ein Protokoll definiert, welches folgendermaßen aussieht: Byte 1 - Adresse bzw. Kommando Byte 2 - Länge der Nutzdaten (max 32.Byte) Byte 3-35 - Nutzdaten Letztes Byte - einfache Checksumme der Nutzbytes Ich möchte das erste Byte prüfen, ob es mit dem Kommando des PICs übereinstimmt (das ist von mir selbst gewählt bsp.: 0xAA). Wenn ja, soll der Rest gelesen und in einem Array gespeichert werden. Anschließend, wenn alles in Ordnung ist (Anzahl des Nutzbytes ok, Checksum ok), soll die Nachricht weiter verarbeitet werden und verschiedene Dinge tun. Nur aber zu meiner Frage: Wo passiert denn die Verarbeitung der empfangenen Daten bzw. die Prüfung des ersten Bytes? Wie fange ich den Fall ab, dass der Sender meinen PIC zu schnell mit neuen Bytes versorgt - klassisches Handshake-Verfahren? Wie löst man so etwas generell elegant? Ich brauche keinen Beispielcode oder ähnliches, sondern suche einen Ansatz für das Problem. Vielen Dank und freundliche Grüße musicmiles
Ich teil das immer auf: Emfpangen / Senden - ISR ("automatisch"): Die ISR stopft nur die Buffer. Ich hab immer zwei Hilfsbuffer, RX und TX. Da steht je ein ganzes Paket drin. Mit jedem Interrupt werden in der ISR die empfangenen Bytes in den RX-Buffer geschreieben und aus dem TX-Buffer in die UART geschrieben. Ist ein Paket vollständig, wird ein Jobflag gesetzt. Auswerten / Antworten - Applikation: Irgendwo in deiner Applikation prüfst du das Jobflag, wenn es gesetzt wird, wertest du den RX-Buffer aus, stopfst die Antwort in den TX-Buffer und startest fallweise die Übertragung - im Endeffekt Interrupt einschalten, 1 Byte schreiben. Senden / Empfangen rattert automatisch durch. Auf die Art macht die ISR nur wenig - Buffer stopfen, Jobflag setzen - und blockiert dir nicht andere Sachen, die Applikaion muss sich nicht um den Low-Level-Mist kümmern. Du wirst auch nie Bytes vermissen, weil alles zeitkritische in der ISR passiert.
musicmiles schrieb: > Ich habe mir ein Protokoll definiert, welches folgendermaßen aussieht: > Byte 1 - Adresse bzw. Kommando > Byte 2 - Länge der Nutzdaten (max 32.Byte) > Byte 3-35 - Nutzdaten > Letztes Byte - einfache Checksumme der Nutzbytes Ich glaube, ich mache es ähnlich wie WehOhWeh. Zusätzlich zu deinen Protokollüberlegungen benutze ich noch ein START- und STOPBYTE (gegebenenfalls noch eine ESCBYTE wenn keine Länge der Nutzdaten) Nach Empfang des STARTBYTE (z.B. 0xAA) wird alles bis zum Empfang des STOPBYTE (z.B. 0xAB) in einen Puffer geschrieben und dann ausgewertet. Ist die Checksumme korrekt geht das Paket zur Weiterverarbeitung.
Vielen Dank für die ausführlichen Antworten. WehOhWeh schrieb: > Mit jedem Interrupt werden in der ISR die empfangenen Bytes in den > RX-Buffer geschreieben und aus dem TX-Buffer in die UART geschrieben. > Ist ein Paket vollständig, wird ein Jobflag gesetzt. Ich habe es eben nochmal ausprobiert, die ISR wird von jedem empfangenen Byte erneut ausgelöst, d.h. ich schreibe bei jedem UART-Interrupt ein Byte ins RX-Buffer und zähle einen counter hoch. Um aber ein vollständiges Paket zu identifizieren muss ich doch wissen wie lang es ist. Dazu muss ich das zweite Byte prüfen. Wo findet diese Prüfung statt, in der ISR? Wenn ich nicht weiß wie lang meine Nachricht ist, kann ich ja nicht zu gegebenen Anlass das Job-Flag setzen. Oder ich arbeite mit statischen Nachrichtenlängen, was mir eine wenig die zukünftige Flexibilität nehmen würde. Volker SchK schrieb: > Nach Empfang des STARTBYTE (z.B. 0xAA) wird alles bis zum Empfang des > STOPBYTE (z.B. 0xAB) in einen Puffer geschrieben und dann ausgewertet. > Ist die Checksumme korrekt geht das Paket zur Weiterverarbeitung. Wo genau findet die Prüfung, ob ein Startbyte (z.B. 0xAA) empfangen wurde statt? In der ISR oder außerhalb? Vielen Dank und freundliche Grüße musicmiles
musicmiles schrieb: > Dazu muss ich das zweite Byte prüfen. Wo findet diese Prüfung > statt, in der ISR? Wenn ich nicht weiß wie lang meine Nachricht ist, > kann ich ja nicht zu gegebenen Anlass das Job-Flag setzen. Oder ich > arbeite mit statischen Nachrichtenlängen, was mir eine wenig die > zukünftige Flexibilität nehmen würde. Das muss, wie Du richtig erkannt hast, natürlich in der ISR passieren. Aber das ist kein Problem, da das nicht viel Programm ist und auf nichts gewartet wird. > Volker SchK schrieb: >> Nach Empfang des STARTBYTE (z.B. 0xAA) wird alles bis zum Empfang des >> STOPBYTE (z.B. 0xAB) in einen Puffer geschrieben und dann ausgewertet. >> Ist die Checksumme korrekt geht das Paket zur Weiterverarbeitung. > > Wo genau findet die Prüfung, ob ein Startbyte (z.B. 0xAA) empfangen > wurde statt? In der ISR oder außerhalb? Auch das muss in der ISR passieren. Solange das Startbyte nicht empfangen wurde, wird das empfangene Byte verworfen und der Zeiger des Buffers bleibt am Anfang. Was auch noch fehlt, ist ein Time-Out - falls die Übertragung unterbrochen wurde oder falsch gestartet ist. Am Besten lässt sich das Ganze mit einer Zustandsmachine steuern - in der ISR! Siehe http://www.mikrocontroller.net/articles/Statemachine Gruß Dietrich
:
Bearbeitet durch User
Dietrich L. schrieb: >> Wo genau findet die Prüfung, ob ein Startbyte (z.B. 0xAA) empfangen >> wurde statt? In der ISR oder außerhalb? > > Auch das muss in der ISR passieren. Solange das Startbyte nicht > empfangen wurde, wird das empfangene Byte verworfen und der Zeiger des > Buffers bleibt am Anfang. Ich habe es anders gemacht. Bei mir wird im Interrupt nur ein Puffer gefüllt, der dann in der Hauptschleife wieder abgearbeitet wird. Dann puffert man natürlich gegebenenfalls unnötige Bytes, aber dafür muss der Interrupt vom Protokoll nichts wissen. Ich habe sozusagen zwei Puffer. Einen für den Empfänger (Erweiterung des HW FIFOs) und einen für das "Empfangspaket" -> Es gibt bestimmt mehrere Lösungen die nicht schlecht sind ;-) Dietrich L. schrieb: > Was auch noch fehlt, ist ein Time-Out - falls die Übertragung > unterbrochen wurde Ist sicher auch noch interessant. Habe ich aber bisher noch nie implementiert.
:
Bearbeitet durch User
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.