Tải bản đầy đủ (.docx) (33 trang)

24 BÀI CODE HỆ ĐIỀU HÀNH NHÚNG THỜI GIAN THỰC FREERTOS

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (582.87 KB, 33 trang )

HỆ ĐIỀU HÀNH NHÚNG THỜI GIAN THỰC
Bài 1: Quản lý ngắt sử dụng Queue
Viết chương trình tạo Task_Printer đọc chuỗi kí tự từ hàng đợi StringQueue và in chuỗi đó ra
màn hình Serial Monitor. Các phần tử của hàng đợi được ghi bởi một chương trình con phục
vụ ngắt (ISR) sử dụng Timer1 của Arduino.
#include <Arduino_FreeRTOS.h>
#include "queue.h"
QueueHandle_t xStringQueue;
int timer1_counter ;
void setup(){
Serial.begin(9600);
xTaskCreate(vStringPrinter," String Printer", 100, NULL, 1,NULL);
xStringQueue = xQueueCreate(5,sizeof(char *));
InterruptInit();
}
void vStringPrinter(void *pvParameters)
{
char *pcString;
while(1)
{
xQueueReceive(xStringQueue,&pcString,portMAX_DELAY);
Serial.println(pcString);
}
}
ISR(TIMER1_OVF_vect)
{
TCNT1 = timer1_counter;
uint32_t receivedNumber;
static const char *pcStrings[]=
{
"Hello\r\n",


"Hi\r\n",
"I\r\n",
"am\r\n",
"here\r\n",
};
xQueueSendToBackFromISR(xStringQueue,&pcStrings[0],pdFALSE);
}
void loop(){}
void InterruptInit()
{
noInterrupts();
TCCR1A =0;
TCCR1B =0;

1


timer1_counter = 34286;
TCNT1 = timer1_counter;
TCCR1B |=(1<TIMSK1 |= (1 << TOIE1);
interrupts();
}
Bài 2: xQueuePeek, xQueueOverwrite
Viết chương trình tạo 2 tác vụ có cùng mức ưu tiên, trong đó:
-- Task1: Tạo queue có 3 phần tử kiểu chuỗi kí tự (tối đa 15 kí tự); nhập vào queue 2
phần tử cho trước (message 1; message 2), sau đó ghi đè vào 1 phần tử khác (message
3). In ra “Data waiting to be read: n” (n là số lượng phần tử có thể đọc ra); và
“Available spaces: m” (m là số không gian trống trong queue)
-- Task2: Đọc dữ liệu từ Queue với hàm xQueuePeek và in ra màn hình

#include <Arduino_FreeRTOS.h>
#include "queue.h"
//define task handles
TaskHandle_t xTask1_Handler;
TaskHandle_t xTask2_Handler;
QueueHandle_t myQueue;
// define tasks
void Task1(void *pvParameters);
void Task2(void *pvParameters);
//define var
unsigned int count = 0;
// creat task
void setup() {
Serial.begin(9600);
xTaskCreate(Task1, "Task 1", 256, NULL, tskIDLE_PRIORITY, &xTask1_Handler);
xTaskCreate(Task2, "Task 2", 256, NULL, tskIDLE_PRIORITY, &xTask2_Handler);
vTaskStartScheduler();
}
void loop() {
}
//Task 1
void Task1(void *pvParameters) {
char txBuff[15];
myQueue = xQueueCreate(1, sizeof(txBuff));
sprintf(txBuff, "message 1");
xQueueSend(myQueue, (void *)txBuff, (TickType_t)0);
//sprintf(txBuff, "message 2");

2



//xQueueSend(myQueue, (void *)txBuff, (TickType_t)0);
Serial.print("Data waiting to be read: ");
Serial.println(uxQueueMessagesWaiting(myQueue));
Serial.print("Available spaces: ");
Serial.println(uxQueueSpacesAvailable(myQueue));
vTaskDelay(2000 / portTICK_PERIOD_MS);
sprintf(txBuff, "message 3");
xQueueOverwrite(myQueue, (void *)txBuff);
//sprintf(txBuff, "message 4");
//xQueueOverwrite(myQueue, (void *)txBuff);
for (;;) {
}
}
//Task 1
void Task2(void *pvParameters) {
char rxBuff[15];
for (;;) {
if (myQueue != 0) {
if (xQueuePeek(myQueue, (void *)rxBuff, (TickType_t)5)) {
Serial.print("Data Recieve: ");
Serial.println(rxBuff);
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}
}
}
Bài 3: Thay đổi mức ưu tiên của tác vụ
Viết chương trình tạo 2 tác vụ Task1, Task2 có mức ưu tiên tương ứng là 2, 1 trước khi gọi
trình lập lịch. Trong đó:

-- Kích thước ngăn xếp 64 từ máy (words);
-- Task1: In ra màn hình “Task1 is running, N” cứ mỗi 1s, N là biến đếm khởi tạo bằng
0. Nếu N =4 thì thay đổi mức ưu tiên của Task2 thành 3 và in ra màn hình “Back from
Task2”.
-- Task2: Thay đổi mức ưu tiên của mình thành 2, và cứ mỗi 1s in ra màn hình “Task2 is
running”
#include <Arduino_FreeRTOS.h>
//define task handles
TaskHandle_t xTask1_Handler;
TaskHandle_t xTask2_Handler;
// define tasks
void Task1(void *pvParameters);
void Task2(void *pvParameters);

3


//define var
unsigned int count = 0;
// creat task
void setup() {
Serial.begin(9600);
xTaskCreate(Task1, "Task 1", 128, NULL, 2, &xTask1_Handler);
xTaskCreate(Task2, "Task 2", 128, NULL, 1, &xTask2_Handler);
vTaskStartScheduler();
}
void loop() {
}
void Task1(void *pvParameters) {
for (;;) {

count++;
Serial.print("Task 1 is running, ");
Serial.println(count);
vTaskDelay(1000 / portTICK_PERIOD_MS);
if (count == 4) {
vTaskPrioritySet(xTask2_Handler, 3);
Serial.println("Back from Task 2");
}
}
vTaskDelete(NULL);
}
void Task2(void *pvParameters) {
vTaskPrioritySet(NULL, 2);
for (;;) {
Serial.println("Task 2 is running");
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
vTaskDelete(NULL);
}
Bài 4: Lập trình vào/ra trên Arduino với UART
Lập trình giao tiếp giữa hai Arduino sử dụng giao thức UART, với yêu cầu sau:
-- 1 board gửi kí tự X và giá trị 235 sang cho board nhận cứ mỗi 0,5s
-- Board nhận có kết nối LCD I2C và hiển thị đúng ký tự và giá trị nhận về lên dòng thứ
2 của LCD
- Arduino gửi
unsigned char val;
void setup() {
Serial.begin(9600);
}
void loop() {

val = X;

4


Serial.print('A');
Serial.print(val);
delay(500);
val = 235;
Serial.print('A');
Serial.print(val);
delay(500);
}

- Arduino nhận
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16,2);
byte Data[4];
unsigned char val = 0;
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
lcd.init();
lcd.backlight();
}
void loop() {
// put your main code here, to run repeatedly:
if(Serial.available() >3) {
Data[0] = Serial.read();

if(Data[0] == 'A') {
Data[1] = Serial.read() - 48;
Data[2] = Serial.read() - 48;
Data[3] = Serial.read() - 48;
val = (Data[1] * 100) + (Data[2] * 10) + (Data[3]);
lcd.setCursor(0,0);
lcd.print(val);
}
}
}

5


Bài 5: Queue
Viết chương trình thực hiện tạo hai tác vụ có tên “Task1”, “Task2” sao cho:
-- Cả 2 tác vụ có: Stack 250 từ máy (word), mức ưu tiên (tskIDLE_PRIORITY + 1),
Handle lần lượt là HTask1, HTask2
-- Task1 thực hiện tạo hàng đợi có tên “CT2Queue” có 6 phần tử kiểu chuỗi 20 ký tự;
gửi 3 chuỗi ký tự (“CT02-Hello”; “DT01-Hi”; “AT-Welcome” cho trước) vào hàng
đợi.
-- Task2 đọc từng phần tử từ hàng đợi và lần lượt in ra màn hình sau mỗi lần đọc các nội
dung sau: giá trị của phần tử; số phần tử có thể đọc ra từ hàng đợi và khơng gian khả
dụng cịn lại tương ứng của hàng đợi.
#include <Arduino_FreeRTOS.h>
#include "queue.h"
//define task handles
TaskHandle_t HTask1;
TaskHandle_t HTask2;
QueueHandle_t myQueue;

// define tasks
void Task1(void *pvParameters);
void Task2(void *pvParameters);
//define var

6


unsigned int count = 0;
// creat task
void setup() {
Serial.begin(9600);
xTaskCreate(Task1, "Task 1", 250, NULL, tskIDLE_PRIORITY + 1, &HTask1);
xTaskCreate(Task2, "Task 2", 250, NULL, tskIDLE_PRIORITY + 1, &HTask2);
vTaskStartScheduler();
}
void loop() {
}
//Task 1
void Task1(void *pvParameters) {
char txBuff[20];
myQueue = xQueueCreate(6, sizeof(txBuff));
sprintf(txBuff, "CT02 - Hello");
xQueueSend(myQueue, (void *)txBuff, (TickType_t)0);
sprintf(txBuff, "DT01 - Hi");
xQueueSend(myQueue, (void *)txBuff, (TickType_t)0);
sprintf(txBuff, "AT - Welcome");
xQueueSend(myQueue, (void *)txBuff, (TickType_t)0);
for (;;) {
}

}
//Task 2
void Task2(void *pvParameters) {
char rxBuff[20];
for (;;) {
if (myQueue != 0) {
if (xQueueReceive(myQueue, (void *)rxBuff, (TickType_t)0)) {
Serial.print("Data Recieve: ");
Serial.println(rxBuff);
Serial.print("Messages Waiting: ");
Serial.println(uxQueueMessagesWaiting(myQueue));
Serial.print("Empty Spaces: ");
Serial.println(uxQueueSpacesAvailable(myQueue));
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}
}
}
Bài 6: Using Interrupt to resume task
Viết chương trình tạo 3 tác vụ MyTask1, MyTask2, MyTask3 có mức ưu tiên tương ứng 1, 2,
3, trong đó:
-- MyTask1, MyTask2: đều in ra màn hình Serial Monitor dịng chữ “Task N is running,

7


Deleting Itself”, với N tương ứng là 1 và 2
-- MyTask3: In ra màn hình Serial Monitor dịng chữ “Task 3 is running, Suppending all
tasks”; thực hiện đình chỉ cả 3 tác vụ; tiếp tục in ra dòng chữ “Back in Task3, Deleting
Itself” và xóa chính nó (MyTask3)

-- Lần lượt từng tác vụ được khơi phục khi nhận được tín hiệu nút bấm (ngắt ngoài) từ
chân số 2 lần thứ 1, 2, 3.
-- Tác vụ nhàn rỗi (Idle task): In ra dòng chữ “Loop function”
#include <Arduino_FreeRTOS.h>
TaskHandle_t TaskHandle_2;
TaskHandle_t TaskHandle_3;
TaskHandle_t TaskHandle_4;
void setup()
{
Serial.begin(9600);
Serial.println(F("In Setup function"));
/* Use INT0(pin2) falling edge interrupt for resuming tasks */
attachInterrupt(digitalPinToInterrupt(2), ExternalInterrupt, FALLING);
/* Create 3-tasks with priorities 2-4. Capture the Task details to respective handlers */
xTaskCreate(MyTask2, "Task2", 100, NULL, 2, &TaskHandle_2);
xTaskCreate(MyTask3, "Task3", 100, NULL, 3, &TaskHandle_3);
xTaskCreate(MyTask4, "Task4", 100, NULL, 4, &TaskHandle_4);
}
void loop()
{
// Hooked to IDle task, it will run whenever CPU is idle
Serial.println(F("Loop function"));
delay(1000);
}
/*
* Tasks are resumed every time a Falling edge interrupt is detected on PIN2.
* One task is resumed at a time, a counter is used to resume 3taks and after which no tasks are resumed.
* xTaskResumeFromISR() returns True if Context switch is required and accordingly we need to call
portYIELD_FROM_ISR/taskYield(AVR).
* Serial data is printed in ISR only for demonstarting the control flow. This should not be done as it takes long time

to send data on Serial port.
* Tasking to much ISR time will starve the other tasks or User application.
*
*/
static void ExternalInterrupt()
{
static int count=0;
BaseType_t taskYieldRequired = 0;

8


if(count<=3)
{
count++;
}
switch(count) // Resume one task at a time depending on count value
{
case 1:
Serial.println(F("ISR Resuming Task2"));
taskYieldRequired = xTaskResumeFromISR(TaskHandle_2);
Serial.println(F("Leaving ISR"));
break;
case 2:
Serial.println(F("ISR Resuming Task3"));
taskYieldRequired = xTaskResumeFromISR(TaskHandle_3);
Serial.println(F("Leaving ISR"));
break;
case 3:
Serial.println(F("ISR Resuming Task4"));

taskYieldRequired = xTaskResumeFromISR(TaskHandle_4);
Serial.println(F("Leaving ISR"));
break;
default:
//DO nothing
break;
}
if(taskYieldRequired == 1) // If the taskYield is reuiqred then trigger the same.
{
taskYIELD();
}
}

/* Task2 with priority 2 */
static void MyTask2(void* pvParameters)
{
Serial.println(F("Task2, Deleting itself"));
vTaskDelete(NULL); //Delete own task by passing NULL(TaskHandle_2 can also be used)
}
/* Task3 with priority 3 */
static void MyTask3(void* pvParameters)
{
Serial.println(F("Task3, Deleting Itself"));
vTaskDelete(NULL); //Delete own task by passing NULL(TaskHandle_3 can also be used)
}
/* Task4 with priority 4 */
static void MyTask4(void* pvParameters)
{
Serial.println(F("Task4 Running, Suspending all tasks"));


9


vTaskSuspend(TaskHandle_2); //Suspend Task2/3
vTaskSuspend(TaskHandle_3);
vTaskSuspend(NULL);
//Suspend Own Task
Serial.println(F("Back in Task4, Deleting Itself"));
vTaskDelete(TaskHandle_4);
}
Mô tả hoạt động:
Cổng nối tiếp được khởi tạo 3-Nhiệm vụ được tạo với mức độ ưu tiên 2-4.Task4 bắt đầu thực thi vì nó có mức độ ưu
tiên cao nhất và tạm dừng Task2, Task3 và chính nó. Bây giờ Task2, Task3 và Task4 đang ở trạng thái bị treo và sẽ
không chạy cho đến khi chúng được tiếp tục. Bây giờ các tác vụ IDLE tiếp tục chạy cho đến khi một trong các Tác vụ
xuất hiện hoặc trạng thái bị tạm ngừng. Trong ví dụ hiện tại, chỉ INTO ISR mới có thể tiếp tục các tác vụ. Khi ngắt
INT0 được tạo, nó sẽ tiếp tục Task2.Task2 sẽ chạy trong một thời gian và tự xóa. Một lần nữa, nhiệm vụ IDLE tiếp tục
chạy cho đến khi ngắt được tạo ra và các tác vụ được tiếp tục. Khi ngắt INT0 được tạo, nó sẽ tiếp tục Task3. Task3 sẽ
chạy trong một thời gian và tự xóa. Một lần nữa, nhiệm vụ IDLE tiếp tục chạy cho đến khi ngắt được tạo ra và các tác
vụ được tiếp tục. Khi ngắt INT0 được tạo, nó sẽ tiếp tục Task3. Task3 sẽ chạy trong một thời gian và tự xóa.
Chỉ cịn lại tác vụ IDLE và nó tiếp tục chạy.

Bài 7: Task suspend, resume:
Viết chương trình tạo 2 tác vụ có mức ưu tiên (tskIDLE_PRIORITY + 2)
-- Task1: In ra màn hình “Hello World, N” cứ mỗi 1s, N là biến đếm
-- Task2: Cứ 5s sẽ đình chỉ Task1, sau 5s lại khôi phục Task1
#include <Arduino_FreeRTOS.h>
//define task handles
TaskHandle_t xTask1_Handler;
TaskHandle_t xTask2_Handler;
// define tasks

void Task1(void *pvParameters);
void Task2(void *pvParameters);
//define var
unsigned int count = 0;
// creat task
void setup() {
Serial.begin(9600);
xTaskCreate(Task1, "Task 1", 128, NULL, tskIDLE_PRIORITY, &xTask1_Handler);
xTaskCreate(Task2, "Task 2", 128, NULL, tskIDLE_PRIORITY, &xTask2_Handler);
vTaskStartScheduler();
}
void loop() {
}
void Task1(void *pvParameters) {
for (;;) {

10


count++;
Serial.print("Hello World, ");
Serial.println(count);
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}
void Task2(void *pvParameters) {
for (;;) {
vTaskDelay(4000 / portTICK_PERIOD_MS);
vTaskSuspend(xTask1_Handler);
vTaskDelay(5000 / portTICK_PERIOD_MS);

vTaskResume(xTask1_Handler);
}
}
Bài 8: Queue
Viết chương trình thực hiện tạo hai tác vụ có tên “Task1”, “Task2” sao cho:
-- Task 1 thực hiện tạo hàng đợi có tên “MyQueue” có 6 phần tử kiểu chuỗi 20 ký tự; ghi
3 chuỗi ký tự cho trước (message 1; message 2; message 3) vào hàng đợi.
-- Task2 đọc từng phần tử từ hàng đợi và lần lượt in ra màn hình sau mỗi lần đọc các nội
dung sau: giá trị của phần tử; số phần tử có thể đọc ra từ hàng đợi và khơng gian khả
dụng cịn lại tương ứng của hàng đợi.
#include <Arduino_FreeRTOS.h>
#include "queue.h"
//define task handles
TaskHandle_t xTask1_Handler;
TaskHandle_t xTask2_Handler;
QueueHandle_t myQueue;
// define tasks
void Task1(void *pvParameters);
void Task2(void *pvParameters);
//define var
unsigned int count = 0;
// creat task
void setup() {
Serial.begin(9600);
xTaskCreate(Task1, "Task 1", 128, NULL, tskIDLE_PRIORITY, &xTask1_Handler);
xTaskCreate(Task2, "Task 2", 128, NULL, tskIDLE_PRIORITY, &xTask2_Handler);
vTaskStartScheduler();
}
void loop() {
}


11


//Task 1
void Task1(void *pvParameters) {
char txBuff[20];
myQueue = xQueueCreate(6, sizeof(txBuff));
sprintf(txBuff, "message 1");
xQueueSend(myQueue, (void *)txBuff, (TickType_t)0);
sprintf(txBuff, "message 2");
xQueueSend(myQueue, (void *)txBuff, (TickType_t)0);
sprintf(txBuff, "message 3");
xQueueSend(myQueue, (void *)txBuff, (TickType_t)0);
for (;;) {
}
}
void Task2(void *pvParameters) {
char rxBuff[20];
for (;;) {
if (myQueue != 0) {
if (xQueueReceive(myQueue, (void *)rxBuff, (TickType_t)0)) {
Serial.print("Data Recieve: ");
Serial.println(rxBuff);
Serial.print("Messages Waiting: ");
Serial.println(uxQueueMessagesWaiting(myQueue));
Serial.print("Empty Spaces: ");
Serial.println(uxQueueSpacesAvailable(myQueue));
vTaskDelay(1000 / portTICK_PERIOD_MS);
}

}
}
}
Bài 9: Task&Queue, Sensor, LCD
Viết chương trình tạo hai tác vụ Sender, Receiver và hàng đợi Queue có 5 phần tử kiểu
nguyên, sao cho:
-- Tác vụ Receiver có mức ưu tiên cao hơn tác vụ Sender
-- Tác vụ Sender đọc giá trị ADC gửi vào Queue và in giá trị đó ra màn hình Serial
monitor
-- Tác vụ Receiver đọc giá trị từ Queue và hiển thị lên màn hình LCD như sau: Dòng 1
“ADC Value:”; dòng 2: giá trị đọc được.
#include <Arduino_FreeRTOS.h>
//define task handles
TaskHandle_t HTask1;
TaskHandle_t HTask2;

12


// define tasks
void Task1(void *pvParameters);
void Task2(void *pvParameters);
//define var
unsigned int count = 0;
// creat task
void setup() {
Serial.begin(9600);
pinMode(8, OUTPUT);
pinMode(LED_BUILTIN, INPUT_PULLUP);
xTaskCreate(Task1, "Task 1", 100, NULL, tskIDLE_PRIORITY, &HTask1);

xTaskCreate(Task2, "Task 2", 100, NULL, tskIDLE_PRIORITY, &HTask2);
vTaskStartScheduler();
}
void loop() {
}
//Task 1
void Task1(void *pvParameters) {
(void)pvParameters;
for (;;) {
if (digitalRead(2) == 0) {
while (digitalRead(2))
;
digitalWrite(LED_BUILTIN, LOW);
} else {
digitalWrite(LED_BUILTIN, HIGH);
}
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}
//Task 2
void Task2(void *pvParameters) {
(void)pvParameters;
for (;;) {
Serial.println("Task Print");
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}

Bài 10: Using Mutex to handle Multiple Task
Viết chương trình tạo hai tác vụ Task1, Task2 và sử dụng Mutex để xử lý hai tác vụ sao cho

chúng được thực hiện luân phiên. Biết:
-- Hai tác vụ cùng mức ưu tiên
-- Task1, Task 2 đều liên tục in ra màn hình các giá trị từ 0 đến 4 cứ mỗi 0.5s

13


-- Kết quả: Task1 in cả 5 giá trị rồi mới đến Task2 thực hiện
#include <Arduino_FreeRTOS.h>
#include "semphr.h"
//define task handles
TaskHandle_t HTask1;
TaskHandle_t HTask2;
SemaphoreHandle_t mutex;
// define tasks
void Task1(void *pvParameters);
void Task2(void *pvParameters);
//define var
// creat task
void setup() {
Serial.begin(9600);
mutex = xSemaphoreCreateMutex();
if (mutex != NULL) {
Serial.println("Mutex created");
}
xTaskCreate(Task1, "Task 1", 100, NULL, tskIDLE_PRIORITY, &HTask1);
xTaskCreate(Task2, "Task 2", 100, NULL, tskIDLE_PRIORITY, &HTask2);
vTaskStartScheduler();
}
void loop() {

}
//Task 1
void Task1(void *pvParameters) {
(void)pvParameters;
xSemaphoreTake(mutex, portMAX_DELAY);
for (int i = 0; i < 5; i++) {
Serial.print("Task 1: ");
Serial.println(i);
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
xSemaphoreGive(mutex);
}
//Task 2
void Task2(void *pvParameters) {
(void)pvParameters;
xSemaphoreTake(mutex, portMAX_DELAY);
for (int i = 0; i < 5; i++) {
Serial.print("Task 2: ");
Serial.println(i);
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
xSemaphoreGive(mutex);

14


}
Bài 11: Using Mutex to Resource management
Viết chương trình tạo hai tác vụ có tên “Task1”, “Task2” sao cho:
-- Cả hai tác vụ Task1, Task2 đều thực hiện gán từng ký tự của thông báo tương ứng

Msg1, Msg2 cho từng phần tử trong SharedResource; các ký tự còn lại trống. Sau đó
in ra màn hình dịng chữ “Task n: A”, với A là giá trị của biến SharedResource; n là
số thứ tự của tác vụ; Msg1 =“CT01L01”; Msg2 = “CT01L02”.
-- Sử dụng Mutex để đồng bộ việc sử dụng tài nguyên chia sẻ của hai tác vụ trên.
#include <Arduino_FreeRTOS.h>
#include "semphr.h"
//define task handles
TaskHandle_t HTask1;
TaskHandle_t HTask2;
SemaphoreHandle_t mutex;
// define tasks
void Task1(void *pvParameters);
void Task2(void *pvParameters);
//define var
char SharedResource[10];
// creat task
void setup() {
Serial.begin(9600);
mutex = xSemaphoreCreateMutex();
if (mutex != NULL) {
Serial.println("Mutex created");
}
xTaskCreate(Task1, "Task 1", 200, NULL, tskIDLE_PRIORITY, &HTask1);
xTaskCreate(Task2, "Task 2", 200, NULL, tskIDLE_PRIORITY, &HTask2);
vTaskStartScheduler();
}
void loop() {
}
//Task 1
void Task1(void *pvParameters) {

(void)pvParameters;
char Msg1[] = "CT01L01";
for (;;) {
if (xSemaphoreTake(mutex, (TickType_t)0xFFFFFFFF) == pdTRUE) {

15


int i;
for (i = 0; i < 8; i++) {
SharedResource[i] = Msg1[i];
vTaskDelay(50 / portTICK_PERIOD_MS);
}
SharedResource[i] = 0;
Serial.print("Task 1: ");
Serial.println(SharedResource);
xSemaphoreGive(mutex);
}
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}
//Task 2
void Task2(void *pvParameters) {
(void)pvParameters;
char Msg2[] = "CT01L02";
for (;;) {
if (xSemaphoreTake(mutex, (TickType_t)0xFFFFFFFF) == pdTRUE) {
int i;
for (i = 0; i < 8; i++) {
SharedResource[i] = Msg2[i];

vTaskDelay(50 / portTICK_PERIOD_MS);
}
SharedResource[i] = 0;
Serial.print("Task 2: ");
Serial.println(SharedResource);
xSemaphoreGive(mutex);
}
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}
Bài 12: Mailbox Example using Queue and Arduino
Viết chương trình tạo hai tác vụ gửi và nhận dữ liệu vào/từ mailbox, trong đó:
-- Task gửi: Ghi 1 giá trị vào mailbox mỗi 5s và in ra màn hình Serial Monitor dòng chữ
“Data written to mailbox”
-- Task nhận: Đọc dữ liệu từ mailbox mỗi 1s và in ra dòng chữ “Data read from mailbox
= N”, N là giá trị đọc được
#include <Arduino_FreeRTOS.h>
#include "queue.h"
//define task handles
TaskHandle_t HTask1;
TaskHandle_t HTask2;
QueueHandle_t xMailBox;

16


// define tasks
void Task1(void *pvParameters);
void Task2(void *pvParameters);
//define var

char SharedResource[10];
// creat task
void setup() {
Serial.begin(9600);
xMailBox = xQueueCreate(1, sizeof(int));
if (xMailBox != NULL) {
Serial.println("Mailbox created");
}
xTaskCreate(Task1, "Task 1", 100, NULL, tskIDLE_PRIORITY, &HTask1);
xTaskCreate(Task2, "Task 2", 100, NULL, tskIDLE_PRIORITY, &HTask2);
vTaskStartScheduler();
}
void loop() {
}
//Task 1
void Task1(void *pvParameters) {
(void)pvParameters;
int txdata = 1;
for (;;) {
xQueueOverwrite(xMailBox, &txdata);
Serial.println("Data written to mailbox");
txdata++;
vTaskDelay(500 / portTICK_PERIOD_MS);
}
}
//Task 2
void Task2(void *pvParameters) {
(void)pvParameters;
int rxdata;
for (;;) {

xQueuePeek(xMailBox, &rxdata, portMAX_DELAY);
Serial.print("Data read from mailbox: ");
Serial.println(rxdata);
vTaskDelay(100 / portTICK_PERIOD_MS);
}
}
Bài 13: Using Binary Semaphore: Task Synchronization
Viết chương trình sử dụng Binary Semaphore để thực hiện đồng bộ hai tác vụ Task1, Task2
điều khiển bật/tắt đèn tại chân 13 của Arduino, biết:
-- Hai tác vụ có cùng mức ưu tiên

17


-- Không thực thi tại cùng một thời điểm
-- In ra màn hình Serial Monitor trạng thái hiện tại của đèn
#include <Arduino_FreeRTOS.h>
#include "semphr.h"
#define LED 13
SemaphoreHandle_t xBinarySemaphore;
void setup()
{
Serial.begin(9600);
pinMode(LED ,OUTPUT);
xBinarySemaphore = xSemaphoreCreateBinary();
xTaskCreate(LedOnTask, "LedON",100,NULL,1,NULL);
xTaskCreate(LedoffTask, "LedOFF", 100,NULL,1,NULL);
xSemaphoreGive(xBinarySemaphore);
}
void loop(){}

void LedOnTask(void *pvParameters)
{
while(1)
{
xSemaphoreTake(xBinarySemaphore,portMAX_DELAY);
Serial.println("Inside LedOnTask");
digitalWrite(LED,LOW);
xSemaphoreGive(xBinarySemaphore);
vTaskDelay(1);
}
}
void LedoffTask(void *pvParameters)
{
while(1)
{
xSemaphoreTake(xBinarySemaphore,portMAX_DELAY);
Serial.println("Inside LedffTask");
digitalWrite(LED,HIGH);
xSemaphoreGive(xBinarySemaphore);
vTaskDelay(1);
}
}
Mô tả hoạt động:
- “LedOnTask” bắt đầu thực thi. Vì cả hai nhiệm vụ đều có cùng mức độ ưu tiên Do đó, “LedOnTask” nhận một tín hiệu
semaphore nhị phân bằng cách sử dụng xSemaphoreTake () và hoàn thành tất cả q trình thực thi của nó.
- “LedoffTask” sẽ cố gắng thực thi bằng cách bỏ trước “LedOnTask”, nhưng chuyển sang trạng thái chặn do khơng có sẵn
semaphore nhị phân tài ngun được chia sẻ. Do đó, “LedOnTask” đầu tiên hồn thành việc thực thi và sau đó giải phóng
semaphore nhị phân.
- Khi semaphore nhị phân trở nên khả dụng, “LedoffTask” sẽ thực thi nó vì nó được đưa vào trạng thái khối do tính sẵn có
của semaphore nhị phân tài nguyên được chia sẻ


18


Bài 14: Using Binary Semaphore: Task – Interrupt Synchronization
Viết chương trình sử dụng Binary Semaphore để thực hiện đồng bộ hai tác vụ Task1, Task2
điều khiển bật/tắt đèn tại chân 13 của Arduino, biết:
-- Hai tác vụ có cùng mức ưu tiên
-- Không thực thi tại cùng một thời điểm
-- In ra màn hình Serial Monitor trạng thái hiện tại của đèn
#include <Arduino_FreeRTOS.h>
#include "semphr.h"
//define task handles
TaskHandle_t HTask1;
TaskHandle_t HTask2;
SemaphoreHandle_t ISR_Semaphore;
// define tasks
void Task1(void *pvParameters);
void Task2(void *pvParameters);
void ISR_Handle();
//define var
#define LED 8
// creat task
void setup() {
Serial.begin(9600);
pinMode(LED, OUTPUT);
ISR_Semaphore = xSemaphoreCreateBinary();
if (ISR_Semaphore != NULL) {
attachInterrupt(digitalPinToInterrupt(2), ISR_Handle, FALLING);
}

xTaskCreate(Task1, "TaskLedon", 128, NULL, tskIDLE_PRIORITY, &HTask1);
xTaskCreate(Task2, "TaskLedoff", 128, NULL, tskIDLE_PRIORITY, &HTask2);
vTaskStartScheduler();
}
void loop() {
}
//ISR
void ISR_Handle() {
Serial.println("Semaphore is given");
BaseType_t xHigherPriorityTaskWoken pdFALSE;
xSemaphoreGiveFromISR(ISR_Semaphore, &xHigherPriorityTaskWoken);
}
//Task 1
void Task1(void *pvParameters) {
(void)pvParameters;
for (;;) {

19


if (xSemaphoreTake(ISR_Semaphore, portMAX_DELAY) == pdPASS) {
Serial.println("TaskLedon Received Semaphore");
digitalWrite(LED, HIGH);
}
}
}
//Task 2
void Task2(void *pvParameters) {
(void)pvParameters;
for (;;) {

if (xSemaphoreTake(ISR_Semaphore, portMAX_DELAY) == pdPASS) {
Serial.println("TaskLedoff Received Semaphore");
digitalWrite(LED, LOW);
}
}
}
Bài 15: Using Counting Semaphore: Resource Management
Viết chương trình sử dụng Couting Semaphore để quản lý tài nguyên trên Arduino, đảm bảo
tại một thời điểm chỉ có một tác vụ được sử dụng tài nguyên. Biết: Hai tác vụ Task1, Task2
cùng sử dụng giao tiếp Serial (UART module) của Arduino và gửi chuỗi ký tự ra Serial
Monitor.
#include <Arduino_FreeRTOS.h>
#include "semphr.h"
//define task handles
TaskHandle_t HTask1;
TaskHandle_t HTask2;
SemaphoreHandle_t CountingSemaphore;
// define tasks
void Task1(void *pvParameters);
void Task2(void *pvParameters);
//define var
#define LED 8
// creat task
void setup() {
Serial.begin(9600);
pinMode(LED, OUTPUT);
xTaskCreate(Task1, "TaskLedon", 128, NULL, tskIDLE_PRIORITY, &HTask1);
xTaskCreate(Task2, "TaskLedoff", 128, NULL, tskIDLE_PRIORITY, &HTask2);
CountingSemaphore = xSemaphoreCreateCounting(1, 1);
xSemaphoreGive(CountingSemaphore);

//vTaskStartScheduler();
}
void loop() {

20


}
//Task 1
void Task1(void *pvParameters) {
(void)pvParameters;
for (;;) {
xSemaphoreTake(CountingSemaphore, portMAX_DELAY);
Serial.println("Inside Task1 and Serial monitor Resource Taken");
digitalWrite(LED, HIGH);
vTaskDelay(1000 / portTICK_PERIOD_MS);
xSemaphoreGive(CountingSemaphore);
vTaskDelay(1);
}
}
//Task 2
void Task2(void *pvParameters) {
(void)pvParameters;
for (;;) {
xSemaphoreTake(CountingSemaphore, portMAX_DELAY);
Serial.println("Inside Task2 and Serial monitor Resource Taken");
digitalWrite(LED, LOW);
vTaskDelay(1000 / portTICK_PERIOD_MS);
xSemaphoreGive(CountingSemaphore);
vTaskDelay(1);

}
}
Bài 16: One-shot Timer & Auto-reload Timer
Viết chương trình thực thi hai hàm gọi lại chương trình với One-shot Timer và Auto-reload
timer có tên tương ứng là OneShotTimerCallback và AutoReloadTimerCallback.
-- Hai hàm đều in ra màn hình thơng báo trạng thái thực thi của mình kèm số thứ tự của
lần thực thi đó
-- Hàm AutoReloadTimerCallback thực hiện 8 lần thì OneShotTimerCallback thực hiện
1 lần
#include <Arduino_FreeRTOS.h>
#include <task.h>
#include <timers.h>
#define mainONE_SHOT_TIMER_PERIOD pdMS_TO_TICKS(3333)
#define mainAUTO_RELOAD_TIMER_PERIOD pdMS_TO_TICKS(500)
#define mainAUTO_RELOAD_TIMER_PERIOD2 pdMS_TO_TICKS(1000)
//define timer handle
TimerHandle_t xAutoReloadTimer, xOneShotTimer;
BaseType_t xTimer1Started, xTimer2Started;
void setup() {
Serial.begin(9600);
xOneShotTimer = xTimerCreate("OneShot", mainONE_SHOT_TIMER_PERIOD, pdFALSE, 0,

21


prvOneShotTimerCallback);
xAutoReloadTimer = xTimerCreate("AutoReload", mainAUTO_RELOAD_TIMER_PERIOD, pdTRUE, 0,
prvAutoReloadTimerCallback);
if ((xOneShotTimer != NULL) && (xAutoReloadTimer != NULL)) {
xTimer1Started = xTimerStart(xOneShotTimer, 0);

xTimer2Started = xTimerStart(xAutoReloadTimer, 0);
if ((xTimer1Started == pdPASS) && (xTimer2Started == pdPASS)) {
vTaskStartScheduler();
}
}
}
void loop() {
}
//one shot timer
static void prvOneShotTimerCallback(TimerHandle_t xTimer) {
TickType_t xTimeNow;
xTimeNow = xTaskGetTickCount();
Serial.print("One-shot timer callback executing ");
Serial.println(xTimeNow / 31);
}
//auto reload timer
static void prvAutoReloadTimerCallback(TimerHandle_t xTimer) {
TickType_t xTimeNow;
uint32_t ulExecutionCount;
ulExecutionCount = (uint32_t)pvTimerGetTimerID(xTimer);
ulExecutionCount++;
vTimerSetTimerID(xTimer, (void *)ulExecutionCount);
xTimeNow = xTaskGetTickCount();
Serial.print("Auto-reload timer callback executing ");
Serial.println(xTimeNow / 31);
if (ulExecutionCount >= 10) {
xTimerChangePeriod(xAutoReloadTimer, mainAUTO_RELOAD_TIMER_PERIOD2, 0);
}
}
Bài 17: Lập trình vào/ra trên Arduino với I2C

Lập trình giao tiếp giữa hai Arduino sử dụng giao thức I2C, với địa chỉ nhận dữ liệu là 10.
-- Master gửi từng ký tự trong chuỗi “Hello Slave”, yêu cầu Slave phản hồi lại 11 ký tự
và in chuỗi ký tự phản hồi này lên Serial Monitor
-- Slave đọc từng ký tự Master gửi đến và in cả chuỗi lên Serial Monitor
#include <Wire.h>
void setup() {
Serial.begin(9600);
Wire.begin();
}
void loop() {

22


String txbuff = "Hello"; //data
Wire.beginTransmission(10); // Slave's Address
for (int i = 0; i < 5; i++) {
Wire.write(txbuff[i]);
}
Wire.endTransmission();
//request
String request;
Wire.requestFrom(10, 6); //feedback with 15 chars
while (Wire.available()) {
char c = Wire.read();
Serial.print(c);
}
Serial.println();
delay(1000);
}

#include <Wire.h>
void setup() {
Wire.begin(10); // start i2c, "10" is addr
Wire.onReceive(receiveEvent);
Wire.onRequest(requestEvent);
Serial.begin(9600);
}
void loop() {}
//receive Event
void receiveEvent(int num) {
while (Wire.available()) {
char c = Wire.read();
Serial.print(c);
}
Serial.println(" - Receive!!!");
}
//request
void requestEvent() {
Serial.println("Send request!");
Wire.write("Sucess");
}
#include <SoftwareSerial.h>
void setup() {
Serial.begin(9600);
}
void loop() {
if (Serial.available()) {
Serial.write(Serial.read());
}
}


23


void setup() {
Serial.begin(9600);
}
void loop() {
Serial.println("Hello World!!!");
delay(1000);
}
Bài 18: Using Queue
Viết chương trình sử dụng Queue để thực hiện truyền thơng giữa hai tác vụ trên Arduino, biết:
-- Hai chân 8,9 có hai đèn led (xanh, đỏ), ban đầu đèn số 8 bật, đèn số 9 tắt.
-- Khởi tạo 2 task, một task gửi dữ liệu và một task nhận dữ liệu
-- Task gửi tạo ra một giá trị cứ mỗi 1 giây và thêm giá trị này vào cuối hàng đợi
-- Task nhận sẽ đọc một giá trị từ đầu hàng đợi cứ sau 500 ms, nếu khơng có giá trị, nó
sẽ đợi trong 1 giây. Nếu giá trị nhận được lớn hơn hoặc bằng 4 và nhỏ hơn hoặc bằng
10 thì đèn số 8 sẽ tắt và đèn số 9 sẽ bật. Ngược lại nếu giá trị nhận được nhỏ hơn 4 và
lớn hơn 10 thì đền số 8 sẽ bật và đèn số 9 sẽ tắt.
#include <Arduino_FreeRTOS.h>
#include <queue.h>
int redled = 9;
int yellowLed = 8;
TaskHandle_t TaskHandle_1; // trình xử lý cho Task1
TaskHandle_t TaskHandle_2;
QueueHandle_t xQueue;
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);

pinMode(redled,OUTPUT);
pinMode(yellowLed,OUTPUT);
xQueue = xQueueCreate(1, sizeof(int32_t));
xTaskCreate(vSendToBack,"sender",100,NULL,1,&TaskHandle_1);
xTaskCreate(vReceiverTask,"receiver",100,NULL,1,&TaskHandle_2);
vTaskStartScheduler();
}
void loop() {
// put your main code here, to run repeatedly:
}
void vSendToBack (void *pvParam){
int32_t lValueToSend=1;
lValueToSend = (int32_t) pvParam;
for(;;){
xQueueSendToBack(xQueue, &lValueToSend , portMAX_DELAY);
Serial.print("sent = ");
Serial.println(lValueToSend);

24


lValueToSend++;
vTaskDelay(1000/portTICK_PERIOD_MS);
taskYIELD();
}
}
void vReceiverTask(void *pvParam){
int32_t lReceivedValue;
for( ;;){
if(xQueueReceive( xQueue, &lReceivedValue, portMAX_DELAY ) == pdPASS){

if(lReceivedValue >= 4 && lReceivedValue <= 10){
digitalWrite(redled,HIGH);
digitalWrite(yellowLed,LOW);
Serial.print("Received = ");
Serial.println(lReceivedValue);}
else{
digitalWrite(redled,LOW);
digitalWrite(yellowLed,HIGH);
Serial.print("Received = ");
Serial.println(lReceivedValue);
}}
vTaskDelay(500/portTICK_PERIOD_MS);
taskYIELD();
}
}
Bài 19: Using Mutex to Resource management
Viết chương trình tạo hai tác vụ có tên “Task1”, “Task2” sao cho:
-- Cả hai tác vụ Task1, Task2 đều thực hiện gán từng ký tự của thông báo tương ứng
Msg1, Msg2 cho từng phần tử trong biến có tên SharedResource; các ký tự cịn lại
trống. Sau đó in ra màn hình dịng chữ “Task n: A”, với A là giá trị của biến
SharedResource; n là số thứ tự của tác vụ; Msg1 =“13579”; Msg2 = “02468”.
-- Sử dụng Mutex để đồng bộ việc sử dụng tài nguyên chia sẻ của hai tác vụ trên.
#include <Arduino_FreeRTOS.h>
#include "semphr.h"
//define task handles
TaskHandle_t HTask1;
TaskHandle_t HTask2;
SemaphoreHandle_t mutex;
// define tasks
void Task1(void *pvParameters);

void Task2(void *pvParameters);
//define var
char SharedResource[10];

25


×