- vừa được xem lúc

Message Queue: Khám Phá Bí Mật Giao Tiếp Giữa Các Task Trong FreeRTOS

0 0 1

Người đăng: delinux

Theo Viblo Asia

Giới thiệu nhanh

Trong phần trước, chúng ta đã tìm hiểu về Task trong FreeRTOS – những “nhân viên” trong nhà máy phần mềm, mỗi task đảm nhận một nhiệm vụ cụ thể, chạy độc lập theo lịch của Scheduler. Tuy nhiên, một hệ thống không thể hoạt động hiệu quả nếu mỗi thành phần chỉ làm việc một cách cô lập. Các task cần giao tiếp – chia sẻ dữ liệu, ra lệnh, gửi tín hiệu... và đó chính là lúc Queue xuất hiện.


1. Queue trong FreeRTOS là gì?

Trong FreeRTOS, Queue là một cơ chế IPC (Inter-Process Communication) kiểu FIFO (First In First Out), cho phép truyền dữ liệu an toàn giữa các task, hoặc giữa ISR (Interrupt Service Routine) và task.

Hãy tưởng tượng:

  • Task A là một bộ thu tín hiệu từ cảm biến.
  • Task B là một bộ xử lý dữ liệu.
  • Thay vì chia sẻ trực tiếp biến toàn cục (rất nguy hiểm!), Task A chỉ việc “xếp hàng” dữ liệu vào queue, và Task B lấy dữ liệu ra khi đến lượt.

2. Cách hoạt động của Queue

2.1 Tạo queue

Bạn cần tạo một queue trước khi dùng:

QueueHandle_t xQueue;
xQueue = xQueueCreate(10, sizeof(int));
  • 10: số lượng phần tử tối đa trong queue.
  • sizeof(int): kích thước mỗi phần tử (ví dụ: kiểu int).

2.2 Gửi dữ liệu vào queue

Từ task:

xQueueSend(xQueue, &value, portMAX_DELAY);

Từ ISR:

BaseType_t xHigherPriorityTaskWoken = pdFALSE;
xQueueSendFromISR(xQueue, &value, &xHigherPriorityTaskWoken);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);

2.3 Nhận dữ liệu từ queue

int value;
xQueueReceive(xQueue, &value, portMAX_DELAY);

3. Queue hoạt động như thế nào bên trong?

Khi một task gọi xQueueSend, dữ liệu được copy vào một buffer vòng (circular buffer) bên trong queue. Một task khác gọi xQueueReceive sẽ nhận phần tử đầu tiên theo thứ tự FIFO.

Nếu queue rỗng? Task sẽ bị block cho đến khi có dữ liệu (nếu dùng portMAX_DELAY) hoặc timeout.

Nếu queue đầy? Task gửi sẽ bị block hoặc trả về lỗi tùy cấu hình.


4. Khi nào nên dùng Queue?

Tình huống Có nên dùng queue?
Task nhận dữ liệu từ cảm biến và task khác xử lý Rất phù hợp
ISR gửi tín hiệu trạng thái đơn giản Nên dùng Semaphore
Gửi tin nhắn dạng chuỗi Dùng Message Queue hoặc Stream Buffer
Truyền dữ liệu khối lớn Nên xem xét dùng buffer trực tiếp + signal

5. Ưu điểm của Queue trong FreeRTOS

  • An toàn luồng (thread-safe): Được bảo vệ bằng mutex nội bộ.
  • Linh hoạt: Có thể dùng cho ISR <-> task, task <-> task.
  • Tự động block: Task không phải chờ polling.
  • Rất nhẹ: Phù hợp với hệ thống nhúng nhỏ gọn.

6. Các loại queue trong FreeRTOS

Tên Mô tả Ví dụ
Queue thường FIFO cố định int, struct nhỏ
Queue set Chờ nhận từ nhiều queue Ví dụ 2 cảm biến gửi về
Stream Buffer Dòng byte liên tục UART, ADC
Message Buffer Tin nhắn có độ dài thay đổi Tin nhắn dạng TLV

7. Một số tình huống thực tế & ví dụ

7.1 Giao tiếp ISR với task

// ISR
void ADC_IRQHandler() { int val = read_adc(); BaseType_t xHigherPriorityTaskWoken = pdFALSE; xQueueSendFromISR(xQueue, &val, &xHigherPriorityTaskWoken); portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
// Task
void vAdcProcessingTask(void *pvParameters) { int val; while (1) { if (xQueueReceive(xQueue, &val, portMAX_DELAY)) { process(val); } }
}

7.2 Task gửi nhận dữ liệu lẫn nhau

// Task 1
xQueueSend(xQueue, &data, 0); // Task 2
if (xQueueReceive(xQueue, &rx_data, 0)) { // xử lý rx_data
}

Bình luận

Bài viết tương tự

- vừa được xem lúc

Giải mã AUTOSAR: Kiến trúc tiêu chuẩn ngành Automotive

Giới thiệu. AUTOSAR có vẻ khá xa lạ đối với người làm về công nghệ thông tin, nhưng đối với những bạn làm về Embedded System, đặc biệt là trong lĩnh vực Automotive, thì cũng.

0 0 24

- vừa được xem lúc

Từ khoá volatile trong lập trình C

Trong lập trình nhúng chắc hẵn bạn đã từng gặp phải tình huống khi chương trình C của bạn cho ra kết quả không đúng, mặc dù mã code có vẻ đúng? Một nguyên nhân có thể gây ra vấn đề này là việc tối ưu

0 0 24

- vừa được xem lúc

Giải mã AUTOSAR: Kiến trúc để đời ngành Automotive - Phần 2

Updating. Trong bài viết này, ta cùng tìm hiểu kỹ hơn về lớp trên cùng của kiến trúc, chính là lớp Application Layer (ASW).

0 0 20

- vừa được xem lúc

Con Trỏ Hàm - C/C++

Hàm Con Trỏ (Function Pointer) là gì. . Con trỏ tới hàm (A pointer to a function): Đây là biến lưu trữ địa chỉ hàm mà sau này có thể gọi bằng con trỏ này. .

0 0 18

- vừa được xem lúc

Cơ bản về WatchDog Timer trong hệ thống nhúng (Embedded System)

Khái Niệm. Trong hệ thống nhúng, a WatchDog Timer (Bộ đếm thời gian giám sát) là một thành phần hoặc tính năng của phần cứng được thiết kế để giám sát hoạt động của hệ thống và thực hiện hành động khắ

0 0 14

- vừa được xem lúc

Tối ưu hóa thời gian khởi động Nvidia Xavier

1. Vai trò.

0 0 11