- Apa itu Semaphore?
- Bagaimana cara menggunakan Semaphore di FreeRTOS?
- Penjelasan Kod Semaphore
- Rajah Litar
- Apa itu Mutex?
- Bagaimana cara menggunakan Mutex di FreeRTOS?
- Penjelasan Kod Mutex
Dalam tutorial sebelumnya, kami telah membahas asas-asas FreeRTOS dengan Arduino dan objek inti Queue di FreeRTOS Arduino. Sekarang, dalam tutorial FreeRTOS ketiga ini, kita akan mengetahui lebih lanjut mengenai FreeRTOS dan API lanjutannya, yang dapat membuat anda memahami platform berbilang tugas dengan lebih mendalam.
Semaphore dan Mutex (Mutual Exclusion) adalah objek kernel yang digunakan untuk penyegerakan, pengurusan sumber dan melindungi sumber dari kerosakan. Pada separuh pertama tutorial ini, kita akan melihat idea di sebalik Semaphore, bagaimana dan di mana menggunakannya. Pada separuh masa kedua, kami akan meneruskan Mutex.
Apa itu Semaphore?
Dalam tutorial sebelumnya, kami telah membincangkan mengenai keutamaan tugas dan juga mengetahui bahawa tugas dengan keutamaan yang lebih tinggi mendahulukan tugas dengan keutamaan yang lebih rendah sehingga sementara pelaksanaan tugas dengan prioritas tinggi mungkin ada kemungkinan korupsi data dapat terjadi pada tugas dengan prioritas yang lebih rendah kerana belum dilaksanakan dan data terus menerus ke tugas ini dari sensor yang menyebabkan kehilangan data dan kerosakan keseluruhan aplikasi.
Jadi, ada keperluan untuk melindungi sumber dari kehilangan data dan di sini Semaphore memainkan peranan penting.
Semaphore adalah mekanisme isyarat di mana tugas dalam keadaan menunggu ditandakan oleh tugas lain untuk pelaksanaan. Dengan kata lain, apabila tugas1 menyelesaikan kerjanya, maka ia akan menunjukkan bendera atau menaikkan bendera dengan 1 dan kemudian bendera ini diterima oleh tugas lain (tugas2) yang menunjukkan bahawa ia dapat menjalankan tugasnya sekarang. Apabila task2 selesai kerjanya maka bendera akan diturunkan sebanyak 1.
Jadi, pada dasarnya, itu adalah mekanisme "Beri" dan "Ambil" dan semaphore adalah pemboleh ubah integer yang digunakan untuk menyegerakkan akses ke sumber.
Jenis Semaphore dalam FreeRTOS:
Semaphore ada dua jenis.
- Semaphore Perduaan
- Mengira Semaphore
1. Binary Semaphore: Ia mempunyai dua nilai integer 0 dan 1. Ia agak serupa dengan Antrian panjang 1. Contohnya, kita mempunyai dua tugas, task1 dan task2. Task1 menghantar data ke task2 sehingga task2 terus memeriksa item quueue jika ada 1, maka dapat membaca data yang harus ditunggu hingga menjadi 1. Setelah mengambil data, task2 mengurangi queue dan membuatnya 0 Itu bermaksud task1 lagi dapat menghantar data ke task2.
Dari contoh di atas, dapat dikatakan bahawa semaphore binari digunakan untuk penyegerakan antara tugas atau antara tugas dan mengganggu.
2. Membilang Semaphore: Ia mempunyai nilai yang lebih besar dari 0 dan boleh dianggap beratur panjang lebih dari 1. Semaphore ini digunakan untuk mengira peristiwa. Dalam senario penggunaan ini, pengendali acara akan 'memberikan' semaphore setiap kali peristiwa berlaku (meningkatkan nilai kiraan semaphore), dan tugas pengendali akan 'mengambil' semaphore setiap kali memproses suatu peristiwa (penurunan nilai kiraan semaphore).
Oleh itu, nilai kiraan adalah perbezaan antara jumlah peristiwa yang telah berlaku dan jumlah yang telah diproses.
Sekarang, mari lihat bagaimana menggunakan Semaphore dalam kod FreeRTOS kami.
Bagaimana cara menggunakan Semaphore di FreeRTOS?
FreeRTOS menyokong API yang berbeza untuk membuat semaphore, mengambil semaphore dan memberi semaphore.
Sekarang, boleh ada dua jenis API untuk objek kernel yang sama. Sekiranya kita harus memberikan semaphore dari ISR, maka API semaphore normal tidak dapat digunakan. Anda harus menggunakan API yang dilindungi gangguan.
Dalam tutorial ini, kita akan menggunakan semaphore binari kerana senang difahami dan dilaksanakan. Oleh kerana fungsi gangguan digunakan di sini, anda perlu menggunakan API yang dilindungi gangguan dalam fungsi ISR. Apabila kita mengatakan menyegerakkan tugas dengan gangguan, itu bermaksud meletakkan tugas ke keadaan Menjalankan tepat selepas ISR.
Membuat Semaphore:
Untuk menggunakan objek kernel, kita harus membuatnya terlebih dahulu. Untuk membuat semaphore binari, gunakan vSemaphoreCreateBinary ().
API ini tidak mengambil parameter apa pun dan mengembalikan pemboleh ubah jenis SemaphoreHandle_t. Nama pemboleh ubah global sema_v dibuat untuk menyimpan semaphore.
SemaphoreHandle_t sema_v; sema_v = xSemaphoreCreateBinary ();
Memberi semaphore:
Untuk memberikan semaphore, ada dua versi - satu untuk gangguan dan satu lagi untuk tugas biasa.
- xSemaphoreGive (): API ini hanya mengambil satu argumen yang merupakan nama pemboleh ubah semaphore seperti sema_v seperti yang diberikan di atas semasa membuat semaphore. Ia boleh dipanggil dari tugas biasa yang anda mahu segerakkan.
- xSemaphoreGiveFromISR (): Ini adalah versi API dilindungi gangguan xSemaphoreGive (). Apabila kita perlu menyegerakkan ISR dan tugas biasa, maka xSemaphoreGiveFromISR () harus digunakan dari fungsi ISR.
Mengambil semaphore:
Untuk mengambil semaphore, gunakan fungsi API xSemaphoreTake (). API ini mengambil dua parameter.
xSemaphoreTake (SemaphoreHandle_t xSemaphore, TickType_t xTicksToWait);
xSemaphore: Nama semaphore yang akan diambil dalam kes kita sema_v.
xTicksToWait: Ini adalah jumlah masa maksimum yang akan ditunggu tugas dalam keadaan Disekat sehingga semaphore tersedia. Dalam projek kami, kami akan menetapkan xTicksToWait ke portMAX_DELAY untuk membuat task_1 menunggu selama-lamanya dalam keadaan Disekat sehingga sema_v tersedia.
Sekarang, mari gunakan API ini dan tulis kod untuk melaksanakan beberapa tugas.
Di sini satu butang tekan dan dua LED dihubungkan. Butang tekan akan bertindak sebagai butang terputus yang dipasang pada pin 2 Arduino Uno. Apabila butang ini ditekan, gangguan akan dihasilkan dan LED yang disambungkan ke pin 8 akan dihidupkan dan apabila anda menekannya lagi, ia akan mati.
Jadi, apabila butang ditekan xSemaphoreGiveFromISR () akan dipanggil dari fungsi ISR dan fungsi xSemaphoreTake () akan dipanggil dari fungsi TaskLED.
Untuk menjadikan sistem kelihatan multitasking, sambungkan LED lain dengan pin 7 yang akan sentiasa berkedip.
Penjelasan Kod Semaphore
Mari mula menulis kod untuk dengan membuka Arduino IDE
1. Pertama, sertakan fail tajuk Arduino_FreeRTOS.h . Sekarang, jika ada objek kernel yang digunakan seperti queue semaphore, maka fail header juga mesti disertakan untuknya.
#sertakan #sertakan
2. Menyatakan pemboleh ubah jenis SemaphoreHandle_t untuk menyimpan nilai semaphore.
SemaphoreHandle_t menggangguSemaphore;
3. Dalam persediaan kosong (), buat dua tugas (TaskLED dan TaskBlink) menggunakan API xTaskCreate () dan kemudian buat semaphore menggunakan xSemaphoreCreateBinary (). Buat tugas dengan keutamaan yang sama dan kemudian cuba bermain dengan nombor ini. Juga, Konfigurasikan pin 2 sebagai input dan aktifkan resistor penarik dalaman dan pasangkan pin interrupt. Akhirnya, mulakan penjadual seperti yang ditunjukkan di bawah.
batal persediaan () { pinMode (2, INPUT_PULLUP); xTaskCreate (TaskLed, "Led", 128, NULL, 0, NULL); xTaskCreate (TaskBlink, "LedBlink", 128, NULL, 0, NULL); interruptSemaphore = xSemaphoreCreateBinary (); jika (interruptSemaphore! = NULL) { attachInterrupt (digitalPinToInterrupt (2), debounceInterrupt, RENDAH); } }
4. Sekarang, laksanakan fungsi ISR. Jadikan fungsi dan namakan sama dengan argumen kedua fungsi attachInterrupt () . Untuk membuat gangguan berfungsi dengan betul, anda perlu menghilangkan masalah penurunan butang menggunakan fungsi milis atau mikro dan dengan menyesuaikan masa penurunan. Dari fungsi ini, panggil fungsi interruptHandler () seperti gambar di bawah.
debouncing_time yang panjang = 150; Last_micros yang tidak ditandatangani lama tidak stabil; batal debounceInterrupt () { if ((long) (micros () - last_micros)> = debouncing_time * 1000) { interruptHandler (); last_micros = mikro (); } }
Dalam fungsi interruptHandler () , panggil API xSemaphoreGiveFromISR () .
batal interruptHandler () { xSemaphoreGiveFromISR (interruptSemaphore, NULL); }
Fungsi ini akan memberi semaphore kepada TaskLed untuk menghidupkan LED.
5. Buat fungsi TaskLed dan di dalam loop sementara , panggil API xSemaphoreTake () dan periksa sama ada semaphore berjaya diambil atau tidak. Sekiranya sama dengan pdPASS (iaitu 1) maka buat togel LED seperti yang ditunjukkan di bawah.
void TaskLed (void * pvParameters) { (void) pvParameters; pinMode (8, OUTPUT); sementara (1) { if (xSemaphoreTake (interruptSemaphore, portMAX_DELAY) == pdPASS) { digitalWrite (8,! digitalRead (8)); } } }
6. Juga, buat fungsi untuk mengedipkan LED lain yang disambungkan ke pin 7.
void TaskLed1 (void * pvParameters) { (void) pvParameters; pinMode (7, OUTPUT); sementara (1) { digitalWrite (7, TINGGI); vTaskDelay (200 / portTICK_PERIOD_MS); digitalWrite (7, RENDAH); vTaskDelay (200 / portTICK_PERIOD_MS); } }
7. Fungsi gelung void akan tetap kosong. Jangan lupa.
gelung kosong () {}
Itu sahaja, kod lengkap boleh didapati di akhir tutorial ini. Sekarang, muat naik kod ini dan sambungkan LED dan butang tekan dengan Arduino UNO mengikut gambarajah litar.
Rajah Litar
Setelah memuat naik kod, anda akan melihat LED berkelip setelah 200ms dan ketika butang ditekan, segera LED kedua akan bersinar seperti yang ditunjukkan dalam video yang diberikan di akhir.
Dengan cara ini, semaphores dapat digunakan dalam FreeRTOS dengan Arduino di mana ia perlu menyampaikan data dari satu tugas ke tugas lain tanpa kerugian.
Sekarang, mari kita lihat apa itu Mutex dan bagaimana menggunakannya FreeRTOS.
Apa itu Mutex?
Seperti yang dijelaskan di atas semaphore adalah mekanisme isyarat, sama, Mutex adalah mekanisme penguncian tidak seperti semaphore yang mempunyai fungsi terpisah untuk kenaikan dan penurunan tetapi dalam Mutex, fungsi tersebut mengambil dan memberikannya sendiri. Ini adalah teknik untuk mengelakkan kerosakan sumber yang dikongsi.
Untuk melindungi sumber yang dikongsi, seseorang memberikan kad token (mutex) ke sumber tersebut. Sesiapa yang mempunyai kad ini boleh mengakses sumber lain. Yang lain harus menunggu sehingga kad dikembalikan. Dengan cara ini, hanya satu sumber yang dapat mengakses tugas dan yang lain menunggu peluang mereka.
Mari kita fahami Mutex dalam FreeRTOS dengan bantuan contoh.
Di sini kita mempunyai tiga tugas, Satu untuk mencetak data pada LCD, kedua untuk mengirim data LDR ke tugas LCD dan tugas terakhir untuk mengirim data Suhu pada LCD. Jadi di sini dua tugas adalah berkongsi sumber yang sama iaitu LCD. Sekiranya tugas LDR dan tugas suhu menghantar data secara serentak maka salah satu data tersebut mungkin rosak atau hilang.
Jadi untuk melindungi kehilangan data, kita perlu mengunci sumber LCD untuk task1 sehingga selesai tugas paparan. Kemudian tugas LCD akan dibuka dan kemudian task2 dapat menjalankan tugasnya.
Anda dapat melihat cara kerja Mutex dan semaphores dalam rajah di bawah.
Bagaimana cara menggunakan Mutex di FreeRTOS?
Mutex juga digunakan dengan cara yang sama seperti semaphores. Pertama, buat, kemudian berikan dan ambil menggunakan API masing-masing.
Membuat Mutex:
Untuk membuat Mutex, gunakan API xSemaphoreCreateMutex () . Seperti namanya menunjukkan bahawa Mutex adalah sejenis semaphore Binary. Mereka digunakan dalam konteks dan tujuan yang berbeza. Semaphore binari adalah untuk menyegerakkan tugas sementara Mutex digunakan untuk melindungi sumber yang dikongsi.
API ini tidak mengambil argumen dan mengembalikan pemboleh ubah jenis SemaphoreHandle_t . Sekiranya mutex tidak dapat dibuat, xSemaphoreCreateMutex () mengembalikan NULL.
SemaphoreHandle_t mutex_v; mutex_v = xSemaphoreCreateMutex ();
Mengambil Mutex:
Apabila tugas ingin mengakses sumber, ia memerlukan Mutex dengan menggunakan API xSemaphoreTake () . Ia sama dengan semaphore binari. Ia juga memerlukan dua parameter.
xSemaphore: Nama Mutex yang akan diambil dalam kes kami mutex_v .
xTicksToWait: Ini adalah jumlah masa maksimum yang akan ditunggu tugas dalam keadaan disekat sehingga Mutex tersedia. Dalam projek kami, kami akan menetapkan xTicksToWait ke portMAX_DELAY untuk membuat tugas_1 menunggu selama-lamanya dalam keadaan Disekat sehingga mutex_v tersedia.
Memberi Mutex:
Setelah mengakses sumber yang dikongsi, tugas tersebut harus mengembalikan Mutex sehingga tugas lain dapat mengaksesnya. API xSemaphoreGive () digunakan untuk mengembalikan Mutex.
Fungsi xSemaphoreGive () hanya mengambil satu argumen iaitu Mutex yang akan diberikan dalam kes kita mutex_v.
Dengan menggunakan API di atas, Mari kita laksanakan Mutex dalam kod FreeRTOS menggunakan Arduino IDE.
Penjelasan Kod Mutex
Di sini tujuan bahagian ini adalah menggunakan monitor Serial sebagai sumber bersama dan dua tugas yang berbeza untuk mengakses monitor bersiri untuk mencetak beberapa mesej.
1. Fail header akan tetap sama dengan semaphore.
#sertakan #sertakan
2. Menyatakan pemboleh ubah jenis SemaphoreHandle_t untuk menyimpan nilai-nilai Mutex.
SemaphoreHandle_t mutex_v;
3. Dalam persediaan kosong (), mulakan monitor bersiri dengan kadar baud 9600 dan buat dua tugas (Task1 dan Task2) menggunakan API xTaskCreate () . Kemudian buat Mutex menggunakan xSemaphoreCreateMutex (). Buat tugas dengan keutamaan yang sama dan kemudian cuba bermain dengan nombor ini.
persediaan tidak sah () { 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 fungsi loop sementara , sebelum mencetak mesej pada monitor bersiri kita harus mengambil Mutex menggunakan xSemaphoreTake () kemudian mencetak mesej dan kemudian mengembalikan Mutex menggunakan xSemaphoreGive (). Kemudian berikan sedikit kelewatan.
void Task1 (void * pvParameters) { manakala (1) { xSemaphoreTake (mutex_v, portMAX_DELAY); Serial.println ("Hi from Task1"); xSemaphoreGive (mutex_v); vTaskDelay (pdMS_TO_TICKS (1000)); } }
Begitu juga, melaksanakan fungsi Task2 dengan kelewatan 500ms.
5. Gelung kekosongan () akan tetap kosong.
Sekarang, muat naik kod ini di Arduino UNO dan buka monitor bersiri.
Anda akan melihat mesej dicetak dari task1 dan task2.
Untuk menguji cara kerja Mutex, hanya komen xSemaphoreGive (mutex_v); dari sebarang tugas. Anda dapat melihat bahawa program ini tergantung pada mesej cetak terakhir .
Ini adalah bagaimana Semaphore dan Mutex dapat dilaksanakan di FreeRTOS dengan Arduino. Untuk maklumat lebih lanjut mengenai Semaphore dan Mutex, anda boleh mengunjungi dokumentasi rasmi FreeRTOS.
Kod dan video lengkap untuk Semaphore dan Mute diberikan di bawah.