Arduino ile Millis kullanımı ve Timer Uygulamaları
|Merhabalar…
Bu konuda türkçe kaynağı az bulunan Arduino’ da timer ve millis ile yapılmış bir kaç uygulamaya yer vereceğiz. Öncelikle Arduino’ da Timer kullanımı ile ilgili detaylı yazıya buradan ulaşabilirsiniz.
– > Timer diğer konuda bahsetmiştik. Peki ya millis nedir, ne iş yapar? Bu soruların cevabına gelelim.
Millis bir fonksiyondur. Kullandığınız zaman unsigned long veri tipinde bir sayı döndürür. Arduino’ nun enerjisi kesilmeden bu fonksiyonu art arda çağırdığnız zaman döndürdüğü değerin sürekli artttığını gözlemleyebilirsiniz. Bunun sebebi, bu fonksiyonun her bir milisaniyede artan bir sayaç olarak çalışıyor olmasıdır. Ancak arduino’ nun enerjisini kesildiğinde bu sayaç sıfırlanacak ve enerji aldığında tekrar sıfırdan başlayacaktır. Bunun dışında unsigned long int’ in max değeri olan 4294967295 değeri geçildiğinde de sayaç sıfırlancak ve sıfırdan yeniden saymaya başlyacaktır.
-> Peki ya nasıl kullanabiliriz? Bir kütüphane çağırmamız yada ayar yapmamız gerekir mi?
Hayır. Siz isteseniz de istemesinizde bu sayaç arduino’ ya enerji verildiği anda saymaya başlayacaktır. İhtiyacınız olan yerde “millis()” fonksiyonunu çağırmak yeterlidir. Size sayaç değerini döndürecektir.
-> Kullanırken nelere dikkat etmeliyiz?
Değişkenlere bu değeri atama yaparken değişken tipinin sorunların en aza indirilmesi için unsigned long int tipinde olmalıdır. Elbet bu ihtiyaca göre değiecektir. Örneğin siz saniye yada dakikaya ihtiyacınız varsa ve bölme işleminden sonra atama yapacaksınız char değişkenler bile kullanabilirsiniz. Ama normal kullanımlarda unsigned long int tipinde kullanırsanız arduino 1 aya kadar sorunsuzca sayacaktır. Ondan sonrası için kayıtlı değerlerinizi sıfırlamalısınız yada arduino’ yu self reset atacak şekilde ayarlamalısınız.
Şimdi gelelim uygulamalarımıza.
İlk uygulamamızda genelde en çok örnek bulunan “delay” kullanmadan bir kaç led belli süre aralıkları ile yakıp söndürmek. Tanımlamalarımızı yaparak başlayalım.
//pin tanımları int ledPin1 = 2, ledPin2 = 3, ledPin3 = 4; //son millis değerini tutacağımız değişken unsigned long lastTime1 = 0, lastTime2 = 0, lastTime3 = 0;
Bizim yapacağımız işi bir tane lastTime değişkeni ile de yapabiliriz. Ancak ilk örnek olduğu için ayrı ayrı göstermek istedim. Bu kısımda üstte de bahsettiğimiz gibi millis değerini tutacağımız değişkenleri “unsigned long” tipinde tanımladık.
//son millis değeri ile arada 1000 fark varsa if (millis() - lastTime1 > 1000) { digitalWrite(ledPin1, !digitalRead(ledPin1)); //led durumunu değiştir lastTime1 = millis(); //son değere o anki millis //değerini kaydet }
Bu kısımda da o anki millis değeri ile bizim son kaydettiğimiz millis değeri arasında 1000 ms geçmiş mi diye kontrol ettik. Eğer geçmişse if içerisindeki işlemleri gerçekleştirdik. Burada dikkat edilmesi gereken nokta işlemler bittiği zaman if içerisinden çıkarken millis in değerini tekrar kaydetmeyi unutmamak. Aksi taktirde bir sefer bekleme yapıp daha sonrasında bekleme meydana gelmeyecektir.
Peki bu bize ne kazandırdı. Herhangi bir bekleme işlemi olmadan yani ana döngüyü durdurmadan bir kaç işlemin belli sıklıklarla gerçeklemesini sağladık. Özellikle hız ölçümü gibi sayılan devrin hassas ve bekleme yapılmaması gereken durumlarda yada newPing gibi delay kullanımın da sorun çıkartan kütüphaneler ile çalışılması durumunda millis yapısı çok kullanışlıdır.
Bu çok basit bir örnek olduğu için diğer örneğe geçmek istiyorum. Üstteki anlatımda kullandığım yazılımın tamamına buradan ulaşabilirsiniz.
Sıradaki örnekde analog bir değeri 100 ms ile örnekleyip ortalamasını alalım ve bu ortalamasını aldığımız değeri seri port yardımı ile yine belli aralıkla gönderelim. Eğer ki ortalama belli bir sınırı geçmişsse de bir ledi bir saniye aralıklar ile yakıp söndürelim.
Öncelikle tanımlamarımızı yapalım..
//led tanımlamarı ve millis değerini tutacak değişken tanımları int ledPin = 13, potPin = A0; unsigned long lastTime = 0, lastTimeSeriPort = 0, ledLastTime = 0; int sayac = 0; //3 örneği sayacak sayaç double ortalama, deger = 0; //ortalama için değişkenler void setup() { // put your setup code here, to run once: //ledi çıkış potu giriş olarak atadık ve haberleşmeyi //başlattık pinMode(ledPin, OUTPUT); pinMode(potPin, INPUT); Serial.begin(9600); }
Şimdi sıra örneklerı alıp ortalamayı alalım.
//3 örneği 100 ms arlıklarla alalım if (millis() - lastTime > 100) { deger += analogRead(potPin); sayac++; if (sayac == 3) //sayaç değeri 3 olmuşsa ortalamayı al { ortalama = (double)deger / 3.0; sayac = 0; //değerleri sıfırla deger = 0; } lastTime = millis(); }
Gördüğünüz gibi herhangi bir geciktirme işlemi kullanmadık. Bu da bize veriyi gönderirken yada ledi yakıp söndürürken bize ekstra gecikmeye sebep olmamasını ve tüm işlemlerin bir nevi asenkronmuş gibi gerçeklenmesini sağladık. Son olarak da veriyi gönderip ledi yakıp söndürelim.
//500 ms de bir ortalama değerini gönder if (millis() - lastTimeSeriPort > 500) { Serial.println(ortalama); lastTimeSeriPort = millis(); } //eğer ortalama 512 den büyükse ledi yakıp söndür if (ortalama > 512) { if (millis() - ledLastTime > 1000) { digitalWrite(ledPin, !digitalRead(ledPin)); ledLastTime = millis(); } }
Bu örneğin tamamına buradan ulaşabilirsiniz.
Şimdi timer kullanarak karaşimşek devresini delay kullanmadan yapalım. Led ‘ler 100ms aralıkla değişecek şekilde ayar yapalım. Bekleme süresini değişmek için interrupt ların durdurulup OCRxA registerinde değerin o şekilde değiştirilmesi gerektiğini unutmayınız.
// timer 100 ms olacak şekilde ayarlanır cli(); TCCR1A = 0;// TCCR1A register 0'lanıyor TCCR1B = 0;// TCCR1B register 0'lanıyor TCNT1 = 0;//sayac değeri 0'la // OCRxA karşılaştırma registeri 1Hz değer için ayarlanıyor //16 MHz osilatör,10Hz timer1 ın çalışma frekansı,1024 prescalar OCR1A = 1562;// = (16*10^6) / (1*1024) - 1 (değer 65536 dan küçük) // CTC mod açılıyor. TCCR1B |= (1 << WGM12); // CS10 ve CS12 bitleri 1024 prescaler için ayarlanıyor TCCR1B |= (1 << CS12) | (1 << CS10); // timer karşılaştırma interruptı aktifleştiriliyor TIMSK1 |= (1 << OCIE1A); sei();
Timer ın ayarını yaptık. Şimdi sıra timer taşma interrupt ı geldiğinde yapılacakları ayarlayalım. Bu kısımda hem led lerin sağa hem de sola gidebilmesi için bool bir değişken ile sayacın arta ve azalmasını kontrol ettik.
ISR(TIMER1_COMPA_vect) { //timer1 interrupt ı 10Hz de tetikleniyor. if (arttir) { sayac++; } else { sayac--; } if (sayac == 9) arttir = false; if (sayac == 0) arttir = true; }
Ana döngümüzde de yanması gereken ledi yakıp diğerleri sönük bıraktık. Led lerde yanıp sönmeyi engellemek için son led değerinin değişimini kontrol ettik. Eğer değişmişse tüm led leri söndürüp diğer ledi o şekilde yaktık. Böylece led değişme işlemi tamamen 100 ms de bir gerçekleşecek şekilde yapmış olduk.
void loop() { // put your main code here, to run repeatedly: if (sayac != sonSayac) { //tüm ledleri söndür for (int i = 0; i < 9; i++) { digitalWrite(ledPin[i], LOW); } //sırası gelen ledi yak digitalWrite(ledPin[sayac], HIGH); //son sayac değerini bir sonraki değişime kadar hafızada tut sonSayac = sayac; } }
Yazılımın tamamına buradan ulaşabilirsiniz. Arduino gibi tek işlemcili donanımlarda asenkron yapılar son derece kullanışlıdır. Bu yüzden üzerinde durulmasında fayda olduğu düşüncesindeyim. Daha fazla örnek vermek isterdim aklıma şu anlık bunlar geldi ki bu tür sorular sorulmuştu genelde. Umarım biraz da olsun faydası dokunmuştur.
İyi çalışmalar..
Bir ledi bir butonla yakıp butona tekrar bastığım zaman sönmesini basmazsam atıyorum 5 dakika sonra otomatik olarak sönmesini istiyorum.Örnek kod verirmisin.
Merhaba, örnek olarak basit bir uygulama mail adresinize gönderdim. İyi çalışmalar dilerim…
Merhabalar. her bir saniye de 4 uzaklık sensörlerinden aldığım bilgiyi(10 cm den yakınsa 1 değilse 0) bir önceki veri ile karşılaştırıp değişiklik olduğu zaman yazdırmak yada göndermek istiyorum. Millis i kullanacaksam nasıl kullanabilirim?
Merhaba, bahsettiğiniz işlemi millis ile yapmak oldukça kolaydır. Sadece millis ile örnekte olduğu gibi belirli zaman aralıklarında çalışan bir if bloğu yazmalısınız. Bu blok içerisinde o anki değer ile önceki değeri karşılaştırabilirsiniz. İyi çalışmalar dilerim..
İyi günler ben bir zaman rolesi yapmak istiyorum arduino ile nasıl bir kod yazman lazım kısaca şöyle bahsedeyim.
Bir röleye 5 v sinyal göndermem lazım aç kapa yapacak ama bunun sn genligini potansiyometre ile ayarlamak istiyorum.şimdiden ilgilerini için teşekkür ederim
Merhaba, bahsettiğiniz işlemi Arduino ile yapmak oldukça kolaydır. Potansiyometreden okuduğunuz 10 bitlik analog değeri ayarlamak istediğiniz değer aralığına göre skala edip delay fonksiyonu kullanarak anahtarlama süresini ayarlayabilirsiniz. Ancak delay süresiniz uzunsa potansiyometrenin değer değişikliğini uzun delay süresinden sonra algılayacaktır. Bu sorunu yaşamak istemezseniz konuda anlatılan millis fonksiyonu ile asenkron gecikmeli bir yapı oluşturabilirsiniz. Diğer sorularınızı baser61061@gmail.com adresine gönderebilirsiniz. iyi çalışmalar dilerim…
Hocam merhaba, ben şöyle birşey tasarlamaya çalışıyorum, bir buton var butona eğer 3 sn den fazla basılırsa buzzer devreye girsin ve buton bırakılana kadar çalsın, eğer butona hiç basılmazsa ya fa 3 sn altında basılırsa buzzer çalmasın, yardımcı olursanız çok sevinirim. İyi çalışmalar.
Merhaba,
Bu işlemi millis fonskyonu kullanarak rahatlıkla yapabilirsiniz. Butona basılınca zaman değerini kaydeder butonu bırakınca aradaki süreyi hesaplayarak işlem yaptırabilirsiniz.
İyi çalışmalar dilerim…
hocam merhabalar ben 4 farklı röleyi bluetooth üzerinden tetiklemek istiyorum yapıyorumda ama bunları 10 saniye 1 dakika 1 saat 24 saat şeklinde tetiklemem için ne yapmam gerekir tşkler..:)
Merhaba, projenizde röleleri farklı zaman dilimlerinde tetiklemek için millis fonksiyonu ile geçen zaman kontrol edebilirsiniz. millis fonksiyonu 1 ay gibi bir süreye kadar sorunsuz saymakta. Daha sonra sıfırlanıp tekrar saymaya başlar. Ancak projenizin hangi kısmında Bluetooth kullanmanız gerektiğini anlamadım. baser61061@gmail.com adresine mail gönderirseniz yardımcı olmaya çalışırım. İyi çalışmalar dilerim…
iyi günler Oğuzhan bey, bir konuda yardımınıza danışabilir miyim. millis fonksiyonunun içine analaogRead(A0) kodu ile sensörden değer alabilir miyiz, ve bu değeri setup bölümüne return yapabilir miyiz.
Merhaba, sorununuzun ne olduğunu tam olarak anlamadım. baser61061@gmail.com adresine sorununuzu detaylıca yazabilirseniz sevinirim. İyi çalışmalar dilerim…
Kolay gelsin. global değişken yada local değişken ayırt etmeden bütün değişkenleri setup üstüne yani global yazsak bir skıntı olur mu.
Merhaba, mikrodenetleyicilerde global değişken hafızası ayrı olarak tutulmaktadır. Bu hafıza normal program hafızasına göre daha küçüktür ve büyük yazılımlarda her şeyi global tanımlamak bu hafızanın dolmasına sebep olabilir. Ancak küçük yazılımlarda bir fark oluşturmayacaktır. İyi çalışmalar dilerim…
merhabalar,benim sorum şu olucak.delay millisi durdurur mu?
Merhaba, program içerisinde kullanacağınız delay fonksiyonları millis yada micros fonksiyonlarının işlevini bozmayacaktır. Onlar timer interrupt’ ı ile artmaktadırlar. Ancak diğer interrupt fonksiyonları içerisinde kullanılan delay’ lar timer interrupt’ unu engelliyeceği için saymasını engelleyecektir. İyi çalışmalar dilerim…
Merhaba biz AC712 sensörü kullanarak akım ölçen bir cihaz yaptık, Arduino kullanıyoruz fiş priz deneyi için . Fakat fişin prize takılı olması gereken süre 1.5 sn .
Bu 1.5 sn yi aştığında alarm vermek istiyoruz. Millis fonksiyonunu nasıl kullanabiliriz?
Merhaba, bahsettiğiniz işlemi millis kullanarak rahatlıkla yapabilirsiniz. Konudaki örnek size yol gösterici olacaktır. Takıldığınız yerleri mail yardımı ile sorabilirsiniz. İyi çalışmalar dilerim…
Merhaba, Arduino’da bir çift fotodiyot kullanarak(alıcı ve verici olmak üzere karşılıklı iki foto diyot ve aralarında kısa bir mesafe mevcut), bu iki fotodiyot arasından geçme süreleri farklı cisimler geçirerek, devreyi kesme sürelerini ölçmek istiyorum.Buna göre de kategorize edeceğim.En azından bu fotodiyotların kesimde oldukları süreyi arduinoda nasıl ölçeceğime yardım yardım ederseniz sevinirim.Şimdiden teşekkürler
Merhaba, bahsettiğiniz işlem için gerekli adımları konu içerisinde bulabilirsiniz. Ek olarak bir interrupt yazılımı eklemeli kullandığınız mesafe algılayan sensörün üreteceği interrupt lar arasında ki süreyi ölçmelisiniz. Daha detaylı bilgi almak için baser61061@gmail.com adresine mail gönderebilirsiniz. İyi çalışmalar dilerim…
Selamlar
Katkılarınız için teşekkür ederim.
2 saatte bir işlem yapmak için 2 Saat = 7200000 Milisaniye
if (millis() – lastTime1 > 7200000 )
bu şekilde bir kullanım bir sakıncası olur mu ? Yada saat bazlı işlem yapacak bir fonksiyon mevcut mu ?
Teşekkürler
Merhaba, bu şekilde bir kullanım sorun olmaz. Anckak “lastTime1” isimli kullandığınız değişkenin tipinin unsigned long olmasına dikkat edin. İyi çalışmalar dilerim…
Enkoderin 2 pulse arasindaki sureyi millis komutu ile nasil bulabilirm
Merhaba, bahsettiğiniz işlemi rahatlıkla millis fonksiyonu kullanarak gerçekleştirebilirsiniz. Bunun için her enkoder pulse gelmesinde süreyi bir değişkene kaydederek sonraki pulse ile arasındaki süreyi hesaplıyabilirsiniz. Anlamadığınız yerler için baser61061@gmail.com adresine mail atabilirsiniz. İyi çalışmalar dilerim…
Hocam, elinize sağlık süper açıklama. Çok işime yaradı. Bir hallsens takometre yapmak için bilgi arıyordum ilaç gibi geldi
Teşekkürler, işinize yaradığına çok sevindim. İyi çalışmalar dilerim…
Merhaba, ben mz80 sensör kullanarak 5 saniyelik bir koşul yazmak istiyorum. Kısaca şöyle açıklayayım mesela sensör 5 saniye bir şey algılamazsa buzzer aracılığıyla uyarı sistemi yapmak. Bunu nasıl yapabilirim. Eğer bilginiz varsa yardımcı olursanız sevinirim. Lütfen iletişime geçin
Merhaba, yorumu yazdığınız konuda bulunan “millis” fonksiyonu ile bu işlemi gerçekleştirebilirsiniz. Sorunu tam olarak nerede yaşadığınızı baser61061@gmail.com adresine gönderebilirseniz yardımcı olmaya çalışırım. İyi çalışmalar dilerim…
Merhaba,kodun bir kısmını arduino başlattıktan ilk 5 saniye çalışmasını istiyorum. 5. saniyeden sonra o kısım hiç çalışmamalı. Bunu nasıl ayarlayabilirim. Bu konuda yardımcı olabilir misiniz?
Merhaba, bahsettiğiniz işlem için millis fonksiyonunu kullanabilirsiniz. Setup fonksiyonun sonunda millis fonksiyonunun değerini kayıt edin. Daha sonra loop içerisinde millis ile kayıt ettiğiniz süre arasındaki farka bakarak 5 saniye geçti mi diye kontrol edebilirsiniz. Sorunu çözemezseniz daha iyi yardımcı olabilmem için mail atmanızı tavsiye ederim. İyi çalışmalar dilerim…
merhaba arduinoda buton’a 2 kere basıldığında aradan geçen zamanı bularak örnek veriyorum 1 saniyenin altındaysa hizli 2 sn yenin altındaysa orta 3 snyenin altındaysa yavas yazdırmak istiyorum yardım ederseniz sevinirim.Şimdiden teşekkürler
Arduinoda yılda bir kere hatırlatıcı alarm döngüsü oluşturmak istiyorum basit bir kod yöntemiyle nasıl yazabiliriz.
Merhaba, bahsettiğiniz işlem için RTC kullanmanızı şiddetle tavsiye ederim. Arduino içerisindeki timer’ lar 1 yıl gibi süreyi doğrudan sayamazlar. Ancak bir değişkeni belirli zamana aralıklarında artacak şekilde ayarlayabilirsiniz. Böylece değişkenin 1 yıl sonra olması gereken değerini hesaplayıp o değere ulaştı mı kontrolü gerçekleştirebilirsiniz. Ancak bu işlemde 1 yıldan belki 1 gün daha uzun ya da daha kısa hatalı sayabilirsiniz. En kesin çözüm RTC kullanmaktadır. İyi çalışmalar dilerim.