- Apa itu Semaphore?
- Bagaimana cara menggunakan Semaphore di FreeRTOS?
- Penjelasan Kode Semaphore
- Diagram Sirkuit
- Apa Mutex?
- Bagaimana cara menggunakan Mutex di FreeRTOS?
- Penjelasan Kode Mutex
Dalam tutorial sebelumnya, kita telah membahas dasar-dasar FreeRTOS dengan Arduino dan objek kernel Queue di FreeRTOS Arduino. Sekarang, dalam tutorial FreeRTOS ketiga ini, kita akan mempelajari lebih lanjut tentang FreeRTOS dan API lanjutannya, yang dapat membuat Anda memahami platform multi-tasking lebih dalam.
Semaphore dan Mutex (Mutual Exclusion) adalah objek kernel yang digunakan untuk sinkronisasi, manajemen sumber daya, dan melindungi sumber daya dari korupsi. Di paruh pertama tutorial ini, kita akan melihat ide di balik Semaphore, bagaimana dan di mana menggunakannya. Di babak kedua, kami akan melanjutkan dengan Mutex.
Apa itu Semaphore?
Dalam tutorial sebelumnya, kita telah membahas tentang prioritas tugas dan juga mengetahui bahwa tugas dengan prioritas yang lebih tinggi mendahului tugas dengan prioritas yang lebih rendah sehingga saat menjalankan tugas dengan prioritas tinggi mungkin ada kemungkinan bahwa korupsi data dapat terjadi pada tugas dengan prioritas lebih rendah karena itu belum dieksekusi dan data datang terus-menerus untuk tugas ini dari sensor yang menyebabkan kehilangan data dan tidak berfungsinya seluruh aplikasi.
Jadi, ada kebutuhan untuk melindungi sumber daya dari kehilangan data dan di sini Semaphore memainkan peran penting.
Semaphore adalah mekanisme pensinyalan di mana tugas dalam keadaan menunggu ditandai oleh tugas lain untuk dieksekusi. Dengan kata lain, ketika sebuah task1 menyelesaikan pekerjaannya, maka ia akan menampilkan sebuah flag atau menaikkan sebuah flag sebesar 1 dan kemudian flag ini diterima oleh tugas lain (task2) yang menunjukkan bahwa ia dapat melakukan tugasnya sekarang. Ketika task2 menyelesaikan pekerjaannya maka flag akan dikurangi 1.
Jadi, pada dasarnya, ini adalah mekanisme "Memberi" dan "Ambil" dan semaphore adalah variabel integer yang digunakan untuk menyinkronkan akses ke resource.
Jenis Semaphore di FreeRTOS:
Semaphore terdiri dari dua jenis.
- Binary Semaphore
- Menghitung Semaphore
1. Binary Semaphore: Memiliki dua nilai integer 0 dan 1. Ini agak mirip dengan Antrian panjangnya 1. Sebagai contoh, kita memiliki dua tugas, tugas1 dan tugas2. Task1 mengirimkan data ke task2 sehingga task2 terus menerus mengecek item queue jika ada 1, kemudian bisa membaca data yang lain harus menunggu hingga menjadi 1. Setelah mengambil data, task2 mengurangi antrian dan membuatnya 0 Artinya task1 lagi dapat mengirim data ke task2.
Dari contoh diatas, dapat dikatakan bahwa binary semaphore digunakan untuk sinkronisasi antar tugas atau antar tugas dan interupsi.
2. Menghitung Semaphore: Memiliki nilai lebih besar dari 0 dan dapat dianggap antrian panjangnya lebih dari 1. Semaphore ini digunakan untuk menghitung event. Dalam skenario penggunaan ini, penangan peristiwa akan 'memberikan' semaphore setiap kali peristiwa terjadi (menambah nilai jumlah semaphore), dan tugas penangan akan 'mengambil' semaphore setiap kali memproses peristiwa (mengurangi nilai jumlah semaphore).
Oleh karena itu, nilai hitungannya adalah selisih antara jumlah peristiwa yang telah terjadi dan jumlah yang telah diproses.
Sekarang, mari kita lihat bagaimana menggunakan Semaphore dalam kode FreeRTOS kami.
Bagaimana cara menggunakan Semaphore di FreeRTOS?
FreeRTOS mendukung API yang berbeda untuk membuat semaphore, mengambil semaphore dan memberikan semaphore.
Sekarang, ada dua jenis API untuk objek kernel yang sama. Jika kita harus memberikan semaphore dari ISR, maka API semaphore normal tidak dapat digunakan. Anda harus menggunakan API yang dilindungi interupsi.
Dalam tutorial ini, kita akan menggunakan binary semaphore karena mudah dipahami dan diterapkan. Karena fungsionalitas interupsi digunakan di sini, Anda perlu menggunakan API yang dilindungi interupsi dalam fungsi ISR. Saat kami mengatakan menyinkronkan tugas dengan interupsi, itu berarti menempatkan tugas ke status Berjalan tepat setelah ISR.
Membuat Semaphore:
Untuk menggunakan objek kernel apa pun, pertama-tama kita harus membuatnya. Untuk membuat semaphore biner, gunakan vSemaphoreCreateBinary ().
API ini tidak mengambil parameter apa pun dan mengembalikan variabel berjenis SemaphoreHandle_t. Nama variabel global sema_v dibuat untuk menyimpan semafor.
SemaphoreHandle_t sema_v; sema_v = xSemaphoreCreateBinary ();
Memberi semaphore:
Untuk memberikan semaphore, ada dua versi - satu untuk interupsi dan satu lagi untuk tugas normal.
- xSemaphoreGive (): API ini hanya mengambil satu argumen yang merupakan nama variabel dari semaphore seperti sema_v seperti yang diberikan di atas saat membuat semaphore. Ini dapat dipanggil dari tugas normal apa pun yang ingin Anda sinkronkan.
- xSemaphoreGiveFromISR (): Ini adalah versi API yang dilindungi interupsi dari xSemaphoreGive (). Saat kita perlu menyinkronkan ISR dan tugas normal, maka xSemaphoreGiveFromISR () harus digunakan dari fungsi ISR.
Mengambil semaphore:
Untuk mengambil semaphore, gunakan fungsi API xSemaphoreTake (). API ini membutuhkan dua parameter.
xSemaphoreTake (SemaphoreHandle_t xSemaphore, TickType_t xTicksToWait);
xSemaphore: Nama semaphore yang akan diambil dalam kasus kita sema_v.
xTicksToWait: Ini adalah jumlah waktu maksimum tugas akan menunggu dalam status Diblokir agar semafor tersedia. Dalam proyek kami, kami akan menyetel xTicksToWait ke portMAX_DELAY untuk membuat task_1 menunggu tanpa batas waktu dalam status Diblokir hingga sema_v tersedia.
Sekarang, mari gunakan API ini dan tulis kode untuk melakukan beberapa tugas.
Di sini satu tombol tekan dan dua LED dihubungkan. Push-button akan berfungsi sebagai tombol interupsi yang dipasang pada pin 2 Arduino Uno. Saat tombol ini ditekan, akan dihasilkan interupsi dan LED yang terhubung ke pin 8 akan ON dan saat Anda menekannya lagi akan OFF.
Jadi, ketika tombol ditekan xSemaphoreGiveFromISR () akan dipanggil dari fungsi ISR dan fungsi xSemaphoreTake () akan dipanggil dari fungsi TaskLED.
Agar sistem terlihat multitasking, sambungkan LED lain dengan pin 7 yang akan selalu berkedip.
Penjelasan Kode Semaphore
Mari mulai menulis kode dengan membuka Arduino IDE
1. Pertama, sertakan file header Arduino_FreeRTOS.h . Sekarang, jika ada objek kernel yang digunakan seperti queue semaphore, maka file header juga harus disertakan untuk itu.
#include #include
2. Deklarasikan variabel tipe SemaphoreHandle_t untuk menyimpan nilai semaphore.
SemaphoreHandle_t interruptSemaphore;
3. Di void setup (), buat dua tugas (TaskLED dan TaskBlink) menggunakan xTaskCreate () API dan kemudian buat semaphore menggunakan xSemaphoreCreateBinary (). Buat tugas dengan prioritas yang sama dan kemudian coba bermain dengan nomor ini. Juga, Konfigurasikan pin 2 sebagai input dan aktifkan resistor pull-up internal dan pasang pin interupsi. Terakhir, jalankan penjadwal seperti yang ditunjukkan di bawah ini.
batal penyiapan () { pinMode (2, INPUT_PULLUP); xTaskCreate (TaskLed, "Led", 128, NULL, 0, NULL); xTaskCreate (TaskBlink, "LedBlink", 128, NULL, 0, NULL); interruptSemaphore = xSemaphoreCreateBinary (); if (interruptSemaphore! = NULL) { attachInterrupt (digitalPinToInterrupt (2), debounceInterrupt, LOW); } }
4. Sekarang, terapkan fungsi ISR. Buat sebuah fungsi dan beri nama sama dengan argumen kedua dari fungsi attachInterrupt () . Untuk membuat interupsi bekerja dengan baik, Anda perlu menghilangkan masalah debounce tombol menggunakan fungsi milis atau mikro dan dengan menyesuaikan waktu debouncing. Dari fungsi ini, panggil fungsi interruptHandler () seperti yang ditunjukkan di bawah ini.
lama debouncing_time = 150; volatile unsigned long last_micros; void debounceInterrupt () { if ((long) (micros () - last_micros)> = debouncing_time * 1000) { interruptHandler (); last_micros = micros (); } }
Dalam fungsi interruptHandler () , panggil xSemaphoreGiveFromISR () API.
void interruptHandler () { xSemaphoreGiveFromISR (interruptSemaphore, NULL); }
Fungsi ini akan memberikan semaphore pada TaskLed untuk menyalakan LED.
5. Buat fungsi TaskLed dan di dalam while loop, panggil xSemaphoreTake () API dan periksa apakah semaphore berhasil diambil atau tidak. Jika sama dengan pdPASS (mis. 1) maka matikan LED seperti yang ditunjukkan di bawah ini.
void TaskLed (void * pvParameters) { (void) pvParameters; pinMode (8, OUTPUT); sementara (1) { if (xSemaphoreTake (interruptSemaphore, portMAX_DELAY) == pdPASS) { digitalWrite (8 ,! digitalRead (8)); } } }
6. Selain itu, buat fungsi untuk mengedipkan LED lain yang terhubung ke pin 7.
void TaskLed1 (void * pvParameters) { (void) pvParameters; pinMode (7, OUTPUT); sementara (1) { digitalWrite (7, HIGH); vTaskDelay (200 / portTICK_PERIOD_MS); digitalWrite (7, LOW); vTaskDelay (200 / portTICK_PERIOD_MS); } }
7. Fungsi void loop akan tetap kosong. Jangan lupakan.
void loop () {}
Itu saja, kode lengkap dapat ditemukan di akhir tutorial ini. Sekarang, unggah kode ini dan hubungkan LED dan tombol tekan dengan Arduino UNO sesuai diagram sirkuit.
Diagram Sirkuit
Setelah meng-upload kode, Anda akan melihat LED berkedip setelah 200ms dan ketika tombol ditekan, langsung LED kedua akan menyala seperti yang ditunjukkan pada video yang diberikan di bagian akhir.
Dengan cara ini, semaphore dapat digunakan di FreeRTOS dengan Arduino di mana ia perlu meneruskan data dari satu tugas ke tugas lainnya tanpa kehilangan.
Sekarang, mari kita lihat apa itu Mutex dan bagaimana cara menggunakannya FreeRTOS.
Apa Mutex?
Seperti yang dijelaskan di atas semaphore adalah mekanisme pensinyalan, demikian pula, Mutex adalah mekanisme penguncian tidak seperti semaphore yang memiliki fungsi terpisah untuk kenaikan dan penurunan tetapi di Mutex, fungsi mengambil dan memberi dalam dirinya sendiri. Ini adalah teknik untuk menghindari korupsi sumber daya bersama.
Untuk melindungi sumber daya bersama, seseorang menetapkan kartu token (mutex) ke sumber daya. Siapa pun yang memiliki kartu ini dapat mengakses sumber daya lain. Yang lain harus menunggu sampai kartu dikembalikan. Dengan cara ini, hanya satu sumber daya yang dapat mengakses tugas dan yang lainnya menunggu kesempatan mereka.
Mari kita pahami Mutex di FreeRTOS dengan bantuan sebuah contoh.
Di sini kita memiliki tiga tugas, satu tugas mencetak data pada LCD, tugas kedua mengirim data LDR ke LCD dan tugas terakhir mengirim data suhu pada LCD. Jadi di sini dua tugas berbagi sumber daya yang sama yaitu LCD. Jika tugas LDR dan tugas suhu mengirim data secara bersamaan maka salah satu data mungkin rusak atau hilang.
Jadi untuk melindungi kehilangan data, kita perlu mengunci sumber daya LCD untuk task1 sampai tugas tampilan selesai. Kemudian tugas LCD akan terbuka dan kemudian task2 dapat melakukan tugasnya.
Anda dapat mengamati cara kerja Mutex dan semaphore pada diagram di bawah ini.
Bagaimana cara menggunakan Mutex di FreeRTOS?
Mutex juga digunakan dengan cara yang sama seperti semaphore. Pertama, buat, lalu berikan dan terima menggunakan API masing-masing.
Membuat Mutex:
Untuk membuat Mutex, gunakan xSemaphoreCreateMutex () API . Seperti namanya, Mutex adalah sejenis semafor Biner. Mereka digunakan dalam konteks dan tujuan yang berbeda. Semaphore biner untuk menyinkronkan tugas sementara Mutex digunakan untuk melindungi sumber daya bersama.
API ini tidak mengambil argumen apa pun dan mengembalikan variabel berjenis SemaphoreHandle_t . Jika mutex tidak dapat dibuat, xSemaphoreCreateMutex () mengembalikan NULL.
SemaphoreHandle_t mutex_v; mutex_v = xSemaphoreCreateMutex ();
Mengambil Mutex:
Ketika tugas ingin mengakses sumber daya, itu akan mengambil Mutex dengan menggunakan xSemaphoreTake () API. Ini sama dengan semafor biner. Ini juga membutuhkan dua parameter.
xSemaphore: Nama Mutex yang akan diambil dalam kasus kami mutex_v .
xTicksToWait: Ini adalah jumlah waktu maksimum tugas akan menunggu dalam status Diblokir agar Mutex tersedia. Dalam proyek kami, kami akan menyetel xTicksToWait ke portMAX_DELAY untuk membuat task_1 menunggu tanpa batas waktu dalam status Diblokir hingga mutex_v tersedia.
Memberikan Mutex:
Setelah mengakses sumber daya bersama, tugas harus mengembalikan Mutex agar tugas lain dapat mengaksesnya. xSemaphoreGive () API digunakan untuk mengembalikan Mutex.
Fungsi xSemaphoreGive () hanya membutuhkan satu argumen yang Mutex akan diberikan dalam kasus kami mutex_v.
Menggunakan API di atas, Mari terapkan Mutex dalam kode FreeRTOS menggunakan Arduino IDE.
Penjelasan Kode Mutex
Di sini tujuan bagian ini adalah menggunakan monitor Serial sebagai sumber daya bersama dan dua tugas berbeda untuk mengakses monitor serial untuk mencetak beberapa pesan.
1. File header akan tetap sama seperti semaphore.
#include #include
2. Deklarasikan variabel jenis SemaphoreHandle_t untuk menyimpan nilai Mutex.
SemaphoreHandle_t mutex_v;
3. Dalam void setup (), inisialisasi monitor serial dengan 9600 baud rate dan buat dua tugas (Task1 dan Task2) menggunakan xTaskCreate () API. Kemudian buat Mutex menggunakan xSemaphoreCreateMutex (). Buat tugas dengan prioritas yang sama dan kemudian cobalah bermain dengan nomor ini.
void setup () { Serial.begin (9600); mutex_v = xSemaphoreCreateMutex (); if (mutex_v == NULL) { Serial.println ("Mutex tidak dapat dibuat"); } xTaskCreate (Task1, "Task 1", 128, NULL, 1, NULL); xTaskCreate (Task2, "Task 2", 128, NULL, 1, NULL); }
4. Sekarang, buat fungsi tugas untuk Task1 dan Task2. Dalam fungsi while loop of task, sebelum mencetak pesan pada monitor serial kita harus mengambil Mutex menggunakan xSemaphoreTake () kemudian mencetak pesan dan kemudian mengembalikan Mutex menggunakan xSemaphoreGive (). Kemudian berikan penundaan.
void Task1 (void * pvParameters) { while (1) { xSemaphoreTake (mutex_v, portMAX_DELAY); Serial.println ("Hai dari Task1"); xSemaphoreGive (mutex_v); vTaskDelay (pdMS_TO_TICKS (1000)); } }
Demikian pula, implementasikan fungsi Task2 dengan jeda 500ms.
5. Void loop () akan tetap kosong.
Sekarang, unggah kode ini di Arduino UNO dan buka monitor serial.
Anda akan melihat pesan sedang dicetak dari task1 dan task2.
Untuk menguji kerja Mutex, cukup beri komentar xSemaphoreGive (mutex_v); dari tugas apa pun. Anda dapat melihat bahwa program hang pada pesan cetak terakhir .
Ini adalah bagaimana Semaphore dan Mutex dapat diimplementasikan di FreeRTOS dengan Arduino. Untuk informasi lebih lanjut tentang Semaphore dan Mutex, Anda dapat mengunjungi dokumentasi resmi FreeRTOS.
Kode lengkap dan video untuk Semaphore dan Bisu diberikan di bawah ini.