You are on page 1of 9

Bài tập thực hành 5: Đồng bộ tác vụ

Nguyễn Tiến Quang – DT040145

TH5.1.a:
CODE:

#include <Arduino_FreeRTOS.h> // Khai báo thư viện FreeRTOS


#include "semphr.h" // Khai báo semphr.h để sử dụng Semaphore
#define LED 13 // Định nghĩa chân LED 13
SemaphoreHandle_t xBinarySemaphore; // Tạo Semaphore nhị phân
void setup()
{
Serial.begin(9600); // Giao tiếp serial với tốc độ 9600bps
pinMode(LED ,OUTPUT); // Cài đặt chân LED là OUTPUT
xBinarySemaphore = xSemaphoreCreateBinary();
xTaskCreate(LedOnTask, "LedON",100,NULL,1,NULL); // Tạo Task LedON
xTaskCreate(LedoffTask, "LedOFF", 100,NULL,1,NULL); // Tạo Task LedOFF
xSemaphoreGive(xBinarySemaphore);
}
void loop(){}
void LedOnTask(void *pvParameters)
{
while(1)
{
xSemaphoreTake(xBinarySemaphore,portMAX_DELAY); // Đợi và lấy Semaphore
Serial.println("Inside LedOnTask"); // In ra seiral Inside LedOnTask
digitalWrite(LED,LOW); // Bật đèn LED
xSemaphoreGive(xBinarySemaphore); // Trả Semaphore sau khi sử dụng xong
vTaskDelay(1);
}
}
void LedoffTask(void *pvParameters)
{
while(1)
{
xSemaphoreTake(xBinarySemaphore,portMAX_DELAY); // Đợi và lấy Semaphore
Serial.println("Inside LedffTask"); // In ra seiral Inside LedffTask
digitalWrite(LED,HIGH); // Tắt đèn LED
xSemaphoreGive(xBinarySemaphore); // Trả Semaphore sau khi sử dụng xong
vTaskDelay(1);
}
}

GIẢI THÍCH CODE:


- Chương trình bao gồm 2 tác vụ: 1 tác vụ bật đèn LED và 1 tác vụ sẽ tắt
đèn LED. Nhưng cả 2 nhiệm vụ không thể thực hiện cùng một lúc, vì cả
2 đều chia sẻ cùng mọt semaphore nhị phân. Cả 2 nhiệm vụ đều có cùng
mức độ ưu tiên. Do đó, bộ lập lịch FreeRTOS sẽ lên lịch cho cả 2 tác vụ
theo kiểu chia sẻ thời gian hoặc vòng tròn.
- Tại thời điểm t1, "LedOnTask" bắt đầu thực thi. Bởi vì cả hai nhiệm vụ đều có
mức độ ưu tiên như nhau. Ngoài ra, semaphore nhị phân có sẵn để có được vì
chúng tôi đã cung cấp semaphore bên trong chức năng thiết lập. Do đó,
"LedOnTask" lấy tín hiệu semaphore nhị phân bằng cách sử dụng
xSemaphoreTake () và hoàn thành tất cả việc thực thi nó.
- Do kỹ thuật lập lịch chia sẻ thời gian của FreeRTOS cho các tác vụ ưu tiên
bằng nhau, "LedoffTask" sẽ cố gắng thực thi bằng cách ưu tiên trước
"LedOnTask", nhưng chuyển sang trạng thái chặn do không có sẵn tài nguyên
được chia sẻ nhị phân semaphore. Do đó, "LedOnTask" trước tiên hoàn thành
việc thực thi và sau đó phát hành semaphore nhị phân.
- Ngay sau khi semaphore nhị phân trở nên có sẵn, "LedoffTask" được thực thi
bởi vì nó được nhập ở trạng thái khối do không có sẵn tài nguyên được chia sẻ
nhị phân semaphore. Tương tự, nó cũng hoàn thành việc thực hiện và phát
hành mã thông báo. Sau đó, mã Arduino lặp lại cùng một mẫu để thực thi.
TH5.1.b:
CODE:

#include <Arduino_FreeRTOS.h> // Khai báo thư viện FreeRTOS


