Sadece Arduino Öğrenmek Yeterli Mi ? - Lojik Prob
by Gökhan Dökmetaş · Published 02/04/2019 · Updated 02/04/2019
Arduino kitlesi içerisinde fanatik diye tabir edebileceğimiz ve Arduino’ya sıkı sıkıya bağlı ve Arduino ile her şeyi yapabileceğini düşünenler olsa da bu alanda “Eğitimci” olarak ortaya çıkan ve pazarlama dili ile konuşanlar da sık sık Arduino ile yapabileceklerinizin hayal gücünüzle sınırlı olduğunu söylerler. Bu söylem Arduino’nun işin son noktası olduğu ve sadece Arduino öğrenmenin yeterli olacağı yönünde yeni başlayanlar üzerinde bir algı oluşturmaktadır. Yapabileceğinizin hayal gücünüzle sınırlı olduğu bir platformdan iyisi olamaz değil mi ? Biz bir geliştiricinin ağzından size sadece Arduino öğrenmenin yeterli olup olmadığını ayrıntıları ile anlatacağız. Fakat öncelikle Arduino nedir sorusunu bizce cevapladıktan sonra buna değinmemiz gerekecektir.
“Arduino Nedir?” diye onlarca video ve makale bulabilseniz de biz bunları referans almak yerine Arduino’yu baştan anlatmak zorundayız. Arduino Eğitim Kitabı’nda Arduino’nun ne olduğunu sayfalarca anlatmış olsam da burada yeni başlayanlara değil kendini geliştirmek isteyen geliştiricilere hitap ettiğimden daha farklı bir boyutta konuyu ele almam gerekli. Kitabımda yazdığım şeylerden farklı bir şey demeyecek olsam da üzerine koyacağım pek çok konu var.
Arduino kendini “mikrodenetleyici geliştirme platformu” olarak pazarlamaktadır. Kendisi böyle dememiş olsa bile bize bu şekilde lanse edilmektedir. Burada dikkat etmeniz gereken nokta Arduino’nun sadece bir karttan ibaret olmadığıdır. Arduino’dan önce pek çok mikrodenetleyici geliştirme kartı gelip geçmiştir ve Arduino bu yönüyle piyasaya çıksa çok da ses getirebilecek bir durumda olamazdı. Çünkü ilk Arduino kartı RS-232 ile programlanan ucuz bir mikrodenetleyici bulunduran ve üzerinde neredeyse bir şey olmayan bir asgari sistem halindeydi. Üstelik günümüzde bile Arduino kartları ilk zamanlardaki kartlardan çok farklı değildir. Zaman içerisinde bilgisayar ile olan iletişim protokolleri değişmiş elemanlar SMD kılıfa geçmiş ve kartlarda bazı ufak değişiklikler yapılmıştır. Bunlar kayda değer bir gelişme olmayıp donanım olarak Arduino ana seri kartlar bakımından (Uno, Nano, Mega) ilk çıktığı zaman ile hemen hemen aynıdır.
Arduino kartlarının açık kaynak olduğunu biliyoruz. Üzerine “Arduino” yazmadıktan sonra istediğimiz gibi klonunu üretebiliriz. Bunun için devre şemasını bile paylaşmaktalar. Bu şemaya bakarak bir kart çizmek belki birkaç saatinizi alacak kadar basit bir iştir. Günümüzde klon Arduino kartı üretenlerin alkışlandığını, fenomen olduklarını görüyoruz. Aslında bir klon Arduino yapmak devre kartı üretmeye atılan ilk adım olmalıdır.
Arduino’nun mikrodenetleyici geliştirme kartı değil platformu olduğunu yazılımsal boyutuna baktığımızda anlamaktayız. Yazılımsal boyutta Arduino’ya ait bir şey olmadığını gördüğümüzden neyin Arduino olduğu neyin Arduino olmadığı konusunda kafa karışıklığı yaşanmaktadır. Geliştirme stüdyosu Processing tabanlıdır, derleyici AVR-GCC derleyicisidir ve Arduino hazır olarak almıştır, ön yükleyici zaten üreticinin verdiği bir üründür, Arduino kütüphaneleri ise Wiring’den intihal edilmiştir.
Bu durumda Arduino donanımsal boyutta basit bir devre kartı iken yazılımsal boyutta da diğer yazılımların bir arada toplanmış halidir diyebiliriz. Yalnız bu durumda ortada Arduino denen kalmaması gereklidir. Çünkü Arduino’nun yaptığı tek şey burada kart üretmek ve bu kartları da açık kaynak olarak piyasaya sürmekte ve herkes üretebilmektedir. Burada bir farkın “marka” olduğunu ve Arduino’nun “marka” olarak varlığını koruduğunu görebiliriz. Yalnız sırf kart markası olmak Arduino’ya yeterli gelmemektedir. Çünkü Arduino gibi kartlar piyasada aşırı derecede fazladır ve pek çok Arduino’dan daha iyi kart da piyasaya sürülmektedir. Bu durumda Arduino ne kadar kart üretilirse üretilsin bütün kartların kendi derleyicilerinde ve kütüphanelerinde programlanmasını istemiştir. Arduino’nun tekel olduğu kısım donanım değil yazılımdır. Yazılımda tekel olması ise kopyaladığı Wiring kütüphanesini sahiplenmesinden ötürüdür.
Github’da “Arduino Core” diye arattığımızda Arduino’nun sahiplendiği uygulama programlama arayüzü karşımıza çıkmaktadır. Pek çok Arduino kullananın haberi olmasa da önemli bir noktadır. Fakat asıl mesele buradadır ve Arduino Core olmadan, Arduino Core üzerinde program yazmadan yaptığınız kart Arduino ile birebir aynı olsa da bir anlam ifade etmeyecektir. Çünkü Arduino programını çalıştırmayan bir karta Arduino denemez. Bu Arduino çekirdeğini Arduino kaynak kodu incelemesi çalışmamda büyük ölçüde inceledim. Bu işte ilerlemek isteyenlere de bu yazılardan faydalanmasını tavsiye ediyorum çünkü Arduino’yu bu kadar etraflıca inceleyen bir çalışmayı başka yerde göremezsiniz. Bazıları bootloader (önyükleyici) programının Arduino komutlarını çalıştıran bir interpreter (tercüman) program olduğunu sansa da bu tamamen yanlıştır. Hatta bazı eğitimlerde bile bundan böyle bahsedildiğini görmekteyim. Bootloader mikrodenetleyiciler üzerinde çalışanların yakından tanıdığı ve Arduino ile alakası olmayan bir program olup UART, SPI, I2C gibi iletişim arayüzleri ile programlayıcı olmadan program yazmaya yarayan bir programcıktır.
Kısacası Arduino’nun toplama ve bazen de kopyalama sonucu ortaya çıkan bir platform olduğunu söylebiliriz. Böyle bir platformu ortaya koymak için çok ileri mühendislik bilgisine ihtiyaç olmasa gerektir. O yüzden böyle bir platformun kartının klonunu yapabilmek de hiç büyük bir başarı değildir. Önemli olan Arduino gibi bir geliştirme platformu ortaya koymak olsa da Arduino medya gücünü etkili bir şekilde kullanmaktadır.
Burada kadar Arduino’nun marka, kart tasarımı ve sahiplendiği uygulama programlama arayüzünden ibaret olduğunu gördük. Peki bu kartları kullanarak ve uygulama programlama arayüzü ile neler yapabileceğimize bir bakalım. Gerçekten bir geliştirici için yeterli imkanları verip vermediğini görelim.
Arduino Yeterli Mi?
Arduino’nun sitesinden referans sayfasına baktığımızda öncelikle temel arduino fonksiyonları karşımıza çıkmaktadır. Bunlar resmi kütüphaneler içinde olmayan ve geliştirme arayüzünün temelinde olan fonksiyonlardır. Öncelikle bu fonksiyonların ne olduğunu görelim ve bu fonksiyonlarla ne yapabileceğimize bakalım.
Burada C/C++ dili ile alakalı fonksiyonların da olduğunu görmekteyiz. Diğer C derleyicilerinde de mevcut olan bu standart fonksiyonları Arduino’ya has fonksiyon olarak saymıyoruz. Çünkü Arduino’nun bir mikrodenetleyici geliştirme platformu olmasından dolayı mikrodenetleyiciyi geliştirmeye yönelik özellikleri ile karşımıza çıkması gerekli. Örneğin abs(), min(), pow() gibi fonksiyonlar C dilinin standart kütüphanesi içerisinde math.h başlık dosyasında zaten yer almaktadır. O yüzden C diline ait fonksiyonları görmezden geleceğiz.
Burada üç ana fonksiyonun en başta yer aldığını görebiliriz. Ben bu fonksiyonların büyük kısmını kaynak kodunu incelerden ayrıntısıyla size açıklamıştım ama burada tekrar hatırlatmak gerekirse digitalRead() fonksiyonu bir ayaktan okuma yapar, digitalWrite() fonksiyonu bir ayaktan çıkış alır ve pinMode() fonksiyonu bir ayağın giriş mi çıkış mı olacağını belirler.
Tek ayaktan tek bir fonksiyonla giriş ve çıkış almak işimizi kolaylaştırsa da bu fonksiyonların her birinin işletimi için 40’a yakın komut işlenmektedir. Örneğin alt alta yazacağımız iki digitalWrite() fonksiyonu 125kHz bir sinyal vermektedir. Aynı komutu AVR’de yazmaçlara müdahale ederek yazdığımızda aynı Arduino kartında 4MHz sinyal alabilmekteyiz!. Yazılımsal SPI, UART veya frekans üretme gibi işlerde bu bizi oldukça kısıtlayacaktır. Tek bir ayaktan bir fonksiyonla çıkış almak için değer mi acaba diye düşünebiliriz.
Paralel dijital giriş ve çıkış işlemlerinde ise işimiz oldukça zorlaşmaktadır. Arduino’nun intihal ettiği Wiring API’de port işlemlerine dair fonksiyonlar olsa da Arduino bunu alma gereği duymamıştır. Bu yüzden paralel işlemlerde işimiz oldukça zorlaşmaktadır. Eğer AVR programlamayı öğrenmeyip yazmaçlar üzerinden port işlemleri yapmayacaksanız alt alta digitalRead() veya dijitalWrite() komutu yazmanız gerekecektir. Portlar genelde 8-bit olduğundan bir baytlık veri işlemi için 8 adet yazmanız gerekli ve her biri için 40 komut çalıştırılacağından işiniz oldukça yavaşlamaktadır. 125kHz/8 dersek saniyede 15 bin adet port işlemi yapabilirsiniz demektir. Aynı kart üzerinde aynı frekansta sırf AVR kodu ile milyonlarca işlem yapmanız mümkün.
Analog işlemler konusunda Arduino’nun üç adet fonksiyonunu olduğunu görsek de bu fonksiyonların ikisi analog-dijital çevirimi için ADC birimini kullanmakta ötekisi ise PWM sinyali üretmektedir. O yüzden iki ayrı kategoride ele almamız gereklidir. Arduino UNO kartında kullanılan Atmegas328P mikrodenetleyicisinin teknik veri kitapçığına baktığımda ADC ile alakalı şu özellikleri görmekteyim.
ADC Çevirim Tamamlandığında Kesme Üretmesi
Otomatik tetikleme ve kaynak seçimi
Referans gerilimi seçimi
ADC Gürültü Engelleyici (Uyku Modu)
Veriyi sola hizalama
Serbest çevirim ya da tek çevirim modu
Biz analog dijital çevirimde Arduino’da analogRead() fonksiyonunu görmekteyiz. Yani Arduino bizim belirlediğimiz bir ayaktan bir kereliğine 10-bitlik bir okuma yapmaktadır. Biz çevirim tamamlandığında yürütülecek bir kesme kullanmak istiyoruz fakat Arduino’da bunu görememekteyiz. Otomatik tetikleme ve tetikleme kaynağı seçimi denen bir şey de yok. ADC’nin dahili sıcaklık algılayıcısını kullanabildiğini biliyoruz fakat bunu AVR kodları olmadan yapmamız imkansız. Üstelik ADC çeviriminde gürültü engelleme modunu da olmasına rağmen kullanamıyoruz. Bunu sırf Arduino bilgisi ile yapmamız mümkün değil. Referans gerilimini tam olarak seçebilsek de yukarıdaki özellikleri kullanamamaktayız. Sadece tek çevirim fonksiyonu ve referans seçme özelliği Arduino’ya eklenmiş.
Görüldüğü gibi Arduino mikrodenetleyici geliştirme platformu olarak çıkmasına karşın üzerinde çalıştığı mikrodenetleyicinin en temel birimlerinden birine ait çoğu özelliği bünyesine almamıştır. Bunun sebebi basitleştirmek için olsa da bir geliştirici bunları kullanmak durumunda kalabilir. Üretici boş yere bu özellikleri koyuyor değil.
analogWrite() fonksiyonu ise AVR üzerinde bulunan üç adet zamanlayıcıların sinyal çıkışları üzerinden 8-bitlik bir PWM sinyali vermektedir. Zamanlayıcıların kullanım alanlarından biri de PWM sinyalleri üretmektir. Yalnız bu PWM sinyalini tek bir modda ve 8-bit çözünürlükte üretmektedir. Oysa ki Atmega328P’de 16-bitlik bir zamanlayıcı bulunmakta ve 16-bitlik PWM çıkışı da verebilmektedir. Çoğu zaman kullanıcılar 8-bitlik PWM’nin çözünürlüğünden yakınsalar da Arduino bu özelliği yıllardan beri geliştirme arayüzüne eklememiştir. Ayrıca AVR mikrodenetleyicilerde birkaç farklı PWM modu yer almasına karşın Arduino tek bir PWM modunu kullanmaktadır. Bu PWM modları hakkında ayrıntılı bilgiyi sitede yazdık.
Zamanlayıcıların en temel görevlerinden biri ise frekans okumaktır. Hatta elektronikte frekans okumanız gereken pek çok yer karşınıza çıkmaktadır. Multimetrelerde bile frekans okuma özelliği olduğunu biliyoruz. AVR mikrodenetleyicilerde frekans okuma gayet hassas bir şekilde zamanlayıcılar vasıtasıyla yapılırken Arduino’da frekans okumaya dair herhangi bir fonksiyon bulunmamaktadır. Bunu AVR komutlarıyla üçüncü şahısların yazdığı kütüphaneler vasıtasıyla yapabiliriz. Hatta ben de Nick Gammon’un Arduino için yazdığı frekans okuma programını AVR derslerinde size anlatmıştım. Fakat bunu Arduino fonksiyonları ile yapmamız mümkün değildir. Arduino bizi bu konuda yarı yolda bırakmaktadır.
Zamanlayıcıların diğer temel özelliklerinden biri ise frekans üretmedir. Dikkat edin, frekans üretmeyi PWM sinyali üretmek ile karıştırmamanız gereklidir. Çünkü PWM sinyalinde frekans sabitken frekans üretmede frekansın değişken olması gereklidir. Alt alta yazacağınız digitalWrite() fonksiyonları da basit bir frekans üretse de örneğin biz 1kHz-1MHz arasında ayarlanabilir bir frekans üreteci yapmak istiyorsak AVR komutları ile zamanlayıcı yazmaçlarını programlayarak bunu yapmak zorundayız. Burada tone() fonksiyonu bir frekans üretse de bu sese yönelik olup belli bir sinyalden sonra fonksiyon kararsızlaşmaktadır. Yani ses haricinde bir işe yaramadığını söyleyebiliriz. Frekans okuma ve üretme işleriyle çok uğraştığım için başımdan geçen ve gurupta paylaştığım mesajı buraya aktarmak istiyorum.
Arduino’da program yazarken TC0 zamanlayıcısı boş olduğu için oraya basit bir frekans üreteci koyayım dedim. Yazdığım basit bir programdı ve sensöre göre frekans çıkışı verecekti. Bunun için tone fonksiyonu kullanmanın anlamı yoktu çünkü kullandığım başka bir kütüphane TC0 ve TC1 zamanlayıcılarını kullanmaktaydı ve tone fonksiyonunu kullanmak istediğimde hata alıyordum. Ben de boşta bekleyen bu zamanlayıcıyı kullanmak için şöyle bir kod yazdım.
int ocr_deger = map(deger, -2000, 1000, 0, 255);
OCR0A = ocr_deger;
TCCR0A |= (1<<COM0A0); // Toggle OC0A Compare Match
TCCR0A &=~ ((1<<COM0B1) | (1<<COM0B0));
TCCR0B |= ((1<<CS02));
Bu program loop() fonksiyonunun içerisinde yer almakta ve zamanlayıcının karşılaştırma yazmacının değerini sensörden okunan değere göre 8-bit olarak düzenlemektedir. Ön derecelendirici ayarından sonra güzel bir frekans aralığı elde ettim ve bunu hoparlörde rahatça duyabiliyordum.
Fakat ne yazık ki kodda herhangi bir hata olmamasına rağmen bilinmeyen bir sebepten dolayı program döngüsü 2 kere çalışıyor ve ardından duruyor bir daha işlemez oluyor. Programı tekrar derleyip attığımda bazen devamlı çalışıyor bazen çalışmıyor. Anlayacağınız üretilen kodda bir kararlılık yok! Üstelik işin ilginci Serial.println() fonksiyonunun altına yazdığım delay() fonksiyonu programın çalışıp çalışmamasını etkileyebiliyor. Biz delay fonksiyonunu sadece işlemciyi meşgul eden bir fonksiyon olarak bilirdik fakat burada kararsızlığı etkileyen bir durum olacak karşımıza çıkmakta.
Kısacası benim tek istediğim bir zamanlayıcıdan hoparlöre frekans çıkışı almaktı. Bunun için Arduino fonksiyonu yok biliyoruz fakat AVR komutlarıyla yazmak istediğimizde bile Arduino buna engel olmakta!.
Bu kararsızlığın sebebi Arduino’nun TC0 zamanlayıcısını millis() gibi fonksiyonları arkaplanda işletirken kullanmasıdır. Eğer kaynak kodu incelemeden bir iş yapmaya kalkarsanız bunlar birbiriyle çakışacaktır ve programınız kodlarınız tamamen doğru olsa da çalışmayacaktır. Bizim donanım özelliklerini kullanma yönündeki girişimimiz Arduino tarafından bu sayede engellenmiş bulunuyor.
Gördüğünüz gibi Arduino arkaplanda bazı donanım özelliklerini bizden habersiz kullandığı için biz bunu doğrudan kullanmak istersek programda kararsızlıklara sebep olabiliyoruz. Bunun için Arduino kaynak kodlarını incelemeli ve işin ayrıntısından haberdar olmak gereklidir.
Zamanlayıcıların bir özelliği de sinyal genişliğini okumaktır. Örneğin bir düğmeye ne kadar uzun süre bastığımızı zamanlayıcı sayarak okuyabilir ve bunun süresini hesaplayabilir. Arduino’da böyle bir özellik pulseIn() komutuyla olsa da bu aynı tone fonksiyonu gibi yazılımsal olmaktadır ve zamanlayıcıları kullanmamaktadır. Donanımsal olmaması performansı düşüren bir etken olarak karşımıza çıkmaktadır. Bunu donanım ile mikrodenetleyiciyi meşgul etmeden yapmak da mümkündür. Fakat bu konumda Arduino’da böyle bir özelliğin olmadığını söyleyemeyiz.
Zamanlayıcıların bir diğer kullanım alanı zaman hesaplamasıdır ve bunu millis() fonksiyonu ile Arduino kısıtlı bir biçimde bize vermektedir. millis() fonksiyonundan dönen değeri değiştirememek, üzerinde işlem yapamamak ve hep dolaylı olarak bu fonksiyondan alınan değerleri işlemek işimizi zorlaştırmakta ve yazacağımız programın esnekliğine olumsuz etki etmektedir. Yine de bir kaç basit formül ile frekans ve zaman hesaplaması yapmak istemeyenler veya bu konuda bilgisi olmayanlar için günü kurtaracak bir fonksiyondur. Fakat zamanlayıcıların zamanlama işlemini millis fonksiyonundan ibaret olarak bilip böyle kullanmak çok hatalı bir yoldur. Bu eksikliğin farkında olan geliştiriciler Arduino için pek çok zamanlayıcılar ile alakalı kütüphane yazmıştır. Bunu yazan Arduino değildir, üçüncü şahıslardır.
bit(), bitset() gibi fonksiyonlar programlama ile alakalı olduğundan görmezden geliyorum. Böyle fonksiyonları çok basit makrolar ile siz de yapabilirsiniz. C dilinde bitwise operatörler ile çok kolay yapıldığından bunun fonksiyonunu yazmaya da kullanmaya da gerek görmüyorum.
En son olarak Arduino fonksiyonları arasında kesmelere geldik. Kesmeler Arduino’da sadece iki harici ayaktan alınan sinyale göre işlemekte ve bu ayakların haritalandırılması yapılamamaktadır. Yani belirli ayaklardan kesme özelliğini kullanmanıza izin vardır. Oysa ki AVR’de dış kesmeler için bu ayak seçeneğiniz fazlalaştığı gibi kullanabileceğiniz onlarca iç kesme fonksiyonu da bulunmaktadır. Arduino ise yine her yönde olduğu gibi kırpılmış ve oldukça kısıtlı bir halde bu özelliği bize vermektedir. Kesmeler hakkında daha ayrıntılı bilgi isteyen C ile AVR Programlama kitabıma veya sitemize bakabilir.
Görüldüğü gibi Arduino’nun bir geliştirici için kırpılmış ve kısıtlı donanımsal fonksiyonları içeren bir kütüphaneden ibaret olduğunu görüyoruz. Örneğin analog karşılaştırıcı birimi olsa da bunu kullanmamız için Arduino’da herhangi bir fonksiyon veya kütüphane yoktur. Elimizdeki mikrodenetleyicinin özelliklerini kullanamadığımız halde onun üzerinde nasıl geliştirme yapabiliriz diye bir düşünelim. Sadece bu özellik kısıtlılığı değil aynı zamanda gereksiz yere RAM kullanımı, program boyutu gibi konularda kapasiteyi zorlamakta ve yavaşlığı ile mikrodenetleyiciden almamız gereken performansı bize vermemektedir. En kötü noktası ise bana göre hazır kütüphane kullanmaya ve tembelliğe alıştırmasıdır. Bu alışkanlığı üzerinizden atmanız diğer hepsinden daha zordur.
Arduino’nun yeterli olduğunu savunanlar bu görüşlerinde oldukça haksızdır ve bir dayanakları yoktur. Bizim hitap ettiğimiz kitle belli olduğundan hobicilerin üzerine alınıp hobi için yeterli olduğunu söylemesi meselenin dışındadır. Biz geliştiricilere ve geliştirici olmak isteyenlere hitap ettiğimizden bu yazıyı da bu kitleye yönelik yazdık.
Maşallah. Daha önce buna benzer yazıların oldu ama hiçbirisi beni bu kadar tatmin etmemişti. Arduino hiç kullanmadığım için böyle içi dolu kıyaslamalar yapamıyordum. Bu yazı için, bundan önce yazdıkların için ve bundan sonra yazacakların için eline emeğine sağlık. Tecrübelerini paylaştığın için tekrar teşekkürler.
Next story Gömülü Sistem Rehberi – Gökhan DÖKMETAŞ (E-Kitap)