- Xóa tác vụ trong FreeRTOS Arduino
- Hàng đợi trong FreeRTOS là gì?
- Tạo hàng đợi trong FreeRTOS
- Sơ đồ mạch
- Triển khai hàng đợi FreeRTOS trong Arduino IDE
Trong hướng dẫn trước, chúng tôi đã giới thiệu FreeRTOS trong Arduino Uno và tạo tác vụ cho đèn LED nhấp nháy. Bây giờ, trong hướng dẫn này, chúng ta sẽ đi sâu hơn vào các khái niệm trước về API RTOS và tìm hiểu về giao tiếp giữa các tác vụ khác nhau. Ở đây chúng ta cũng tìm hiểu về Hàng đợi để truyền dữ liệu từ tác vụ này sang tác vụ khác và chứng minh hoạt động của các API hàng đợi bằng cách giao tiếp LCD 16x2 và LDR với Arduino Uno.
Trước khi thảo luận về Hàng đợi, chúng ta hãy xem thêm một API FreeRTOS hữu ích trong việc xóa các tác vụ khi nó hoàn thành với công việc được giao. Đôi khi tác vụ cần được xóa để giải phóng bộ nhớ được phân bổ. Trong phần tiếp theo của hướng dẫn trước, chúng tôi sẽ sử dụng hàm vTaskDelete () API trong cùng một đoạn mã để xóa một trong các tác vụ. Một tác vụ có thể sử dụng hàm vTaskDelete () API để xóa chính nó hoặc bất kỳ tác vụ nào khác.
Để sử dụng API này, bạn phải định cấu hình tệp FreeRTOSConfig.h . Tệp này được sử dụng để điều chỉnh FreeRTOS theo ứng dụng. Nó được sử dụng để thay đổi các thuật toán lập lịch và nhiều thông số khác. Tệp có thể được tìm thấy trong Thư mục Arduino thường có sẵn trong thư mục Tài liệu trên PC của bạn. Trong trường hợp của tôi, nó có sẵn trong \ Documents \ Arduino \ library \ FreeRTOS \ src như hình dưới đây.
Bây giờ, mở tập tin này bằng bất kỳ soạn thảo văn bản và tìm kiếm các #define INCLUDE_vTaskDelete và chắc chắn giá trị của nó là '1' (1 có nghĩa là kích hoạt và 0 có nghĩa là vô hiệu hóa). Nó là 1 theo mặc định nhưng kiểm tra nó.
Chúng tôi sẽ sử dụng tệp cấu hình này thường xuyên trong các hướng dẫn tiếp theo để thiết lập các thông số.
Bây giờ, chúng ta hãy xem cách xóa một nhiệm vụ.
Xóa tác vụ trong FreeRTOS Arduino
Để xóa một tác vụ, chúng ta phải sử dụng hàm vTaskDelete () API. Nó chỉ cần một đối số.
vTaskDelete (TaskHandle_t pxTaskToDelete);
pxTaskToDelete: Nó là phần xử lý của tác vụ sẽ bị xóa. Nó giống như đối số thứ 6 của API xTaskCreate () . Trong hướng dẫn trước, đối số này được đặt là NULL nhưng bạn có thể chuyển địa chỉ của nội dung của nhiệm vụ bằng cách sử dụng bất kỳ tên nào. Giả sử nếu bạn muốn đặt task handle cho Task2 được khai báo là
TaskHandle_t any_name; Ví dụ: TaskHandle_t xTask2Handle;
Bây giờ, trong vTaskCreate () API, đặt đối số thứ 6 là
xTaskCreate (TaskBlink2, "task2", 128, NULL, 1, & xTask2Handle);
Nội dung của nhiệm vụ này hiện có thể được truy cập bằng cách sử dụng tay cầm do bạn cung cấp.
Ngoài ra, một tác vụ có thể tự xóa bằng cách chuyển NULL thay cho một xử lý tác vụ hợp lệ.
Nếu chúng ta muốn xóa Task 3 khỏi chính task 3, bạn cần viết vTaskDelete (NULL); bên trong hàm Task3 nhưng nếu bạn muốn xóa task 3 khỏi task 2 thì hãy viết vTaskDelete (xTask3Handle); bên trong hàm task2.
Trong mã hướng dẫn trước, để xóa Task2 khỏi chính task2, chỉ cần thêm vTaskDelete (NULL); trong hàm void TaskBlink2 (void * pvParameters) . Khi đó hàm trên sẽ như thế này
void TaskBlink2 (void * pvParameters) { Serial.println (“Task2 đang chạy và sắp xóa”); vTaskDelete (NULL); pinMode (7, OUTPUT); while (1) { digitalWrite (7, HIGH); vTaskDelay (300 / portTICK_PERIOD_MS); digitalWrite (7, LOW); vTaskDelay (300 / portTICK_PERIOD_MS); } }
Bây giờ, tải lên mã và quan sát các đèn LED và màn hình nối tiếp. Bạn sẽ thấy rằng đèn LED thứ hai hiện không nhấp nháy và task2 bị xóa sau khi gặp API xóa.
Vì vậy, API này có thể được sử dụng để dừng việc thực thi tác vụ cụ thể.
Bây giờ, hãy bắt đầu với Hàng đợi.
Hàng đợi trong FreeRTOS là gì?
Hàng đợi là cấu trúc dữ liệu có thể chứa số lượng hữu hạn các phần tử có kích thước cố định và nó được vận hành trong lược đồ FIFO (First-in First-out). Hàng đợi cung cấp cơ chế giao tiếp giữa nhiệm vụ với tác vụ, tác vụ để ngắt và ngắt giữa tác vụ.
Số lượng phần tử tối đa mà hàng đợi có thể chứa được gọi là "độ dài" của nó. Cả chiều dài và kích thước của mỗi phần tử đều được đặt khi hàng đợi được tạo.
Ví dụ về cách hàng đợi được sử dụng để truyền dữ liệu được minh họa rõ ràng trong tài liệu FreeRTOS có thể tìm thấy tại đây. Bạn có thể dễ dàng hiểu ví dụ đã cho.
Các bác sĩ cho biết thêm:Sau khi hiểu Hàng đợi, hãy cố gắng hiểu quá trình tạo hàng đợi và cố gắng triển khai nó trong mã FreeRTOS của chúng ta.
Tạo hàng đợi trong FreeRTOS
Đầu tiên, mô tả câu lệnh vấn đề sẽ được thực hiện với sự trợ giúp của hàng đợi FreeRTOS và Arduino Uno.
Chúng tôi muốn in giá trị của cảm biến LDR trên màn hình LCD 16 * 2. Vì vậy, có hai nhiệm vụ bây giờ
- Task1 đang nhận các giá trị tương tự của LDR.
- Task2 đang in giá trị tương tự trên màn hình LCD.
Vì vậy, ở đây hàng đợi đóng vai trò của nó vì để gửi dữ liệu được tạo ra bởi task1 đến task2. Trong task1, chúng ta sẽ gửi giá trị tương tự đến hàng đợi và trong task2, chúng ta sẽ nhận nó từ hàng đợi.
Có ba chức năng để làm việc với hàng đợi
- Tạo hàng đợi
- Gửi dữ liệu đến hàng đợi
- Nhận dữ liệu từ Hàng đợi
Để tạo hàng đợi, hãy sử dụng hàm API xQueueCreate (). Nó cần hai đối số.
xQueueCreate (UBaseType_t uxQueueLength, UBaseType_t uxItemSize);
uxQueueLength: Số lượng mục tối đa mà hàng đợi đang được tạo có thể chứa bất kỳ lúc nào.
uxItemSize: Kích thước tính bằng byte của mỗi mục dữ liệu có thể được lưu trữ trong hàng đợi.
Nếu hàm này trả về NULL thì hàng đợi không được tạo do không đủ bộ nhớ và nếu nó trả về giá trị không phải NULL thì hàng đợi được tạo thành công. Lưu trữ giá trị trả về này vào một biến để sử dụng nó như một điều khiển để truy cập hàng đợi như hình dưới đây.
QueueHandle_t queue1; queue1 = xQueueCreate (4, sizeof (int));
Thao tác này sẽ tạo ra một hàng đợi 4 phần tử trong bộ nhớ heap có kích thước int (2 byte mỗi khối) và lưu giá trị trả về vào biến xử lý queue1 .
2. Gửi dữ liệu đến hàng đợi trong FreeRTOS
Để gửi các giá trị đến hàng đợi, FreeRTOS có 2 biến thể API cho mục đích này.
- xQueueSendToBack (): Được sử dụng để gửi dữ liệu đến phía sau (đuôi) của một hàng đợi.
- xQueueSendToFront (): Được sử dụng để gửi dữ liệu đến phía trước (đầu) của một hàng đợi.
Bây giờ , xQueueSend () tương đương và giống hệt như xQueueSendToBack ().
Tất cả các API này có 3 đối số.
xQueueSendToBack (QueueHandle_t xQueue, const void * pvItemToQueue, TickType_t xTicksToWait);
xQueue: Xử lý hàng đợi mà dữ liệu đang được gửi (ghi). Biến này giống như được sử dụng để lưu trữ giá trị trả về của API xQueueCreate.
pvItemToQueue: Một con trỏ tới dữ liệu được sao chép vào hàng đợi.
xTicksToWait: Khoảng thời gian tối đa mà nhiệm vụ nên duy trì ở trạng thái Bị chặn để đợi khoảng trống có sẵn trong hàng đợi.
Đặt xTicksToWait thành portMAX_DELAY sẽ khiến tác vụ chờ vô thời hạn (không hết thời gian chờ), miễn là INCLUDE_vTaskSuspend được đặt thành 1 trong FreeRTOSConfig.h khác bạn có thể sử dụng macro pdMS_TO_TICKS () để chuyển đổi thời gian được chỉ định bằng mili giây thành thời gian được chỉ định bằng tích tắc.
3. Nhận dữ liệu từ hàng đợi trong FreeRTOS
Để nhận (đọc) một mục từ hàng đợi, xQueueReceive () được sử dụng. Mục nhận được sẽ bị xóa khỏi hàng đợi.
API này cũng có ba đối số.
xQueueReceive (QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait);
Đối số thứ nhất và thứ ba giống như gửi API. Chỉ có lập luận thứ hai là khác nhau.
const pvBuffer: Một con trỏ tới bộ nhớ mà dữ liệu nhận được sẽ được sao chép vào.
Hy vọng bạn đã hiểu ba API. Bây giờ, chúng tôi sẽ triển khai các API này trong Arduino IDE và cố gắng giải quyết vấn đề mà chúng tôi đã mô tả ở trên.
Sơ đồ mạch
Đây là giao diện của nó trên breadboard:
Triển khai hàng đợi FreeRTOS trong Arduino IDE
Hãy bắt đầu viết mã cho ứng dụng của chúng tôi.
1. Đầu tiên, mở Arduino IDE và bao gồm tệp tiêu đề Arduino_FreeRTOS.h . Bây giờ, nếu bất kỳ đối tượng hạt nhân nào như hàng đợi được sử dụng thì hãy bao gồm tệp tiêu đề của nó. Vì chúng tôi đang sử dụng LCD 16 * 2 nên hãy bao gồm cả thư viện cho nó.
#include #include
2. Khởi tạo một xử lý hàng đợi để lưu trữ nội dung của hàng đợi. Ngoài ra, khởi tạo số pin LCD.
QueueHandle_t hàng đợi_1; Màn hình LCD LiquidCrystal (7, 8, 9, 10, 11, 12);
3. Trong void setup (), khởi tạo màn hình LCD và màn hình nối tiếp với tốc độ truyền 9600. Tạo một hàng đợi và hai tác vụ bằng cách sử dụng các API tương ứng. Ở đây chúng ta sẽ tạo một hàng đợi có kích thước 4 với kiểu số nguyên. Tạo một nhiệm vụ với mức độ ưu tiên như nhau và sau đó hãy thử chơi với số này. Cuối cùng, khởi động trình lên lịch như hình bên dưới.
void setup () { Serial.begin (9600); lcd.begin (16, 2); queue_1 = xQueueCreate (4, sizeof (int)); if (queue_1 == NULL) { Serial.println ("Không thể tạo hàng đợi"); } xTaskCreate (TaskDisplay, "Display_task", 128, NULL, 1, NULL); xTaskCreate (TaskLDR, "LDR_task", 128, NULL, 1, NULL); vTaskStartScheduler (); }
4. Bây giờ, hãy thực hiện hai chức năng TaskDisplay và TaskLDR . Trong chức năng TaskLDR , đọc chân A0 tương tự trong một biến khi chúng ta có LDR được kết nối với chân A0 của Arduino UNO. Bây giờ hãy gửi giá trị được lưu trữ trong biến bằng cách chuyển nó trong API xQueueSend và gửi tác vụ đến trạng thái khối sau 1 giây bằng vTaskDelay () API như hình bên dưới.
void TaskLDR (void * pvParameters) { int current_intensity; while (1) { Serial.println ("Task1"); current_intensity = analogRead (A0); Serial.println (cường độ hiện tại); xQueueSend (queue_1, & current_intensity, portMAX_DELAY); vTaskDelay (1000 / portTICK_PERIOD_MS); } }
5. Tương tự, tạo một hàm cho TaskDisplay và nhận các giá trị trong một biến được chuyển đến hàm xQueueReceive . Ngoài ra, xQueueReceive () trả về pdPASS nếu dữ liệu có thể được nhận thành công từ hàng đợi và trả về errQUEUE_EMPTY nếu hàng đợi trống.
Bây giờ, hiển thị các giá trị ra màn hình LCD bằng hàm lcd.print () .
void TaskDisplay (void * pvParameters) { int Cường độ = 0; while (1) { Serial.println ("Task2"); if (xQueueReceive (queue_1, & Cường độ, portMAX_DELAY) == pdPASS) { lcd.clear (); lcd.setCursor (0, 0); lcd.print ("Cường độ:"); lcd.setCursor (11, 0); lcd.print (cường độ); } } }
Đó là nó. Chúng ta đã hoàn thành phần viết mã của việc triển khai Hàng đợi. Mã hoàn chỉnh với một Video đang hoạt động có thể được tìm thấy ở cuối.
Bây giờ, kết nối LCD và LDR với Arduino UNO theo sơ đồ mạch tải lên mã. Mở màn hình nối tiếp và quan sát các tác vụ. Bạn sẽ thấy các tác vụ đang chuyển đổi và giá trị LDR đang thay đổi theo cường độ ánh sáng.
LƯU Ý: Hầu hết các thư viện được tạo cho các cảm biến khác nhau không được hạt nhân FreeRTOS hỗ trợ do triển khai chức năng bên trong các thư viện chậm trễ. Độ trễ làm cho CPU dừng hoàn toàn, do đó, hạt nhân FreeRTOS cũng ngừng hoạt động và mã sẽ không thực thi thêm và nó bắt đầu hoạt động sai. Vì vậy, chúng ta phải làm cho các thư viện hoạt động với FreeRTOS một cách dễ dàng.