#include <semphr.h> // Khai báo semphr.h để sử dụng Semaphore
SemaphoreHandle_t interruptSemaphore; // Khai báo biến Semaphore có tên
là interruptSemaphore
void setup()
{
Serial.begin(9600);
pinMode(LED_BUILTIN, OUTPUT); // Cài đặt chân LED_BUILTIN là
OUTPUT
xTaskCreate(TaskLedon, // Task function
"Ledon", // Task name
128, // Stack size
NULL,
0 ,// Priority
NULL );
xTaskCreate(TaskLedoff, // Task function
"Ledoff", // Task name
128, // Stack size
NULL,
0, // Priority
NULL );
interruptSemaphore = xSemaphoreCreateBinary(); // Tạo Semaphore nhị
phân
if (interruptSemaphore != NULL)
{
attachInterrupt(digitalPinToInterrupt(2), interruptHandler, HIGH); // Gán
ngắt chân số 2, khi ngắt xảy ra, hàm interruptHandler sẽ được gọi
}
}
void loop() {}
void interruptHandler()
{
Serial.println("Semaphore is given"); // In ra Serial "Semaphore is given"
BaseType_t xHigherPriorityTaskWoken pdFALSE;
xSemaphoreGiveFromISR(interruptSemaphore,
&xHigherPriorityTaskWoken); // Gửi Semaphore từ bên trong một hàm ngắt
}
// TaskLedon thực hiện việc bật LED khi nhận được Semaphore và in ra
TaskLedon Received Semaphore
void TaskLedon(void *pvParameters)
{
(void) pvParameters;
for (;;)
{
if (xSemaphoreTake(interruptSemaphore, portMAX_DELAY) ==
pdPASS)
{
Serial.println("TaskLedon Received Semaphore"); // TaskLedoff thực
hiện việc tắt LED khi nhận được Semaphore và in ra TaskLedoff Received
Semaphore
digitalWrite(LED_BUILTIN, HIGH);
}
}
}
void TaskLedoff(void *pvParameters)
{
(void) pvParameters;
for (;;)
{
if (xSemaphoreTake(interruptSemaphore, portMAX_DELAY) ==
pdPASS)
{
Serial.println("TaskLedoff Received Semaphore");
digitalWrite(LED_BUILTIN, LOW);
}
}
}

GIẢI THÍCH CODE:


- Chương trình tạo 2 tác vụ và ngắt bên ngoài trên chân kỹ thuật số hai của
Adruino để đồng bộ hóa các tác vụ này bằng cách sử dụng semaphore nhị
phân. Hai tác vụ này điều khiển một đèn LED mà chúng tôi kết nối với
chân kỹ thuật số 13 của Adruino. Tác vụ "LedOnTask" bật đèn LED và in
chuỗi "Bên trong LedOnTask" trên màn hình Arduino Serial. Tương tự,
"LedoffTask" tắt đèn LED và in chuỗi "Inside LedffTask" trên màn hình
nối tiếp Arduino.
- Cả hai tác vụ này đều có cùng mức độ ưu tiên và sử dụng cùng một semaphore
nhị phân. Do đó, FreeRTOS lên lịch cho cả hai tác vụ bằng thuật toán lập lịch
chia sẻ thời gian. Hơn nữa, cả hai tác vụ vẫn ở trạng thái chặn trừ khi gián đoạn
xảy ra và nó cung cấp semaphore nhị phân. Vì các tác vụ ưu tiên bằng nhau
tuân theo thuật toán lập lịch chia sẻ thời gian trong FreeRTOS. Đáp lại, cả hai
nhiệm vụ sẽ thu được semaphore nhị phân lần lượt.

BÀI TH5.2:
CODE:

#include <Arduino_FreeRTOS.h> // Khai báo thư viện FreeRTOS


