- Διαγραφή μιας εργασίας στο FreeRTOS Arduino
- Τι είναι η ουρά στο FreeRTOS;
- Δημιουργία ουράς στο FreeRTOS
- Διάγραμμα κυκλώματος
- Εφαρμογή της ουράς FreeRTOS στο Arduino IDE
Στο προηγούμενο σεμινάριο, παρουσιάσαμε το FreeRTOS στο Arduino Uno και δημιουργήσαμε μια εργασία για το LED που αναβοσβήνει. Τώρα, σε αυτό το σεμινάριο, θα διερευνήσουμε περισσότερο τις προηγμένες έννοιες των RTOS API και θα μάθουμε για την επικοινωνία μεταξύ διαφορετικών εργασιών. Εδώ μαθαίνουμε επίσης για την ουρά για τη μεταφορά δεδομένων από τη μία εργασία στην άλλη και για να δείξουμε τη λειτουργία των API ουράς με διασύνδεση 16x2 LCD και LDR με το Arduino Uno.
Πριν συζητήσουμε σχετικά με τις ουρές, ας δούμε ένα ακόμη FreeRTOS API που είναι χρήσιμο στη διαγραφή των εργασιών όταν τελειώσει με την εργασία που έχει ανατεθεί. Μερικές φορές η εργασία πρέπει να διαγραφεί για να ελευθερωθεί η εκχωρημένη μνήμη. Σε συνέχεια του προηγούμενου σεμιναρίου, θα χρησιμοποιήσουμε τη συνάρτηση API vTaskDelete () στον ίδιο κώδικα για να διαγράψουμε μία από τις εργασίες. Μια εργασία μπορεί να χρησιμοποιήσει τη συνάρτηση API vTaskDelete () για να διαγραφεί, ή οποιαδήποτε άλλη εργασία.
Για να χρησιμοποιήσετε αυτό το API, πρέπει να διαμορφώσετε το αρχείο FreeRTOSConfig.h . Αυτό το αρχείο χρησιμοποιείται για την προσαρμογή του FreeRTOS σύμφωνα με την εφαρμογή. Χρησιμοποιείται για την αλλαγή των αλγορίθμων προγραμματισμού και πολλών άλλων παραμέτρων. Το αρχείο βρίσκεται στον κατάλογο Arduino που είναι γενικά διαθέσιμος στο φάκελο Documents του υπολογιστή σας. Στην περίπτωσή μου, είναι διαθέσιμο στο \ Documents \ Arduino \ libraries \ FreeRTOS \ src όπως φαίνεται παρακάτω.
Τώρα, ανοίξτε αυτό το αρχείο χρησιμοποιώντας οποιοδήποτε πρόγραμμα επεξεργασίας κειμένου και αναζητήστε το #define INCLUDE_vTaskDelete και βεβαιωθείτε ότι η τιμή του είναι «1» (1 σημαίνει ενεργοποίηση και 0 σημαίνει απενεργοποίηση). Είναι 1 από προεπιλογή, αλλά το ελέγχει.
Θα χρησιμοποιούμε αυτό το αρχείο ρυθμίσεων συχνά στα επόμενα σεμινάρια για τον καθορισμό των παραμέτρων.
Τώρα, ας δούμε πώς να διαγράψετε μια εργασία.
Διαγραφή μιας εργασίας στο FreeRTOS Arduino
Για να διαγράψετε μια εργασία, πρέπει να χρησιμοποιήσουμε τη συνάρτηση API vTaskDelete (). Χρειάζεται μόνο ένα επιχείρημα.
vTaskDelete (TaskHandle_t pxTaskToDelete);
pxTaskToDelete: Είναι η λαβή της εργασίας που πρέπει να διαγραφεί. Είναι το ίδιο με το 6 ου επιχείρημα της xTaskCreate () API. Στο προηγούμενο σεμινάριο, αυτό το όρισμα έχει οριστεί ως NULL, αλλά μπορείτε να μεταβιβάσετε τη διεύθυνση του περιεχομένου της εργασίας χρησιμοποιώντας οποιοδήποτε όνομα. Ας πούμε αν θέλετε να ορίσετε τη λαβή εργασιών για το Task2 που δηλώνεται ως
TaskHandle_t any_name; Παράδειγμα: TaskHandle_t xTask2Handle;
Τώρα, σε vTaskCreate () API ρυθμιστεί 6 ου επιχείρημα ως
xTaskCreate (TaskBlink2, "task2", 128, NULL, 1, & xTask2Handle);
Μπορείτε να αποκτήσετε πρόσβαση στο περιεχόμενο αυτής της εργασίας χρησιμοποιώντας τη λαβή που έχετε δώσει.
Επίσης, μια εργασία μπορεί να διαγραφεί μεταβιβάζοντας το NULL αντί για μια έγκυρη λαβή εργασιών.
Εάν θέλουμε να διαγράψουμε την Εργασία 3 από την ίδια την εργασία 3, πρέπει να γράψετε vTaskDelete (NULL). μέσα στη συνάρτηση Task3, αλλά αν θέλετε να διαγράψετε την εργασία 3 από την εργασία 2, τότε γράψτε vTaskDelete (xTask3Handle); μέσα στη συνάρτηση task2.
Στον προηγούμενο κώδικα εκμάθησης, για να διαγράψετε το Task2 από το ίδιο το task2, απλώς προσθέστε το vTaskDelete (NULL). in void TaskBlink2 (void * pvParameters) συνάρτηση. Τότε η παραπάνω συνάρτηση θα μοιάζει με αυτήν
void TaskBlink2 (void * pvParameters) { Serial.println ("Η εργασία 2 εκτελείται και πρόκειται να διαγραφεί"); vTaskDelete (NULL); pinMode (7, ΕΞΟΔΟΣ); ενώ (1) { digitalWrite (7, HIGH); vTaskDelay (300 / portTICK_PERIOD_MS); digitalWrite (7, LOW)? vTaskDelay (300 / portTICK_PERIOD_MS)? } }
Τώρα, ανεβάστε τον κωδικό και παρατηρήστε τις λυχνίες LED και τη σειριακή οθόνη. Θα δείτε ότι το δεύτερο LED δεν αναβοσβήνει τώρα και το task2 διαγράφεται αφού συναντήσετε το API διαγραφής.
Έτσι, αυτό το API μπορεί να χρησιμοποιηθεί για να σταματήσει η εκτέλεση της συγκεκριμένης εργασίας.
Τώρα, ας ξεκινήσουμε με την ουρά.
Τι είναι η ουρά στο FreeRTOS;
Η ουρά είναι η δομή δεδομένων που μπορεί να κρατήσει τον πεπερασμένο αριθμό στοιχείων σταθερού μεγέθους και λειτουργεί στο σχήμα FIFO (First-in First-out). Οι ουρές παρέχουν έναν μηχανισμό επικοινωνίας task-to-task, task-to-interrupt και interrupt-to-task.
Ο μέγιστος αριθμός στοιχείων που μπορεί να κρατήσει η ουρά ονομάζεται «μήκος». Τόσο το μήκος όσο και το μέγεθος κάθε στοιχείου ρυθμίζονται κατά τη δημιουργία της ουράς.
Ένα παράδειγμα του τρόπου με τον οποίο χρησιμοποιείται η ουρά για μεταφορά δεδομένων περιγράφεται καλά στην τεκμηρίωση του FreeRTOS που μπορείτε να βρείτε εδώ Μπορείτε εύκολα να καταλάβετε το δεδομένο παράδειγμα.
Αφού κατανοήσουμε τις ουρές, ας προσπαθήσουμε να κατανοήσουμε τη διαδικασία δημιουργίας μιας ουράς και να προσπαθήσουμε να την εφαρμόσουμε στον κώδικα FreeRTOS.
Δημιουργία ουράς στο FreeRTOS
Πρώτα, περιγράψτε τη δήλωση προβλήματος που πρόκειται να εφαρμοστεί με τη βοήθεια της ουράς FreeRTOS και του Arduino Uno.
Θέλουμε να εκτυπώσουμε την τιμή του αισθητήρα LDR σε οθόνη LCD 16 * 2. Υπάρχουν λοιπόν δύο εργασίες τώρα
- Η Εργασία 1 λαμβάνει αναλογικές τιμές LDR.
- Το Task2 εκτυπώνει την αναλογική τιμή σε LCD.
Λοιπόν, εδώ η ουρά παίζει το ρόλο της επειδή στέλνει τα δεδομένα που δημιουργούνται από το task1 στο task2. Στην εργασία 1, θα στείλουμε αναλογική τιμή στην ουρά και στην εργασία 2, θα την λάβουμε από την ουρά.
Υπάρχουν τρεις λειτουργίες για εργασία με ουρές
- Δημιουργία ουράς
- Αποστολή δεδομένων στην ουρά
- Λήψη δεδομένων από την ουρά
Για τη δημιουργία ουράς, χρησιμοποιήστε το API συνάρτησης xQueueCreate (). Χρειάζονται δύο επιχειρήματα.
xQueueCreate (UBaseType_t uxQueueLength, UBaseType_t uxItemSize);
uxQueueLength: Ο μέγιστος αριθμός στοιχείων που μπορεί να διατηρήσει η ουρά που δημιουργείται ανά πάσα στιγμή.
uxItemSize: Το μέγεθος σε byte κάθε στοιχείου δεδομένων που μπορεί να αποθηκευτεί στην ουρά.
Εάν αυτή η συνάρτηση επιστρέψει NULL τότε η ουρά δεν δημιουργείται λόγω ανεπαρκούς μνήμης και αν επιστρέψει μια τιμή μη NULL, η ουρά δημιουργείται επιτυχώς. Αποθηκεύστε αυτήν την τιμή επιστροφής σε μια μεταβλητή για να τη χρησιμοποιήσετε ως λαβή για πρόσβαση στην ουρά όπως φαίνεται παρακάτω.
QueueHandle_t ουρά1; queue1 = xQueueCreate (4, sizeof (int));
Αυτό θα δημιουργήσει μια ουρά 4 στοιχείων στη μνήμη σωρού του μεγέθους int (2 byte κάθε μπλοκ) και θα αποθηκεύσει την τιμή επιστροφής στη μεταβλητή της λαβής ουράς1 .
2. Αποστολή δεδομένων στην ουρά στο FreeRTOS
Για να στείλετε τις τιμές στην ουρά, το FreeRTOS διαθέτει 2 παραλλαγές API για το σκοπό αυτό.
- xQueueSendToBack (): Χρησιμοποιείται για την αποστολή δεδομένων στο πίσω μέρος (ουρά) μιας ουράς.
- xQueueSendToFront (): Χρησιμοποιείται για την αποστολή δεδομένων στο μπροστινό μέρος (κεφάλι) μιας ουράς.
Τώρα , το xQueueSend () είναι ισοδύναμο με και ακριβώς το ίδιο με το xQueueSendToBack ().
Όλα αυτά τα API χρειάζονται 3 ορίσματα.
xQueueSendToBack (QueueHandle_t xQueue, const void * pvItemToQueue, TickType_t xTicksToWait);
xQueue: Η λαβή της ουράς στην οποία αποστέλλονται τα δεδομένα (γραπτή). Αυτή η μεταβλητή είναι η ίδια με την οποία χρησιμοποιείται για την αποθήκευση της τιμής επιστροφής του API xQueueCreate.
pvItemToQueue: Ένας δείκτης στα δεδομένα που θα αντιγραφούν στην ουρά.
xTicksToWait: Ο μέγιστος χρόνος που πρέπει να παραμείνει η εργασία στην κατάσταση αποκλεισμού για να περιμένετε να διατεθεί χώρος στην ουρά
Η ρύθμιση του xTicksToWait στη θύραMAX_DELAY θα προκαλέσει την αναμονή της εργασίας επ 'αόριστον (χωρίς χρονικό όριο), με την προϋπόθεση ότι το INCLUDE_vTaskSuspend έχει οριστεί σε 1 στο FreeRTOSConfig. Αλλιώς μπορείτε να χρησιμοποιήσετε τη μακροεντολή pdMS_TO_TICKS () για να μετατρέψετε μια ώρα που καθορίζεται σε χιλιοστά του δευτερολέπτου σε μια ώρα που καθορίζεται σε τσιμπούρια.
3. Λήψη δεδομένων από την ουρά στο FreeRTOS
Για τη λήψη (ανάγνωση) ενός στοιχείου από μια ουρά, χρησιμοποιείται το xQueueReceive (). Το στοιχείο που λαμβάνεται καταργείται από την ουρά.
Αυτό το API λαμβάνει επίσης τρία ορίσματα.
xQueueReceive (QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait);
Το πρώτο και το τρίτο όρισμα είναι τα ίδια με την αποστολή API. Μόνο το δεύτερο επιχείρημα είναι διαφορετικό.
const pvBuffer: Ένας δείκτης στη μνήμη στην οποία θα αντιγραφούν τα ληφθέντα δεδομένα.
Ελπίζω να καταλάβατε τα τρία API. Τώρα, θα εφαρμόσουμε αυτά τα API στο Arduino IDE και θα προσπαθήσουμε να λύσουμε τη δήλωση προβλήματος που έχουμε περιγράψει παραπάνω.
Διάγραμμα κυκλώματος
Έτσι φαίνεται στο breadboard:
Εφαρμογή της ουράς FreeRTOS στο Arduino IDE
Ας αρχίσουμε να γράφουμε κώδικα για την εφαρμογή μας.
1. Πρώτα, ανοίξτε το Arduino IDE και συμπεριλάβετε το αρχείο κεφαλίδας Arduino_FreeRTOS.h . Τώρα, εάν χρησιμοποιηθεί οποιοδήποτε αντικείμενο πυρήνα όπως η ουρά, τότε συμπεριλάβετε το αρχείο κεφαλίδας του. Καθώς χρησιμοποιούμε LCD 16 * 2, συμπεριλάβετε και τη βιβλιοθήκη.
# συμπερίληψη # συμπερίληψη
2. Αρχικοποιήστε μια λαβή ουράς για να αποθηκεύσετε τα περιεχόμενα της ουράς. Επίσης, αρχικοποιήστε τους αριθμούς ακίδων LCD.
QueueHandle_t queue_1; LiquidCrystal lcd (7, 8, 9, 10, 11, 12);
3. Στην κενή ρύθμιση (), αρχικοποιήστε την οθόνη LCD και την σειριακή οθόνη με ρυθμό baud 9600. Δημιουργήστε μια ουρά και δύο εργασίες χρησιμοποιώντας τα αντίστοιχα API. Εδώ θα δημιουργήσουμε μια ουρά μεγέθους 4 με ακέραιο τύπο. Δημιουργήστε μια εργασία με ίσες προτεραιότητες και αργότερα προσπαθήστε να παίξετε με αυτόν τον αριθμό. Τέλος, ξεκινήστε τον προγραμματιστή όπως φαίνεται παρακάτω.
άκυρη ρύθμιση () { Serial.begin (9600); lcd.begin (16, 2); queue_1 = xQueueCreate (4, sizeof (int)); if (queue_1 == NULL) { Serial.println ("Δεν είναι δυνατή η δημιουργία ουράς"); } xTaskCreate (TaskDisplay, "Display_task", 128, NULL, 1, NULL); xTaskCreate (TaskLDR, "LDR_task", 128, NULL, 1, NULL); vTaskStartScheduler (); }
4. Τώρα, κάντε δύο λειτουργίες TaskDisplay και TaskLDR . Στη συνάρτηση TaskLDR , διαβάστε την αναλογική ακίδα A0 σε μια μεταβλητή καθώς έχουμε LDR συνδεδεμένο με τον ακροδέκτη A0 του Arduino UNO. Τώρα στείλτε την τιμή που είναι αποθηκευμένη στη μεταβλητή μεταβιβάζοντάς την στο API xQueueSend και στείλτε την εργασία για την κατάσταση αποκλεισμού μετά από 1 δευτερόλεπτο χρησιμοποιώντας το API vTaskDelay () όπως φαίνεται παρακάτω.
void TaskLDR (void * pvParameters) { int current_intensity; ενώ (1) { Serial.println ("Task1"); current_intensity = analogRead (A0); Serial.println (current_intensity); xQueueSend (queue_1, & current_intensity, portMAX_DELAY); vTaskDelay (1000 / portTICK_PERIOD_MS); } }
5. Ομοίως, κάντε μια συνάρτηση για το TaskDisplay και λάβετε τις τιμές σε μια μεταβλητή που μεταφέρεται στη συνάρτηση xQueueReceive Επίσης, το xQueueReceive () επιστρέφει pdPASS εάν τα δεδομένα μπορούν να ληφθούν επιτυχώς από την ουρά και επιστρέφει errQUEUE_EMPTY εάν μια ουρά είναι κενή.
Τώρα, εμφανίστε τις τιμές στην οθόνη LCD χρησιμοποιώντας τη λειτουργία lcd.print () .
void TaskDisplay (void * pvParameters) { int ένταση = 0; ενώ (1) { Serial.println ("Task2"); if (xQueueReceive (queue_1, & intensity, portMAX_DELAY) == pdPASS) { lcd.clear (); lcd.setCursor (0, 0); lcd.print ("Ένταση:"); lcd.setCursor (11, 0); lcd.print (ένταση); } } }
Αυτό είναι. Ολοκληρώσαμε το κωδικοποιητικό μέρος της εφαρμογής Queue. Ο πλήρης κώδικας με ένα λειτουργικό βίντεο βρίσκεται στο τέλος.
Τώρα, συνδέστε την οθόνη LCD και LDR με το Arduino UNO σύμφωνα με το διάγραμμα κυκλώματος ανεβάστε τον κωδικό. Ανοίξτε τη σειριακή οθόνη και παρατηρήστε τις εργασίες. Θα δείτε ότι οι εργασίες αλλάζουν και οι τιμές LDR αλλάζουν ανάλογα με την ένταση του φωτός.
ΣΗΜΕΙΩΣΗ: Οι περισσότερες βιβλιοθήκες που έχουν δημιουργηθεί για διαφορετικούς αισθητήρες δεν υποστηρίζονται από τον πυρήνα του FreeRTOS λόγω καθυστέρησης της εφαρμογής της λειτουργίας στις βιβλιοθήκες. Η καθυστέρηση κάνει τη CPU να σταματήσει εντελώς, επομένως, ο πυρήνας του FreeRTOS σταματά επίσης να λειτουργεί και ο κώδικας δεν θα εκτελεστεί περαιτέρω και αρχίζει να έχει κακή συμπεριφορά. Επομένως, πρέπει να κάνουμε τις βιβλιοθήκες καθυστερημένες για να συνεργαστούμε με το FreeRTOS.