Arduino ile Rtos Kullanımı
|Merhaba Arkadaşlar,
Bu yazıda bahsedeceğimiz konu gerçek zamanlı işletim sistemleri ve arduino ile kullanımı olacaktır. Gerçek zamanlı işletim sistemleri zaman kaybı olmaksızın çalışmayı hedefleyen işletim sistemi türüdür.
Gerçek zamanlı işletim sistemleri bilgisayarlarımızın bu kadar işlevsel olmasının en büyük nedenlerinden biridir belki de… Bilgisayarlarımız biz fark etmesek bile bu olayı çok sık kullanırlar. Ekran kartları her pikseli eş zamanlı kontrol ederek zaman kaybını en aza indirirken bilgisayarımızla aynı anda farklı işlemlerde yapabiliriz. Bunun gibi aynı anda birden fazla iş yapma yeteneğine multi-tasking adı verilmektedir.
Gömülü Sistemlerde Rtos
Gömülü sistemler dediğimiz önceden belirlenmiş işleri yerine getiren yapılar genellikle gerçek zamanlı olarak çalışmaktadır. Örneğin bir arabanın hava yastığının zaman kaybı olmaksızın çalışmasını bekleriz. Eğer ki işlemci sadece hava yastığını kontrol etmek için tasarlanmışsa bu durum çok sorun oluşturmayacaktır. Ancak işlemci üzerinde uzun sürebilecek işlerde yaptırılıyorsa işlemci hiyerarşisinden dolayı zaman kaybına yol açar. Bu durumun önüne geçmek için birbirinden bağımsız ve eş zamanlı çalışan yapılar oluşturmak iyi bir yoldur. Bu gibi asenkron yapılar oluşturmanın farklı bir çok yolu vardır. Bunlar donanımsal ve ya yazılımsal olabilmektedir.Dünyada kullanılan farlı rtos örnekleri vardır.En yaygın kullanılanların bazıları şunlardır;
FreeRtos
RTLinux
VxWorks
OSE
QNX
Windows CE, gibi farklı rtos çeşitleri vardır. Biz bunlardan ücretsiz ve dökümanı daha fazla olan FreeRtos’u kullanacağız.
Rtos kullanmanın işlem önceliği, paralel işlem gibi özellikleri olması yanında dezavantajlarıda vardır.
Task sayısı artıkça yazdığımız kodun doğruluğu azalabileceği gibi hedeflediğimiz gerçek zamanlı işlemlerden uzaklaşmanıza yol açabilir. Rtos basit bir mikrodenetleyici için bazen iyi bir tercih olmayabilir. Her rtos CPU’ya ciddi bir yük oluşturmaktadır. Bu yüzden rtos kullanırken mikro denetleyicinin yapısına uygun kod yazmamız gerekir.
Şimdi de Arduino üzerinde FreeRtos kütüphanesi ile basit bir asenkron yapı oluşturalım.
Gerekli kütüphaneyi buradan indirebilirsiniz. Ya da arduino idesi üzerinden kütüphane düzenleme kısmından ‘FreeRtos’ yazarakta import edebilirsiniz.
Aşağıda ki devrede bulunan 4 tane ledi rtos kullanarak farklı bekletme (delay) süreleri ile basit bir blink uygulaması yapalım.
İlk önce her bir led için farklı iş parçacığı oluşturmamız gerekiyor.
xTaskCreate(MyTask1, "Task1", 100, NULL, 1, NULL);//MyTask1 fonk. ismi // 1 ise ilk yapılacak iş olduğunu belirtmek için kullandık xTaskCreate(MyTask2, "Task2", 100, NULL, 2, NULL); xTaskCreate(MyTask3, "Task3", 100, NULL, 3, NULL); xTaskCreate(MyIdleTask, "IdleTask", 100, NULL, 0, NULL);//Bu özel iş parçacığı öncelikli işler bittikten sonra çalışan fonk. dur
İş parçacıklarını bu şekilde oluşturduktan sonra dikkat etmemiz gereken bazı noktalar var.Bunlardan birincisi artık void loop döngüsünün içinin boş kalması gerekmektedir.Bütün işlerimizi oluşturduğumuz taskler üzerinden gerçekleştircez.
#include <Arduino_FreeRTOS.h> void setup() { Serial.begin(9600); pinMode(3, OUTPUT); pinMode(4, OUTPUT); pinMode(5, OUTPUT); pinMode(6, OUTPUT); xTaskCreate(MyTask1, "Task1", 100, NULL, 3, NULL); xTaskCreate(MyTask2, "Task2", 100, NULL, 2, NULL); xTaskCreate(MyTask3, "Task3", 100, NULL, 1, NULL); xTaskCreate(MyIdleTask, "IdleTask", 100, NULL, 0, NULL); } void loop() { //Bu kısım boş } static void MyTask1(void* pvParameters) { while (true){ digitalWrite(3, HIGH); vTaskDelay(100 / portTICK_PERIOD_MS);//100 ms digitalWrite(3, LOW); vTaskDelay(100 / portTICK_PERIOD_MS); Serial.println(F("Task1")); } } static void MyTask2(void* pvParameters) { while (true) { digitalWrite(4, HIGH); vTaskDelay(1000 / portTICK_PERIOD_MS);//1000 ms digitalWrite(4, LOW); vTaskDelay(1000 / portTICK_PERIOD_MS); Serial.println(F("Task2")); } } static void MyTask3(void* pvParameters) { while (true){ digitalWrite(5, HIGH); vTaskDelay(2000 / portTICK_PERIOD_MS);//2000 ms digitalWrite(5, LOW); vTaskDelay(2000 / portTICK_PERIOD_MS); Serial.println(F("Task3")); } } static void MyIdleTask(void* pvParameters) { while (true){ digitalWrite(6, HIGH); delay(3000);//3000 ms digitalWrite(6, LOW); delay(3000); Serial.println(F("Idle state")); } }
Bu kodu arduino ya yüklediğimiz zaman ledlerin birbirinden bağımsız bir şekilde farklı sürelerde blink yaptığını görebiliyoruz.
Aslında bizim alıştığımız durumdan biraz daha farklı ilerliyor kodlar.Yukarıdan aşağıya doğru bir ilerleme olmuyor.Şimdi adım adım yazılımda olanları takip edelim.
- Oluşturduğumuz iş parçacıklarından sonra kod yapısının ilerlemesini timer ve çekirdek ayarlıyor.
- İş önceliği en yüksek olan ‘myTask1’ ilk önce çalışır.
vTaskDelay(100 / portTICK_PERIOD_MS);
bu satıra kadar bütün işleri yapar ve iş 100 ms boyunca bloke edilir.Yani3 numaralı pine bağlı led HIGH durumunda kalır.
- Artık zamanlayıcı için 3 iş kaldı geriye ve önceliği yüksek olan ‘myTask2’ i çalıştırır.Aynı şekilde bu fonksiyonda çalışır ve led 1000 ms boyunca HIGH durumunda bloke edilir.
- myTask3 de 2000 ms boyunca bloke edilir.6 numaralı pine bağlı led 2000 ms boyunca HIGH kalır.
- Öncelikli bütün işler bittikten sonra timer myIdleTask i çalıştırıyor.
- Bloke süresi biten taskler için while döngüsü içinde ki kodu çalıştırmaya devam ediyor.Bu şekilde bir döngü içine girmiş oluyor yazılımımız.
Peki bu sistemin hiç mi eksik yönleri yok? Tabii ki var.. Arduino(uno,nano vs..) nun tek çekirdekli ve 16 mhZ lik bir işlemcisi olduğunu düşünürsek yapılan bu iş için zaman kaybı olması çok doğal.Eğer en başta 2 tane task oluşturmuş olsaydık taskler arasında geçişte ortalama 15 ms’lik bir kayıp yaşancağını kütüphanede yazmaktadır.Bizim gibi 4 tane task oluşturduğumuzda ise bu kayıp 50 ms’ye kadar çıkmaktadır.
Önemli bir nokta ise eğer ki tasklerin içinde zamanı ayarlamamıza yardımcı olan “portTICK_PERIOD_MS” ifadesine gelene kadar işlemciye zaman alan bir işlem yaptırıyorsanız bu geçen zamanı hesaplayıp bloke süresini ona göre düzenlemenizde fayda var.
Not: Yapacağınız işleme bağlı olarak millis,timer yada donanımsal olarak bu iş yaptırmak isterseniz interrupt kullanmak iyi bir seçenek olabilir.
İyi çalışmalar..
Çok teşekkür ederim kardeşim. Çok faydan oldu ….