#include <semphr.h> // Khai báo semphr.h để sử dụng Semaphore
SemaphoreHandle_t xCountingSemaphore; // Khai báo biến Semaphore loại đếm
(xCountingSemaphore).
void setup()
{
Serial.begin(9600);
pinMode(LED_BUILTIN, OUTPUT);
xTaskCreate(Task1, // Task function
"Ledon", // Task name
128, // Stack size
NULL,
0 ,// Priority
NULL );
xTaskCreate(Task2, // Task function
"Ledoff", // Task name
128, // Stack size
NULL,
0, // Priority
NULL );
xCountingSemaphore = xSemaphoreCreateCounting(1,1); // Tạo Semaphore đếm với
giá trị khởi tạo là 1 và giá trị tối đa là 1.
xSemaphoreGive(xCountingSemaphore); // Gửi Semaphore ban đầu ho phép một trong
hai task có thể bắt đầu thực hiện ngay lập tức.
}
void loop() {}
// Cả hai task đều thực hiện công việc bật (Task1) và tắt (Task2) đèn LED cùng với việc
ghi thông điệp vào Serial Monitor khi có Semaphore được lấy.
void Task1(void *pvParameters)
{
(void) pvParameters;
for (;;)
{
xSemaphoreTake(xCountingSemaphore, portMAX_DELAY);
Serial.println("Inside Task1 and Serial monitor Resource Taken");
digitalWrite(LED_BUILTIN, HIGH);
xSemaphoreGive(xCountingSemaphore);
vTaskDelay(1);
}
}
void Task2(void *pvParameters)
{
(void) pvParameters;
for (;;)
{
xSemaphoreTake(xCountingSemaphore, portMAX_DELAY);
Serial.println("Inside Task2 and Serial monitor Resource Taken");
digitalWrite(LED_BUILTIN, LOW);
xSemaphoreGive(xCountingSemaphore);
vTaskDelay(1);
}
}

GIẢI THÍCH CODE:


- Tạo núm điều khiển kiểu SemaphoreHandle_t
- Bước tiếp theo là tạo hai tác vụ như Task1 và Task2. Cả hai nhiệm vụ được tạo
ra với mức độ ưu tiên như nhau. Do đó, bộ lập lịch FreeRTOS sẽ lên lịch cho
chúng theo thuật toán cắt thời gian. Khi bắt đầu, cả hai nhiệm vụ sẽ sẵn sàng ở
trạng thái. Nhưng chỉ có một nhiệm vụ sẽ có thể thực hiện sau khi đếm
semaphore. Một tác vụ khác sẽ chuyển sang trạng thái chặn do không có sẵn
các tài nguyên như cổng giao tiếp nối tiếp và màn hình nối tiếp Arduino.
- Task1 và Task2 sử dụng giao tiếp nối tiếp để in dữ liệu trên màn hình nối tiếp.
Do đó, bạn phải kích hoạt cổng nối tiếp của Arduino với bất kỳ tốc độ truyền
nào có thể. Do đó, chúng tôi kích hoạt nó với tốc độ truyền là 9600. Cả hai tác
vụ cũng điều khiển đèn LED tích hợp của bo mạch phát triển Arduino. Task1
bật và Task2 tắt đèn LED.

TH5.3:
CODE:

#include <Arduino_FreeRTOS.h> // Khai báo thư viện FreeRTOS


#include "semphr.h" // Khai báo semphr.h để sử dụng Semaphore Mutex
SemaphoreHandle_t xMutex; // Khai báo biến Semaphore Mutex có tên là xMutex
void setup()
{
Serial.begin(9600);
xMutex = xSemaphoreCreateMutex(); // Tạo Semaphore Mutex
xTaskCreate(OutputTask,"PrinterTask1",100,"Task1#####################Task1 \r\
n",1,NULL); // Tạo một task có tên là "PrinterTask1" để gọi hàm OutputTask. Task này
có độ ưu tiên là 1.
xTaskCreate(OutputTask,"Printer Task 2", 100,"Task 2 ---------------------Task2 \r\
n",2,NULL); // Tạo một task có tên là "Printer Task 2" để gọi hàm OutputTask. Task này
có độ ưu tiên là 2.
}
// Nhận thông điệp cần in (pcStringToPrint) thông qua tham số pvParameters. Trong
vòng lặp vô hạn, task sẽ gọi hàm printer() để ghi thông điệp ra Serial Monitor và sau đó
chờ một khoảng thời gian bằng vTaskDelay(pdMS_TO_TICKS(100))
void OutputTask(void *pvParameters)
{
char *pcStringToPrint;
pcStringToPrint = (char *)pvParameters;
while(1)
{
printer(pcStringToPrint);
vTaskDelay(pdMS_TO_TICKS(100));
}
}
// Ghi thông điệp ra Serial Monitor. Trước khi ghi, task sử dụng Semaphore Mutex để
đảm bảo rằng chỉ có một task được phép ghi vào Serial Monitor tại một thời điểm. Sau
khi ghi, task trả lại Semaphore Mutex bằng cách gọi xSemaphoreGive(xMutex).
void printer(const char* pcString)
{
xSemaphoreTake(xMutex, portMAX_DELAY);
Serial.println(pcString);
xSemaphoreGive(xMutex);
}
void loop(){
}

You might also like