Warteschlangen in FreeRTOS

Ich habe mehrere Aufgaben, die alle auf einen Bildschirm schreiben. Offensichtlich ohne zu steuern, wer auf den Bildschirm schreiben kann, wenn ich Probleme habe. Ich dachte, der einfachste Weg, dies zu tun, wäre das Anstehen.

Ich habe eine globale QueueHandle. In meiner int main(void)Funktion erstelle ich eine Warteschlange der Größe 10 (groß genug für meine Bedürfnisse) mit einer Elementgröße, die meiner entspricht und structalle Daten enthält.

struct screenData {
    uint8_t string;
    uint8_t line;
} data;

In den Aufgaben, die auf den Bildschirm schreiben müssen, senden sie an die Warteschlange:

struct screenData * toSend;
data.string = "TEST";
data.line = 0;

toSend = &data;

xQueueSend ( xQueue, ( void * ) &toSend , xTicksToWait );

In der Aufgabe, die den Bildschirm aktualisiert, liest sie aus der Warteschlange und bringt sie auf den Bildschirm:

struct screenData * data;
xQueueReceive( xQueue, &( data ), xTicksToWait );

Ich greife dann so auf die Daten zu: data->string;etc ...

Soweit ich es verstehe, übergibt dies jedoch die Adresse der Struktur. Das heißt, wenn ich aktualisiere data, sind die in der Struktur enthaltenen Daten unterschiedlich.

Was ich tun möchte, ist eine Warteschlange zu haben, die ich hinzufügen kann, wo die gesendeten Daten vom Typ sind screenData, und es liest jeden Eingang, screenDataum eine Nachricht auf dem Bildschirm anzuzeigen.

Sollte ich im Wesentlichen nur die gesamte Struktur an die Warteschlange senden? In welchem ​​Fall ist dies die beste Verwendung der Warteschlange? Oder gibt es eine bessere Möglichkeit, Daten zu puffern?

Danke

"uint8_t string;", sollte das nicht "uint8_t *string;" sein?
Yup - habe diesen Tippfehler nicht bemerkt. Im Originalcode ist es richtig.

Antworten (3)

Es gibt zwei grundlegende Ansätze, die in den Sinn kommen.

1) Verwenden Sie eine Warteschlange , wie im OP beschrieben.

Laut der FreeRTOS-API-Dokumentation für xQueueSend werden alle Daten aus Ihrer screenDataStruktur in die Warteschlange kopiert (siehe Beschreibung für das pvItemToQueueArgument: „Ein Zeiger auf das Element, das in die Warteschlange gestellt werden soll. Die Größe der Elemente der Warteschlange wird halten wurde definiert, als die Warteschlange erstellt wurde, also werden diese vielen Bytes von pvItemToQueue in den Warteschlangenspeicherbereich kopiert." Dies bedeutet, dass Ihre Annahme falsch ist. Nachdem die Codeausführung vom Aufruf zurückkehrt xQueueSend, können Sie ändern, dataohne befürchten zu müssen, was zu überschreiben wurde nur in die Warteschlange gestellt.

2) Verwenden Sie einen Semaphor oder Mutex für gegenseitigen Ausschluss .

(Lesen Sie mehr über die FreeRTOS-Mutex-Implementierung in der API-Dokumentation von xSemaphoreCreateMutex ), um den Zugriff auf die Anzeige zwischen verschiedenen Aufgaben zu synchronisieren.

Die wichtigsten Kompromisse, die bei der Wahl zwischen einer Warteschlange oder einem Mutex zu berücksichtigen sind, lauten wie folgt:

Die Verwendung einer Warteschlange puffert die Daten und blockiert die Ausführung von Aufgaben nicht, es sei denn, Ihre Warteschlange wird voll, erfordert jedoch, dass Sie mehr Speicher zuweisen (in diesem Fall 10 * sizeof(screenData)).

Die Verwendung eines Mutex erfordert keine Speicherzuweisung, blockiert jedoch die Ausführung von Aufgaben, wenn mehr als einer gleichzeitig versucht, auf die Anzeige zuzugreifen.

Ich glaube, Ihr Verständnis ist falsch. Der FreeRTOS-Warteschlangendienst erstellt eine Kopie der von Ihnen gesendeten Daten. Die Größe eines Warteschlangenelements wird beim Erstellen der Warteschlange definiert. xQueueSend empfängt einen Zeiger auf das Element, erstellt jedoch eine Kopie dieses Elements – es stellt den Zeiger nicht in die Warteschlange. Wenn also die Aufgabe, die xQueueSend aufgerufen hat, das ursprüngliche Element nachträglich ändert, werden diese Änderungen nicht in der Kopie widergespiegelt, die in die Warteschlange gestellt wurde.

Hier ist die Beschreibung der FreeRTOS-Warteschlange

Zu Ihren Fragen: Ja, die Zusendung einer Kopie der screenData erscheint sinnvoll. Ich glaube, Ihr Beispielcode ist falsch. Wenn Sie beabsichtigen, ein screenData-Element in die Warteschlange einzufügen, und Sie die Warteschlange mit einer Elementgröße gleich sizeof(screenData) erstellt haben, sollten Sie die Adresse von dataan xQueueSend übergeben. Mit anderen Worten, Sie brauchen nicht toSendund sollten xQueueSend so aufrufen:

xQueueSend ( xQueue, ( void * ) &data , xTicksToWait );

Außerdem sollten Sie in der Funktion, die xQueueReceive aufruft, dataals screenData-Typ und nicht als Zeiger auf screenData deklarieren. Übergeben Sie dann die Adresse der Daten an xQueueReceive.

Wenn ich also in derselben Aufgabe in zwei verschiedene Zeilen schreiben wollte, kann ich verwenden data, aufrufen xQueueSendund dann ändern data(die Zeile/Zeichenfolge ändern) und aufrufen xQueueSend. Am anderen Ende sollen die beiden Queue-Items unterschiedliche Daten haben?
Ja, die FreeRTOS-Dokumentation ist eindeutig: „Nachrichten werden per Kopie durch Warteschlangen gesendet, was bedeutet, dass die Daten selbst in die Warteschlange kopiert werden, anstatt dass die Warteschlange immer nur einen Verweis auf die Daten speichert.“

im Allgemeinen der beste Weg, um mehrere Prozesse zu handhaben, die auf den Bildschirm schreiben

ist, einen dedizierten Prozess zu haben, der der einzige ist, der tatsächlich in sysout schreibt.

Alle anderen Prozesse verwenden ein Messaging-System wie 'msgsnd()' zum Passieren

Nachrichten an den einen Prozess, der tatsächlich auf den Bildschirm schreibt.

Das Betriebssystem stellt die Nachrichten in eine Warteschlange, die von dem einen Prozess gelesen werden sollen, der tatsächlich auf den Bildschirm schreibt.

Wenn diese Warteschlange voll wird, wird der Sendeprozess blockiert, bis in der Warteschlange Platz ist.

Dies führt normalerweise dazu, dass die Benutzerprozesse keine Nachrichtenwarteschlange für den Bildschirm unterhalten müssen

Das ist im Wesentlichen das, was ich oben erklärt habe. Ich brauchte jedoch eine Klärung darüber, wie Daten in die Warteschlange gestellt werden!