Her şey “hep Arduino kullanmasak daha basit projeler için Arduino’yu heba etmesek!” ile başladı. Malum Arduino fiyatları çok yükseldi. Onun için diğer mikrodenetleyiciler deneyimlemeye çalıştım. PIC serisi bunların başında geliyor. Ama onların da fiyatı çok ucuz değil. Ayrıca açık kod olmadığından kod bulmak oldukça zor. Kodu da anlamak zor. Kodu çipe yüklemek de başka bir sorun. Bulabildiğim hex dosyalarını yükleyerek yapmaya çalıştığım projeleri hatırladım. Onun için Arduino’daki ATmega328 çipini de üreten ATmel firmasının daha basit modelleri ATtiny13 ve ATtiny85 çiplerine baktım. ATtiny85 ‘tiny’ olmasına rağmen hiç de ucuz değil ve fiyatı neredeyse ATmega328’in fiyatına yakın. Ben de ucuz olan ATtiny13’e yoğunlaştım. Bu çipie Arduino Uno ile program yüklemeyi (Blink) de başardım. Ama daha gelişmiş projeler için belleği yetersiz olduğundan bazı komut satırlarının bizim kullanığımız şekillerden farklı kullanıldığını gördüm. Onun için de bir çalışma yapıp işlemcinin ‘register’ ayarlamalarını, daha az hafıza kullanmak kodda nasıl değişiklik yapabileceğimizi de çalışacağım. Ama öncesinde Arduino kullanırken değişkenlerin üzerinden geçmek, tiplerini, sınırlarını görmek, Arduino’ya bunları tanıtmak nasıl oluyor bunu incelemek istedim. Tek kaynağım da arduino.cc resmi sitesi. Tüm bilgiler oradan alındı.
Öncelikle değişken nedir? Program içerisinde verileri isimlendirmek ve saklamak için kullanılan büyüklüklerdir. Bunlar bir matematiksel işlemin ara basamakları olabilir. Mesela tarlanın etrafını tel örgü ile kapatmak istediğimizde ihtiyacımız olan değişkenleri düşünelim. Tarlanın eni, boyu, çevresi, tel örgünün birim fiyatı, montaj fiyatı, gibi. Bunların hepsi birer değişken. Bu işlemi Arduino’nun hesaplamasını istiyorsak on da bunları tanıtmalıyız (deklare etmek). Ya da projelerimizde bir sürü sensör kullanıyoruz. Bunlardan okunan, işlenen değerler Arduino’ya bir şekilde deklare edilmeli.
Peki bu deklarasyon nerede yapılmalı? En başta yapılan tanımlanan değişkenlere ‘global’ değişkenler deniliyor. Genel değişkenler de diyebileceğimiz bu değişkenleri programın her yerinde kullanabiliyoruz. Değişkeni setup içerisinde tanımlarsak sadece burada kullanabiliyoruz. Bir değişkeni burada tanımlayıp yazdırabiliriz mesela. Ama loop içerisinde bu değişkeni kullanmak istediğimizde Arduino hata veriyor. Loop içerisinde tanımlanan değişkenler de sadece loop içerisinde çalışıyor (E başka bölüm mü var!.. Evet arkadaşlar basit programlarda (varsayılan olarak da) sadece setup ve loop var. Ama loop aslında bir fonksiyon ve istediğimiz kadar fonksiyon yazabiliriz. Daha önce rotary encoder projesinde yaptık). Burada daha çok örneğin (sadece) for döngüsü içinde kullanacağımız bir sayaç değişkeni atayabiliriz ( for (int i=0; i<10; i++){ } gibi ). Kısaca bu tanımlamaları setup’dan önce yapmak hayırlıdır.
Peki bu değişkenleri nasıl tanımlıyoruz. Öncelikle değişkene isim vermek gerekiyor. Türkçe karakter, +,- gibi matematik operatörleri, programda kullanılan komut isimleri verilemiyor. İsimler büyük/küçük harf duyarlı. Yani ‘isim’ bir değişken ise ‘iSim’ başka bir değişken! Sadece alt+tire (_) kullanılabiliyor. Sayı olabiliyor ama ismin başında değil! İsim verirken anlamlı isimler kullanılmalı, daha sonra programa baktığınızda anlamanız kolay olsun diye (butonPin, okunanDeger, ledPin1, … gibi isimler) Şimdi bu ismin başına değişken tipi yazılmalı ve isteniyorsa ilk değer ataması yapılmalı. Aşağıdaki örnekler geçerli tanımlamalar:
int ledPin = 13;
float deger;
boolean mant_1 = 1;
Peki öndeki değişkenler neler? bu çalışmanın konusu da bu. İnceleyelim:
char : char harfim = ‘k’;
Tek tırnak arasına yazılan tek bir karakter. Hafızada 1 byte (8 bit) yer kaplıyor. Her bir bit o noktada gerilim var (1), ya da yok (0) mantığına göre çalışıyor. Bunlar yan yana geldiğinde 8 basamaklı iki tabanına göre (Binary) bir sayı oluşturuyor.En sağdaki basamak değeri en küçük olan (LSB: Least Significant Bit) birler basamağı. Sola doğru gidildikçe; ikiler basamağı, dörtler basamağı, sekizler basamağı, .. şeklinde gidiyor. (Bu arada Arduino’da kullanılan ATmega328p işlemcisindeki sayılar: 32 (kByte cinsinden) kod yazılabilecek hafıza büyüklüğü, 8 ise işlemcinin kaç bitlik işlemci olduğunu gösteriyor. Yani aslında Arduino 8 bit ile çalışıyor. Daha büyük değerler 8 bite dönüştürülüyor. Bu da programda fazladan yer işgaline, yavaşlamaya neden oluyor)
byte: byte sayi = 140;
Adından da anlaşılacağı üzere hafızada 1 byte yer kaplıyor. Ama bir bayte dediğimiz şeyin ikili sayı sisteminde sekiz basamaklı bir sayı olduğunu söylemiştik. Bu basamakların en büyük değer olan ‘1’ olduğunu düşünürsek; 11 111 111 sayısının ondalık karşılığı 255. Doğal olarak az yer kaplasa da byte değişkeni 0-255 arasındaki tamsayıları saklamak için kullanılabiliyor.
int: int mesafe = 13;
2 byte’lık hafızada tamsayıları (integer) değerleri için kullanılabiliyor. 16 bitin (2 byte=16 bit) bir biti (+/-) işaret için kullanıldığından, kalan 15 bitin en büyük değeri bu değişkenin sınırlarını belirliyor. Bu aralık da (-32 768) ile (32 767) arası.
unsigned int: unsigned int sayac;
2 byte’lık hafızada sadece pozitif tamsayılar için kullanılıyor (unsigned: işaretsiz). Dolayısıyla (+/-) işareti olmadığından 16 bitin tamamı bu pozitif tamsayı için kullanılabiliyor. 16 tane ‘1’in yanyana yazıldığı ikili sistem sayısının ondalık karşılığı 65 635. Bu da 0 ile 65 535 arasında bir aralık sağlıyor. (zaten int aralığındaki artı ve eksi sayıların mutlak değer toplamı 65 535 ediyor.)
long: long carpim;
Hafızada 4 byte (32 bit) yer kaplıyor. Pozitif ve negatif tam sayılar için kullanıldığından bir bit buna harcanıyor. 31 bit’lik büyüklük de long (uzun) değişkenine: (-2 147 483 648) ile (2 147 483 647) arası tamsayı atanabilmesine olanak sağlıyor.
unsigned long: unsigned long genelToplam;
Eğer negatif sayı kullanmayacağım diyorsanız, o işaret biti de sayıya dahil oluyor ve bu değişkene atabileceğiniz sayı aralığı (yukarıdaki pozitif ve negatif sayıların mutlak toplamına eşit, 2^32) oluyor :0 ile 4 294 967 295 arası tamsayılar.
float (=double): float alan = 3.50;
Başka programlama dillerinde farklı amaçlar için kullanılan float ve double değişkenleri Arduino’da aynı işi yapıyorlar; pozitif ve negatif ondalıklı sayılar. Hafızada 4 byte yer kaplayan bu değişkenin alabileceği değerler : (-3.4028235*10^38) ile (3.4028235 *10^38) arasındaki ondalıklı sayılar. Burada dikkat edilmesi gereken nokta program içinde ondalıklı sayı bir şekilde tamsayıya dönüştürülürse sadece tam kısmı alınıyor, yuvarlama yapılmıyor. Buyurun size örnek:
float x = 2.9;
int y = x; // y’nin değeri = 2 olur.
Sayı 2.9 olmasına rağmen 2 değeri alındı. Yuvarlatılması gerektiğinde ’round’ kullanılmalı. Bu ondalıklı sayının yakın tamsayı değerine yuvarlatılmasını sağlıyor.
float x = 2.9;
int y = round(x); // y’nin değeri = 3 olur.
String:
Şimdi string değişken türü text türü diziler için, yani kelimeler, cümleler gibi karakteri saklamak için kullanılıyor. Ama arduino.cc diyorki “siz bu işlemi char ile yapsanız daha iyi olur! Tamam String’in değişik özellikleri var ama bu size daha fazla hafızaya patlar. Aşağıdaki şekilde kullanın char tipi değişkeni başınız ağrımaz!” Biz de hemen ne diyor bakalım, sonra String’i de inceleyelim. Yapmamız gereken char tipinde isim verdiğimiz değişkene isimden sonra köşeli parantez eklemek. Bu parantezin içine kaç karakterlik bir dizi olduğunu yazmak. Bu da önemli değil değişkende sakladığınız veri sayısından büyük yazabilirsiniz. Küçük yazarsanız sadece yazdığınız sayıdaki değişken dikkate alınıyor. Ama en güzel boş bırakabiliyoruz bu köşeli parantezin içini. Kaç eleman varsa kendisi ayarlıyor. Hemen çalışan örnekleri inceleyelim.
char Str1[15]; // ilk değer atanmamış string
char Str2[8] = {‘a’, ‘r’, ‘d’, ‘u’, ‘i’, ‘n’, ‘o’}; //yazdırınca: arduino
char Str3[8] = {‘a’, ‘r’, ‘d’, ‘u’, ‘i’, ‘n’, ‘o’, ‘\0’}; //yazdırınca: arduino
char Str4[] = “arduino”; //yazdırınca: arduino
char Str5[8] = “arduino”; //yazdırınca: arduino
char Str6[1] = “arduino”; //yazdırınca: arduino
Örnekler baktığımızda eğer bir text dizisi saklayacaksak, köşeli parantezin içini boş bırakıp, çift tırnak arasına karakter dizisini yazmak yeterli görünüyor. Sitede ayrıca char* kullanımına da örnek verilmiş. Bu sayede string içinde string işlemeye olanak verilmiş. Bu örnekte string içindeki stringler her yarım saniyede tek tek yazdırılmış. Burada dikkat edilmesi gereken, her bir string’in çift tırnak ile yazılması gerektiği. Eğer tek bir karakter dahi yazdırmak isteseniz tek tırnak yerine çift tırnak kullanmak zorunluluğu. Aşağıda örnek kod ve seri iletişim ekranındaki çıktısı görünmekte (while(1)döngünün sadece bir kez çalışıp durması için eklendi:
char *Stringlerim[] = {“String 1”, “String 2”, “String 3”,
“String 4”, “String 5”, “String 6”};
void setup () {
Serial.begin(9600);
}
void loop () {
for (int i = 0; i < 6; i++) {
Serial.println (Stringlerim[i]);
delay(500); }
while (1);
}
Program çıktısı seri ekranda 0,5 saniye aralıklarla alt alta yazılıp aşağıdaki gibidir:
String 1
String 2
String 3
String 4
String 5
String 6
Şimdi sayfanın bile çok yer kapladığı asıl String() komutuna. Genel yazılımı:
String (değer)
String (değer, taban)
String (değer, ondalıkNokta)
değer diye bahsedilen şey string olarak formatlanacak olan; string, char,byte, int, long, unsigned int, unsigned long, float, double burada kullanılabiliyor. Taban, isteğe bağlı olarak int (tamsayı) değişkeni ile birlikte kullanılabiliyor. OndalıkNokta dediği de float ya da double (ondalıklı sayı) ile kullanılabilen ve virgülden sonra kaç basamak olacağını gösteren değer. Dolayısıyla çok geniş bir kapsama alanı var. Doğal olarak da çok yer kaplıyor. Olabilecek seçenekleri gösteren sitedeki örnek kodlar aşağıda verilmiştir.
// sabit String kullanımı
String dize_1 = “Egitim Sart”;
// sabit char(karakter), Stringe dönüştürülmüş
String dize_2 = String(‘a’);
// sabit String, string nesnesine dönüştürülmüş
String dize_3 = String(“Bu bir stringtir”);
// iki string birleştirilmiş
String dize_4 = String(dize_2 + ” ve dahası”);
// sabit tamsayı kullanımı
String dize_5 = String(13);
// tamsayı ve taban kullanımı
String dize_6 = String(analogRead(0), DEC);
// tamsayı ve taban kullanımı (headecimal)
String dize_7 = String(45, HEX);
// long (uzun tamsayı) ve taban kullanımı
String dize_8 = String(millis(), DEC);
// ondalık sayı ve virgülden sonraki basamak sayısı(3)
String dize_9 = String(5.698, 3);
Ek Bilgiler:
Değişkenlerle ilgili birkaç noktayı daha site üzerindeki bilgilerden anlatmaya çalışayım. İlk nokta ilk başta özellikle Arduino’nun bacak bağlantılarını deklare ederken #define komutu kullanılması. Siteye göre hafızada yer kaplamıyor. Eşittir ve noktalı virgül kullanılmadığına dikkat!
#define ledPin 13
#define butonPin 0
İkinci nokta; değişken değerinin programın bir yerlerinde değişmesini istemiyorsak bunu const (constant:sabit) komutu ile sabitliyebiliyoruz. Program içinde bu şekilde tanımlanmış değişkene yanlışlıkla bir değer atamaya çalıştığınızda hata veriyor. Güzel bir şey!
const int carpan = 2;
const float pi = 3.14;
Üçüncü nokta; tamsayı değişkenleri diğer sayı tabanlarında da atayabiliyoruz:
// B ile başlayan sayı ikili sistemde (Binary) atanıyor (0-255 arası)
int binSayi = B1011;
// sayının başında 0 olursa Arduino bunu octal (8 tanbanında) algılıyor
int octalSayi = 0723;
// sayının başında 0x olursa bu hexadecimal (16 tanbanında) oluyor
int hexSayi = 0x12A;
int ile tanımlanmış sayı kendi sınırlarında değer alırken;
- Sayının sonuna eklenen ‘u’ ya da ‘U’ harfleriyle bu sayı unsigned (sadece pozitif) olabiliyor ve onun sınırlarında değer taşıyabiliyor.
int zaman = 60u ;
- Sayının sonuna eklenen ‘l’ ya da ‘L’ harfleriyle bu sayı long (uzun pozitif) olabiliyor ve onun sınırlarında değer taşıyabiliyor.
int saniye = 60L ;
- Her iki değişkliği aynı anda yapmak istersek:
int salise= 60UL ;
Evet dostlar. Dilim döndüğünce açıklamaya çalıştım. Çok ağır konulara girmek istemiyorum ama asıl amacım, hafızadan yer kazanmak için bu mikrodenetleyicilerin register’larına müdahale etmek.
Hoşça kalın, sağlıkla kalın…
Kaynak: https://www.arduino.cc/en/Reference/VariableDeclaration
Merhaba hocam,
Sitenizin ne olduğunu incelemedim ama; çok güzel tek tek anlatmışsınız elinize ağzınıza sağlık..
İstifade etmeyi …ve edeceğimi belirtmek isterim.
Bir sorum olacak?
nodemcu ile keypad kullanıyorum ama arduinodaki gibi kullnımını yapıyor normal. Ancak; iki ayrı değişkenime gsm modülü kullanmam için ayrı bir gsm değişkeni ve şifre doğrulamasını aynı döngü içinde ayrı ayrı birbirinden bağımsız olarak yapmam mümkün mü? nasıl yapacağım.
BeğenLiked by 1 kişi
Öncelikle teşekkür ederim. Ama daha önce nodeMcu ile çalışmadım. Üzgünüm, yanlış bilgi vermek istemem…
BeğenBeğen