İleri seviye arduino eğitimi kategorisindeki ilk dersimizde Seri Port nesnesini detaylı olarak ele alacağız.
Daha önceki Seri Port Ekranı Kullanımı dersimizde seri port nesnemizin bazı fonksiyonlarını ele almıştık. Bu dersimizde ise Seri Port nesnemizin tüm fonksiyonlarını detaylı olarak anlatmaya çalışacağız.
Öncelikle bu fonksiyonların bir listesine bakalım;
Şimdi bu fonksiyonları bir bir ele alalım.
Bu fonksiyonumuz yeni bir seri haberleşme tanımlamak için kullanılır. Daha önce bu fonksiyonumuzun setup() yapısında birçok kez kullanıldığına şahit olmuştuk. Serial.begin() fonksiyonumuz Arduino UNO için 0 ve 1 numaralı pinlerinde bulunan fiziksel seri haberleşme özelliğini aktif eder. Bu fonksiyonumuz “seri haberleşme hızı, iletilecek bilginin bit sayısı, parity (eşlik) biti’nin kaç bitten oluşacağı ve stop bitinin kaç bitten oluşacağı” olmak üzere 4 adet parametre alır. Yalnızca seri haberleşme hızını girerek de kullanılabilir.
Şimdi Serial.begin() fonksiyonun alabileceği parametrelere bakalım;
Sözdizimi: Serial.begin(baudRate, yapılandırma);
baudRate : Bu özellik olmazsa olmaz olan seri portun saniyede göndereceği ve alacağı bit sayısını belirler. Seri portun haberleşeceği cihaz ile aynı olmak zorundadır. Eğer aynı olmaz ise göndereceğiniz ya da alacağınız verilerin haberleşme yaptığınız cihaz ile çok farklı olduğunu görürsünüz. Çoğu cihazın seri haberleşme hızı 9600 Baud Rate’dir. Bu değer cihaz saniyede 9600 bit gönderip alabilir demektir. 300, 600, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200 değerleri alabilir.
yapılandırma: SERIAL_XYZ şeklinde yapılandırma yapılabilir. XYZ değerlerinin açıklamaları aşağıda belirtilmiştir;
X = Data Bit değeridir. Bu özellik ise seri porttan gönderilecek her bir verinin kaç bitten oluşacağını belirler. 5 ile 8 bit arasında bir değer alabilir.
Alabileceği değerler ise; 5, 6, 7 ve 8’dir. Varsayılan değeri “8”dir.
Y = Parity yani eşlik biti değeridir. Bu özellik seri port ile gönderilecek her bir verinin ardından gönderilecek eşlik bitini belirtmek için kullanılır. Eşlik biti gönderilen verinin karşı tarafa hatalı gidip gitmediğini kontrol etmek içindir.
Alabileceği değerler; N,O ve E değerleridir. Varsayılan değeri “N”dir.
“N” değeri “None” yani Parity biti gönderilmeyecek demektir. “O” değeri “One” yani “1” bitlik parity biti gönderileceğini, E değeri ise “Even” yani “2” bit parity biti gönderileceğini belitmek için kullanılır.
Z = Gönderilecek verinin sonuna eklenecek olan Stop Biti sayısını temsil eder. 1 ve 2 değerini alabilir. Aldığı değer kadar gönderilen verinin sonuna stop biti ekler. Varsayılan değeri “1”dir.
Yani biz Serial.begin(9600); yazdığımızda yapılandırma otomatik olarak SERIAL_8N1 değerini kullanır.
Eğer biz 9600 baud rate hızında, 8 bitlik data biti, 2 bitlik parity (eşlik) biti ve 1 bitlik stop biti gönderilecek şekilde seri portu yapılandırmamız gerekirse begin() fonksiyonumuz şu şekilde olmalıdır;
Serial.begin(9600, SERIAL_8E1);
Şimdi ikinci fonksiyonumuz olan print fonksiyonuna geçelim.
Bu fonksiyon gönderilecek olan verinin ASCII standartlarında gönderilmesini sağlar. Yani veriyi karşıya direkt karakter olarak gönderir. Bu fonksiyon ile gönderilen veriler makina tarafından ekrana basılabilir ve insan tarafından okunabilir.
Sözdizimi; Serial.print(gonderilecekVeri);
1 2 3 4 |
Serial.print(78); // "78" gönderir Serial.print(1.23456); // "1.23" gönderir Serial.print('N'); // "N" gönderir Serial.print("Hello world."); // "Hello world." gönderir |
Direkt olarak girilen karakterleri seri porta gönderse de ikinci bir parametre olarak gönderilecek verinin formatı belirlenebilir;
Serial.print(veri,format);
İzin verilen format değerleri; BIN (Binary yani 2 tabanlı veri), OCT (Octal yani 8 tabanlı veri), DEC (Decimal yani 10 tabanlı veri) veya HEX (Hexadecimal yani 16 tabanlı veri) olarak gönderilebilir.
1 2 3 4 |
Serial.print(78, BIN); // "1001110" gönderir Serial.print(78, OCT); // "116" gönderir Serial.print(78, DEC); // "78" gönderir Serial.print(78, HEX); // "4E" gönderir |
Ondalıklı sayılar için ise ikinci parametre noktadan sonra gösterilecek basamak sayısını belirleyebilir;
1 2 3 |
Serial.print(1.23456, 0); // "1" gönderir Serial.print(1.23456, 2); // "1.23" gönderir Serial.print(1.23456, 4); // "1.2346" gönderir |
Serial.println() fonksiyonu Serial.print() fonksiyonu ile tamamen aynı işlemi yapar, Ancak bu fonksiyon gönderdiği her verinin sonuna Satır Başı (ASCII 13 veya ‘\r’) karakteri ve ardından Yeni Satır(ASCII 10 veya “\n”) karakterini ekler. Böylelikle gönderilen her veride alıcı cihaz alt satırdan devam eder.
Sözdizimi; Serial.println(gonderilecekVeri);
1 |
Serial.println("Merhaba"); // "Merhaba" yaz ve alt satıra geç |
Serial.available() fonksiyonu seri port arabelleğindeki (buffer) alınana byte sayısını verir. Biz seri porta gelen veriyi almadan önce bu veriler seri port arabelleğine kayıt edilir. Seri port arabelleği 64 byte değerindeki veriyi saklayabilecek kapasitededir. Biz Serial.available() fonksiyonu ile gelen verinin kaç byte’dan oluştuğunu öğrenebiliriz. Fonksiyon, herhangi bir parametre almaz ve gelen verinin byte sayısını integer cinsinden değer olarak bize verir.
Sözdizimi: Serial.available();
Bu fonksiyonu seri porta veri gelip gelmediğini anlamak için de kullanabiliriz.
Örneğin seri porta veri geldiğinde, gelen verileri alan program yazalım;
1 2 3 4 5 |
void loop() { if(Serial.available()>0){ // Eğer seri porta veri gelmişse int gelen = Serial.read(); // gelen veriyi "gelen" değişkenine kaydet } } |
Serial.read() fonksiyonu, seri porta gelen verileri okumak için kullanılır. Okunan bu verileri bir değişkene atayarak kullanabilirsiniz.
Sözdizimi: Serial.read();
Örnek olarak seri porta gelen bir sayıyı alalım ve değişkene atayalım;
1 2 3 4 |
void loop() { Srting gelenVeri; gelenVeri = Serial.read(); // gelen veriyi "gelenVeri" değişkenine kaydet } |
Serial.readBytes() fonksiyonumuz seri porttan gelen verileri char ya da byte dizisi olarak okumak için kullanılır. Gelen veriler byte ya da char dizisine aktarılabilir. Gelen verilerin belli bir bölümünü okumak için de kullanılabilir. İki adet parametre alır. Birinci parametre verilerin aktarılacağı dizi, ikinci parametre ise seri porttan kaç byte veri okunacağını bildirir.
Sözdizimi: Serial.readBytes(verilerinAktarılacağıDizi, okunacakByteSayısı);
Örnek olarak seri porta gelen verilerin tamamını okuyup bir byte dizisine kaydedelim;
1 2 3 4 5 6 7 |
void loop() { if(Serial.available()>0){ // Eğer buffer'da veri varsa int uzunluk = Serial.available(); // gelen byte sayısını uzunluk değişkenine ata byte gelenVeri[uzunluk]; // gelen veri uzunluğunda "gelenVeri" adında byte dizisi oluştur Serial.readBytes(gelenVeri,uzunluk); // gelen byte'ların tamamını, "gelenVeri" dizisine aktar } } |
Bir başka örnekle gelen verinin ilk 5 byte’ını okuyalım;
1 2 3 4 5 6 |
void loop() { if(Serial.available()>0){ // Eğer seri porta veri geldiyse byte gelen[5]; // gelen adında 5 indisli dizi oluştur Serial.readBytes(gelen,5); // gelen veriden 5 byte oku ve gelen dizisine aktar } } |
Seri porttan gelen verileri belli bir karaktere kadar okumaya yarar. Belirlenen karaktere ulaşıldığında okuma işlemi sona erer ve belirtilen karakter arabellekten temizlenir.
Sözdizimi: Serial.readBytesUntil(karakter, buffer, lenght);
karakter: hangi karakter gelince okuma sona ersin (char)
buffer: okunan verinin aktarılacağı dizi (byte[] ya da char[])
lenght: okunacak byte sayısı (int)
Örnek olarak seri pottan 15 byte veri okuyalım ancak okunan verinin içerisinde ASCII 0x3 nolu End Of Text karakteri geldiğinde okumayı sonlandıralım. Kodlarımız şu şekilde olacak;
1 2 3 4 5 6 |
void loop() { if(Serial.available()>0){ // Eğer seri porta veri geldiyse byte gelen[15]; // gelen adında 15 indisli dizi oluştur Serial.readBytesUntil(0x3,gelen,15); // gelen veriden 15 byte oku ve gelen dizisine aktar } } |
Yukarıdaki kodda, Serial.readBytesUntil(0x3,gelen,15); komutu ile seri porta gelen verinin 15 byte’ını okuyacağımızı söyledik, ancak bu okunan byte dizisi içerisinde ASCII 3 numaralı End Of Text verisi gelirse okumayı sonlandırması gerektiğini belirttik. Eğer bu 15 byte okunurken onuncu byte’da 0x3 verisi gelirse, okuma sona erecek ve buffer’dan okunan veriler ile birlikte 0x3 verisi silinecektir.
Bu fonksiyonumuz seri porttan gelen verileri string (metin) olarak okur.
Sözdizimi: Serial.readString();
Örnek olarak gelen bir veriyi string olarak okuyalım;
1 2 3 4 5 6 |
void loop() { String gelen; if (Serial.available() > 0) { // Eğer seri porta veri geldiyse gelen = Serial.readString(); // gelen veriyi oku ve gelen değişkenine aktar } } |
Serial.readStringUntil() Fonksiyonumuz seri porttan gelen verileri belirlenen karaktere kadar okur.
Sözdizimi: Serial.readStringUntil(karakter)
karakter: char türü herhangi bir ASCII karakter
Örneğin seri porttan gelen verileri “a” karakterine rastlayıncaya dek okuyalım;
1 2 3 4 5 6 |
void loop() { String gelen; if (Serial.available() > 0) { // Eğer seri porta veri geldiyse gelen = Serial.readStringUntil('a'); // gelen veriyi "a" karakterine kadar oku ve gelen değişkenine aktar } } |
Seri porta byte türünde veri göndermek için kullanılır. Eğer metin ve sayı türü veri gönderecekseniz print() fonksiyonunu kullanınız.
Söz dizimi:
Serial.write(byteDeğer);
byteDeğer: gönderilecek 1 byte değerindeki veri.
Serial.write(byteDizi);
byteDizi: byte dizisi elemanı
Serial.write(byteDizi, uzunluk);
byteDizi: byte dizisi
uzunluk: dizinin kaç byte’ı gönderileceği
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
void loop() { byte deger = 0xFA; // bir byte değerindeki veri Serial.write(deger); // deger değişkenini seri pota yaz byte veri[] = {0x15, 0x45, 0xF4, 0xFF, 0xDA, 0x2A}; // veri adında dizi oluşturup değer atadık Serial.write(veri[2]); // veri dizisinin 2. elemanı olan 0xF4 değerini seri porta yazdık Serial.write(veri, 3); // veri dizisinin ilk 3 elemanını seri pota yazdık Serial.write(veri, sizeof(veri)); // veri dizisinin tüm elemanlarını seri porta yazdık delay(1000); } |
Seri port ile veri gönderme işlemini engellemeden seri port arabelleğinden yazılabilir byte sayısını alır. Geriye integer türü değer döndürür.
Sözdizimi: Serial.availableForWrite();
1 2 3 4 5 6 7 8 9 10 11 12 |
void loop() { byte veri[] = {0x15, 0x45, 0xF4, 0xFF, 0xDA, 0x2A}; // veri adında dizi oluşturup değer atadık Serial.write(veri, sizeof(veri)); // veri dizisinin tüm elemanlarını seri porta yazdık int gonderilenByteSayisi = Serial.availableForWrite(); // seri port arabelleğinde kaç byte yazılacak veri olduğunu aldık delay(1000); } |
Bu fonksiyon seri porta veri okuma/yazma yapmak için beklenecek maksimum zamanı milisaniye cinsinden belirtir. Yani seri port zaman aşımıdır. Varsayılan değeri 1000 milisaniye yani 1 saniyedir. Bu fonksiyon ile belirtilen zaman değeri aşılırsa, seri port okuma/yazma işlemini durdurur.
Sözdizimi: Seril.setTimeout(zamanAşımıDeğeri);
Kullanım Şekli:
1 2 |
Serial.setTimeout(1500); // Seri port zaman aşımı değerini 1500 milisaniye olarak belirledik |
Seri port zaman aşımı değerini kullanan seri port işlevleri aşağıdakilerdir;
Seri portu devredışı bırakarak RX ve TX pinlerini dijital giriş/çıkış olarak kullanılmasına izin verir. Bu fonksiyondan sonra tekrar seri portu etkinleştirmek için Serial.begin() fonksiyonu kullanılır. Serial.end() fonksiyonu herhangi bir parametre almaz ve geriye değer döndürmez.
Sözdizimi: Serial.end();
Seri porta gelen veride belirlenen karakteri arar. Char türü parametre alır. Eğer karkteri bulursa TRUE, bulamazsa FALSE sonucu döndürür.
Sözdizimi:
Serial.find(arananKarakter);
arananKarakter türü char olmalı.
Serial.find(arananKarakter, uzunluk);
gelen verinin belirtilen uzunluktaki miktarında belirtilen karakteri arar.
Örneğin gelen veri içerisinde “a” karakterini arayalım;
1 2 3 4 5 6 7 8 9 10 11 |
void loop() { bool karakterVarmı; // karakterVarmi adında bool türü değişken oluşturduk if(Serial.available()>0){ // eğer seri porta veri gelmişse karakterVarmı = Serial.find('a'); // gelen veride 'a' karakterini ara /* * Eğer 'a' karakteri mevcutsa karakterVarmi değişkeni değeri TRUE * eğer 'a' karakteri yoksa karakterVarmi değişkeni değeri FALSE olur */ } } |
Belirtilen karaktere kadar belirtilen karakteri aramak için kullanılan seri port nesnedi fonksiyonudur. İki adet parametre alır. Birinci parametre aranacak karakter, ikinci paramere ise hangi karaktere kadar aranacağıdır. Geriye dönüş değeri bool türündendir.
Sözdizimi: Serial.findUntil(aranacakKarakter, hangiKaraktereKadarAranacağı);
Örneğin seri porta gelen veri içerisinde ‘x’ karakteri ile karşılaşıncaya kadar ‘y’ karakterini arayalım;
1 2 3 4 5 6 7 8 9 10 |
void loop() { bool varmi; if (Serial.available() > 0) { // Eğer seri porta veri geldiyse varmi = Serial.findUntil("y","x"); /* * eğer "x" karakteri ile karşılaşıncaya kadar "y" karakteri bulunursa * sonuç değeri TRUE döner. Aksi halde FALSE değer döndürür */ } } |
Bu fonksiyon gönderilen seri veri iletiminin tamamlanmasını beklemek için kullanılır. Herhangi bir parametre almaz ve geriye değer döndürmez. Arduino 1.0’dan önce, bunun yerine arabellekte gelen tüm seri verileri silinir.
Sözdizimi: Serial.flush();
Örnek;
1 2 3 4 5 6 7 8 9 |
void loop() { byte veri[] = {0x15, 0x45, 0xF4, 0xFF, 0xDA, 0x2A}; // veri adında dizi oluşturup değer atadık Serial.write(veri, sizeof(veri)); // veri dizisinin tüm elemanlarını seri porta yazdık Serial.flush(); // Verinin tamamı gönderilene kadar bekle } |
Bu fonksiyon seri arabellekten rastladığı ilk ondalıklı sayıyı ve okumaya devam edilirse rastladığı tüm ondalıklı sayıları döndürür. Rakam olmayan karakterler atlanır. Eksi işareti dahil edilir.
1 2 3 4 5 |
void loop() { if(Serial.available()>0){ float deger = Serial.parseFloat(); } } |
Bu fonksiyon seri port arabelleğinden geçerli ilk tamsayıyı alır. Rakam olmayan değerler atlanır. Zaman aşımı değeri aşıldığında ya da herhangi bir tamsayı bulunmadığında işlem sonlanır ve sıfır değeri döndürülür. Ayrıştırma karakteri belirlemek için char türünden parametre alabilir.
Sözdizimi:
Serial.parseInt();
Serial.parseInt(ayrıştırmaKarakteri);
ayrıştırma karakteri char türündendir. Gelen veride tire, virgül gibi belirli karakterleri atlamamızı sağlar.
Örneğin seri porttan gelen verilerden tamsayı olan veriyi alalım;
1 2 3 4 5 |
void loop() { if(Serial.available()>0){ int deger = Serial.parseInt(); } } |
Serial port nesnesinin bu fonksiyonu ise, seri porta gelen verinin bir sonraki byte değerini döndürür. Örneğin seri porttan okuma yaparken birinci byte değerini okuduğumuzu varsayalım, ikinci byte değerini okumadan önce gelen byte değerini kontrol edip, ardından veriyi almak istersek önce Seril.peek() fonksiyonuyla veriyi kontrol ederiz. Serial.peek() fonksiyonuyla okuduğumuz veri arabellekten silinmez. Bu fonksiyonumuz herhangi bir parametre almaz ve geriye dönüş değeri integer cinsindendir. Eğer veri mevcut değilse -1 sonucunu döndürür.
Örnek olarak gelen verinin ilk byte değeri 0x4A ise, bu veriyi okuyalım, eğer 0x4A değilse, okumayı iptal edelim;
1 2 3 4 5 6 7 8 9 |
void loop() { int gelen = 0; // gelen adında bir değişken oluşturduk if(Serial.available()>0){ // Seri portta veri var mı int kontrol = Serial.peek(); // gelen verinin ilk byte değerini al if(kontrol == 0x4A){ // ilk byte değeri 0x4A ise gelen = Serial.read(); // gelen veriyi gelen değişkenine ata } } } |
Bu fonksiyon birden seri portu dinler ve veri geldiğinde veriyi yakalamak için kullanılır. Binevi seri port kesmesi gibi davranır. Bu işlemi loop() döngüsünden bağımsız olarak yapar. Yani loop() döngüsünde kodlarımız çalışırken, seri porta bir veri geldiğinde, serialEven() fonksiyonumuz o veriyi alır ve tanımladığımız değişkende saklar. İstediğimiz zaman değişkende saklanan verileri kullanabiliriz.
Örnek olarak loop() döngüsünden bağımsız olarak gelen verileri alalım ve ardından loop() döngüsünde veriyi seri porta geri gönderelim.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
String gelenVeri; // gelen verileri atayacağımız değişken bool veriKontrol = false; // veri alma ve gönderme işleminde kullanacağız void setup() { Serial.begin(9600); // Seri port ayarı gelenVeri.reserve(200); // gelen veriler için hafızada 200 byte alan rezerve ediyoruz } void loop() { if (veriKontrol == true) { // eğer veri alınmışsa Serial.print(gelenVeri); // gelen veriyi geri gönder veriKontrol = false; // veriyi kullanma işlemi bitti gelenVeri = ""; // veriyi değişkenden sil } } void serialEvent() { // Seri port kesmemiz gelenVeri = (char)Serial.read(); // gelen veriyi char türünden oku veriKontrol = true; // okuma bitince değişken değerini true yap } |
Yerleşik USB bulunan kartlarda if(Serial) ya da if(SerilaUSB) komutu USB için seri bağlantının hazır olup olmadığını kontrol etmek için kullanılır. Eğer bağlantı hazır ise TRUE sonuç döndürecektir. USB olmayan diğer tüm CDC portları ve Uno, Nano, Mini, Mega, Uno WiFi Rev.2 kartları için bu komut her zaman TRUE sonuç döndürecektir.
Örnek olarak USB portu hazır olunca USB port hazır mesajı gönderen kodumuzu yazalım;
1 2 3 4 5 |
void loop() { if(SerialUSB){ Serial.print("USB port hazir"); } } |
Yukarıdaki kod Arduino Uno, Nano, Mini, Mega, Uno WiFi Rev.2 kartlarında çalışmaz!