Basitçe kesme, Arduino’da kullanılan işlemcimizin,
bizim belirlediğimiz bir anda yapmakta olduğu işi bırakıp, bizim istediğimiz
işi yapması ve sonra kaldığı yerden devam etmesidir.
Bildiğiniz üzere Arduino gibi tek işlemci birimine
(veya tek çekirdekli) sahip donanımlarda
herhangi bir işletim sistemi (RTOS) kullanılmadığı durumlarda işlem sırası
yukarıdan aşağıya doğru sıra ile gerçekleşir. Normal şartlar altında bu sıra
asla terk edilmez ve girişlerdeki değişikler sırası geldiğinde kontrol edilir.
Ancak çok uzun yazılım içeren veya içerisinde yüksek bekleme süresine sahip
uygulamalarda düşük tepki süresine ihtiyaç duyulduğunda pinin okunma sırasını
beklemek çok geç kalınmasına sebep olabilir. Bu gibi durumlarda kesmeler (Interrupt)
çokça işe yararlar.
Akıllarda daha iyi otursun diye bir örnek vermek
gerekirse; siz belirli aralıklar ile bilgisayarınızda belirli işleri
yapıyorsunuz. Bilgisayar başında ödevinizi yapıp, ders çalışıyorsunuz. Ve aniden
kapı çalıyor. Ne yaparsınız? Tabi ki de yaptığınız işi bırakıp kapıyı açar daha
sonra yarım kalan işe geri dönersiniz. İşte bu örnekte, hali hazırda yapmakta
olduğunuz iş Arduino için örnek vermek gerekirse, void loop() fonksiyonu, kapının çalması ise kesme yani interrupt’tur.
Örneğin bizim arduino’nun interrupt pinlerine
bağlı bir butonumuz olsun. Normal şartlarda interrupt kullanmadan direk buton
kodu ile if-else şeklinde butonu
kullanmayı denersek kodumuz sadece if
kısmı geldiğinde butona basılıp basılmadığını kontrol edecek ve o zaman if’in içine girebilecek. Örneğin 5 saniye
yanıp 5 saniye sönen bir ledimiz olsun ve butona basıldığında ledin yanıyorsa sönmesini,
sönük durumda ise yanmasını isteyelim. Bu durumda koddaki 5 saniyelik delay
kısmında butona istediğimiz kadar basalım kod beklemede olduğu için hiç bir işlemi
yerine getiremeyecektir. İşte bu noktada devreye interrupt giriyor. Interrupt,
kod delay fonksiyonu içinde bile olsa devreye girip istenilen işlemleri
yaptırabiliyor. Yani kısaca interrupt, anlık müdahale yapmamız gereken yerlerde
kullanılıyor.
Kesmelerin
Geçici Olarak Devre Dışı Bırakılması
Kesmeler, belirli önemli görevlerin arka planda
gerçekleşmesine izin verir ve varsayılan olarak etkindir. Bazen, belirli
koşullar altında, kodunuzda kritik bir bölüme ihtiyacınız olabilir. Kesmeler, kodun
zamanlamasını hafifçe bozabildiği için bu kritik bölümde CPU'nun kesintiye
uğramadan çalışmasını isteriz. İşte böyle bir durumla karşılaştığımızda
kesmeleri geçici olarak devre dışı bırakıp sonra tekrar aktif hale
getirebiliriz.
Arduino (Atmega328p) bu amaçla kullanabileceğiniz
global bir kesme etkinleştirme/devre dışı bırakma kontrol bitine sahiptir. Bunlar:
noInterrupts ( ) :Küresel
kesmeleri devre dışı bırakır.
interrupts ( ) :Küresel
kesmeleri devre dışı bırakıldıktan sonra yeniden etkinleştirir.
void setup() {}
void loop()
{
noInterrupts();
// Kritik bölüm
interrupts();
// Kodun Geri Kalanı
}
Yukarıdaki komutlara alternatif olarak, aynı
işlevselliği sağlayan ancak makro oldukları için çok daha hızlı olan iki
Arduino makrosu (fonksiyonu) vardır. Arduino'nun Atmega328p
mikrodenetleyicisinin talimat setinde SEI ve CLI birleştirme talimatları
vardır. Bu iki makro aşağıdaki gibidir:
cli ():Kesme genel etkinleştirme bayrağı bitini temizle
(tüm kesmeleri devre dışı bırak).
sei ():Kesme genel etkinleştirme bayrağı bitini ayarla (kesmeleri devre dışı bıraktıktan sonra yeniden etkinleştir).
void setup()
{} void loop()
{ cli(); // Kritik bölüm sei(); // Kodun Geri Kalanı } NOT: Kesmelerin devre dışı bırakılması, zamanlama
işlevlerini (milisaniye, mikro ve gecikme işlevleri gibi), gelen iletişimi ve
bazı işlemleri bozacağından kullanımı mümkün olduğunca en aza indirilmelidir.
Arduino’da dış kesme, zaman kesmesi, pin değişim
kesmesi ve haberleşme kesmesi gibi kesmeler bulunmaktadır. Haberleşme kesmeleri
dış kesmenin haberleşme donanımlarında bulunan modelidir. Örneğin; seri porttan
veri gelmesi durumunda yapılmasını istediğimiz işlemler varsa bu kesmeler
sayesinde gerçekleştirilebilir. 1-
Dış Kesme(External Interrupt) Dış kesmeler, Arduino’nun özel pinlerinde
gerçekleşen voltaj değişimlerini takip eden kesmelerdir. Örneğin Arduino’nun
dış kesme pinine bağlanmış bir düğmeye basıldığında, dış kesme Arduino’ya
otomatik olarak haber verir. Arduino kartlarının her birisinin dış kesme pini
vardır. Arduino Uno için bu pinler
Dijital 2 ve 3 numaralı pinlerdir. Bu pinlerden arduino sürekli olarak
dinleme yapabilir ve pindeki voltaj değişimlerini anında algılayabilir. Aşağıdaki tabloda Arduino türlerine göre dış kesme
özelliğine sahip pinler gösterilmiştir.
Arduino Uno’da dijital 2 ve 3 nolu pinlere
baktığımızda INT0 ve INT1 yazdığını görebilirsiniz. Bunlar “Interrupt 1” ve
“Interrupt 2” olarak ifade edilir ve kesmelerin kolay kullanımı için
özelleştirilmiştir. Kesmenin kullanımı için bazı modlar belirlenmiştir. Bunlar
şu şekildedir: ·
LOW : Pin gerilimi Lojik-0 olması durumudur. ·
CHANGE : Pin geriliminin değişmesi durumudur. 0’dan 5’e
yada 5’ten 0’a. ·
RISING : Pin geriliminin Lojik-0′ dan Lojik-1′ e geçmesi
durumudur. ·
FALLING : Pin geriliminin Lojik-1′ den Lojik-0′ a düşmesi
durumudur. Not: Burada bahsedilen Lojik-1, Uno, Mega vb. 5V mikrodenetleyiciler
için 2.5V üzeridir. Due gibi 3.3V mikrodenetleyiciler için 1.65V üzeridir.
Arduino da dış kesme attachInterrupt(); fonksiyonu kullanılarak yapılmaktadır. attachInterrup(); fonksiyonu içerisinde 3 adet değişken barındırır. attachInterrupt (dijitalPin, kesme
fonksiyonu, kesme modu); dijitalPin :Arduino’nun kesme için kullandığımız pinidir.
Fakat buraya yazacağımız değer Arduino pin numarası değil interrupt
numarasıdır. Örneğin; Arduino UNO da 2.
dijital pinden kesme yapılacaksa buraya 0, 3. dijital pinden kesme yapılacaksa
ise buraya 1 yazılmalıdır. Kesme fonksiyonu :Kesmeye girildiğinde yapılması gereken işlemlerin
içinde bulunduğu fonksiyondur. Void loop’un dışına yazılmalıdır. Kesme modu :Kesmeye hangi durumda girileceğini gösteren moddur.
Örneğin; pin geriliminin Lojik-0′ dan Lojik-1′ e geçmesi durumunda kesme
olacaksa RISING
yazılmalıdır. Kesme fonksiyonunu aşağıdaki türde de yazabiliriz:
digitalPinToInterrupt(); fonskiyonu,
kullanılacak dijital pin için interrupt numarasını döndüren bir fonksiyondur. Bu fonksiyon da aynı
işi yapar. Yazılımın çalışması sırasında kesmenin modunu
değiştirmek veya tamamen devre dışı bırakmak isteyebilirsiniz. Bunun için
aşağıdaki fonksiyonu kullanmanız kesmeyi devre dışı bırakmak için yeterli
olacaktır.
detachInterrupt(digitalPinToInterrupt(2)); 2-
Pin Değişim Kesmesi(PCI - Pin Change
Interrupt) Bu kesmeyi incelediğimizde adından da anlaşılacağı
üzere belirlenen herhangi bir pinin lojik seviyesinde (HIGH veya LOW) herhangi
değişim meydana geldiğinde yani HIGH iken LOW olduğunda veya LOW iken HIGH
olduğunda kesme rutini çalıştırılır.
Arduino Uno ya ait bütün pinleri kullanarak bu
şekilde kesme rutinleri çalıştırabiliriz. Dikkat etmemiz gereken şey ise; PortD0
ve PortD1 pinleri (Arduino Uno için 0 ve 1 pinleri) seri haberleşme için
kullanıldığından dolayı bu pinleri başka bir yerde kullanmak işlemciye program
atarken problem oluşturabilmektedir. Atmega328P’nin pin değişim kesmesinin vektörleri
vardır. Kullanmak istediğimiz pine göre vektör tanımı yapılmalıdır. Şöyle: ·
ISR (PCINT0_vect) : PortB’ye ait pinler. (Arduino 8 – 13 pinleri). ·
ISR (PCINT1_vect) : PortC’ye ait pinler. (Arduino A0 – A5 pinleri). ·
ISR (PCINT2_vect) : PortD’ye ait pinler. (Arduino 0 – 7 pinleri).
Vektör tanımı program içerisinde aşağıdaki
örnekteki gibi yapılır. Yani kesme oluştuğunda aşağıdaki kısım çalışır: ISR (PCINT0_vect) { //komutlar
} İstediğimiz pine ait pin değişim kesmesini yapmak
için bu kesmeye ait register’larda yapmamız gereken işlemler de aşağıdaki
fonksiyon ile gerçekleştirilir: void pciSetup(byte pin) { *digitalPinToPCMSK(pin) |= bit (digitalPinToPCMSKbit(pin)); // enable pin PCIFR |= bit
(digitalPinToPCICRbit(pin)); // clear any
outstanding interrupt PCICR |= bit
(digitalPinToPCICRbit(pin)); // enable
interrupt for the group
} Kesme için pin seçimi de aşağıdaki komutla
yapılır: void setup() { pciSetup(pin);
} EK BİLGİ: Burada Pin Değişim Kesmesini kontrol eden
aşağıdaki register’ların ayarlarıyla ilgili detaylı bilgilere internet
üzerindeki kaynaklardan ulaşılabilir. Biz şu an yukarıdaki bilgiler ışığında
program yazacağız. Ø PCICR (Pin
Change Interrupt Control Register) Hangi porta ait pinlerde kesme olacağını
ayarlarız. PortB, PortC, PortD. Ø PCIFR (Pin
Change Interrupt Flag Register) Porttaki
pinlerde değişim olduğunda registerin ilgili pini 1 olur. Ø PCMSK (Pin
Change Mask Register)
Portlara ait hangi
pinlerde kesme yapılacaksa o pin 1, diğerleri 0 yapılır. 3-
Zaman Kesmesi(Timer Interrupt) Timer Nedir: Timer; belirli zaman aralıklarında yapmak istediğimiz
olayların gerçekleşmesinde bize yardımcı olan yapıdır. Belirlediğimiz bir süre
sonunda, belirlediğimiz görevleri yaptırabiliriz. İşlemciye o zaman dilimi
geldiğinde ne yapması gerektiğini hatırlatır. Timer, zamanı saymak, gecikmeler
oluşturmak veya periyodik olaylar oluşturmak için kullanılabilir. Örneğin; 1
saniyede bir kodda nerede olursak olalım sensörden veri okumak istersek bu
kesmeyi kullanabiliriz. Kod o sırada delay() fonksiyonu içinde bile olsa
sensörden veri almaya devam edecektir. Klasik bir örnek olan belirli zaman aralıklarında
herhangi bir çıkışa bağlı led’i yakmak istediğimizde, timer kullanmadığınızı
varsayarsak, bu işlemi gerçekleştirmek için geçen zamanı millis(), micros()
fonksiyonları ile sürekli olarak kontrol etmeli ya da delay() gibi kaçınılması
gereken komutlarla o an işlemciyi bloke etmek zorunda kalabiliriz. Bunları
yapmak yerine işlemcide var olan bu yapılar ile gereken zaman kontrolünü
sağlayabiliriz. Bunu yaparken işlemcide diğer paralel işlemlerin devam etmesi
ise bize çoklu işlem yapabilme yeteneği kazandırır. Timer Nasıl
Çalışır: Timer’lar, sayaç yazmacı olarak bilinen counter register değişkenini, kayıtçıya(TCNTx)
yüklenen bir başlangıç değerinden itibaren her clock sinyalinde 1 arttırırlar.
Bu yazmaç, Timer’ın bit sayısına bağlı olarak maximum bir değere kadar ya da
belirlediğimiz bir karşılaştırma değerine kadar ulaşır. Timer’lar genellikle 8
bit veya 16 bit olarak karşımıza çıkarlar. 8 bit ise maximum 255’e, 16 bit ise
maximum 65535’e kadar çıkar. Bu yazmaç maksimum değerine ya da daha önce
belirlediğimiz karşılaştırma değerine ulaştığı zaman kayıtçı sıfırlanır(ya da
sıfırdan başlar) ve Interrupt Service Routine (ISR) ile kesme
oluşturulur. Bu kesmede tüm kontrolleri ISR sağlamaktadır. Örneğin; 8 bitlik counter register’ın ilk değeri
50 olarak belirlendi diyelim. Her clock sinyalinde bu değer bir artırılacaktır.
Counter register’ın değeri, 255 olduktan bir adım sonra sıfırlanacaktır. Bu
noktada zaman kesmesi gerçekleşecektir. Kesme gerçekleştiğinde Arduino otomatik
olarak kesme fonksiyonunu çalıştıracaktır. Timer, çalışması için bir clock sinyaline ihtiyaç
duyar. Bu sinyal her oluştuğunda counter’ı 1 arttırır. Bu sinyal harici
olabileceği gibi dâhili olarak da çoğu işlemcide mevcuttur. Örneğin; bir timer’a 16MHz clock sinyali sağlarsak, bu timer için 1 periyot olur.
Bu timer’ların sayısı kullandığınız Arduino çeşidine göre değişiklik göstermektedir. Örneğin; Uno’ da Timer0, Timer1 ve Timer2 olmak üzere 3 tane varken Mega’ da bu sayı 5′ e kadar çıkmaktadır.
Timer’larda
Prescaler Ayarı Timer’ın çalışması için osilatör’de bir prescalar
ayarı denilen bir ayar bulunmaktadır. Buna zamanlayıcı ön ölçekleyici ya da
bölme oranı da denilebilir. Bu ayar bizim kristalimizin çalışma frekansını
düşürmek için kullanılır. Arduino osilatörü 16Mhz’ de çalışır. Örneğin biz prescalar
değerini 64 yapalım. Bu durumda frekansımız; olur. Bu prescalar değerini kullanmadığımızda
frekans çok yüksek olacağı için timer çok hızlı sayacak ve belki de 1 sn’den
çok daha küçük değerlerin üzerine çıkamayacağız. Aşağıda Timer0, Timer1, Timer2 prescalar değerini
belirlemek için register’da yapılması gereken değişiklikleri gösteren clock
seçimi bilgi tabloları yer almaktadır. Arduino Timers
Control Registers 1. TCCRxA,
TCCRxB: Bunlar zamanlayıcı
kontrol kayıtçılarıdır. x;
zamanlayıcı numarasını temsil eder. Timer0 kullanıyorsanız, TCCR0A ve TCCR0B
kayıtçılarıyla ilgilenmemiz gerekir. Bu kayıtçılardaki WGM00, WGM01, WGM02
bitleriyle zaman kesmesi modu ayarlanır. 2. TCCRxB: Bu kayıtçıdaki CS00, CS01 ve CS02 bitleri osilatörün
prescaler değerini ayarlamak için kullanılır. 3. TCNTx: Timer’ın başlangıç değerini belirlediğimiz
kayıtçıdır. Timer counter kayıtçısıdır. 4. OCRxA, OCRxB: Timer’ın bitiş değerini belirlediğimiz,
karşılaştırma yapacağımız kayıtçıdır. TCNTx ile belirlediğimiz Timer başlangıç
değeri, bu iki kayıtçıdan herhangi birine yüklediğimiz değer ile
karşılaştırılır. Eşleşme olunca kesmeye gidilir. Timer kesmesinin CTC modunda
kullanılır. 5. TMISKx: OCIExA ve
OCIExB bitleri ile OCRxA ve OCRxB
için karşılaştırma kesmeleri aktif edilir. TOIEx
ile de overflow kesmesi aktif edilir. 6. ICRx: Giriş yakalama kayıtçısı. Bu kayıtçı Analog
Karşılaştırıcı konusunda işlenecektir. NOT: Kayıtçıların bitlerinde değişiklik yapmak için: “|=” (veya eşit), “&=” (ve eşit),”=” (eşit) şeklindeki bitsel operatörler kullanılabilir. Kayıtçıdaki
herhangi bir biti 1 yapmak için; “|=”
i, 0 yapmak için; “&=” i
kullanabiliriz. Bu bitsel operatörler kullanıldığında, kayıtçıdaki 0 yapılacak
bitler önce, 1 yapılacak bitler ise en son ayarlanmalıdır. Çünkü bazı
kayıtçılarda bu operatörlerle bir bit sıfır yapıldığında, tüm kayıtçıyı
sıfırladığı görüldü. Bu nedenlerden
dolayı bu operatörler yerine kayıtçı_adı=0b10010001
şeklinde ya da bitSet() ve bitClear() komutlarının kullanımı daha sağlıklı olmaktadır.
NOT:
Kesme alt programları içerisinde seri port ekranına yazdırma işlemi
yapılmamalıdır.
İki Farklı
Zaman Kesmesi Modu Vardır: ·
Normal Mod
veya Overflow Interrupt ·
Clear Timer on
Compare Match Interrupt (CTC) Overflow
Interrupt; sayaçta taşma(overflow) meydana
geldiğinde kesmeye gidilmesi. CTC ise;
bizim daha önceden set ettiğimiz bir count değerine eşit olunca kesmeye
gidilmesi.
a. Clear Timer on
Compare Match Kesmesi ( CTC ) CTC kesmesinde başlangıç değeri; TCNTx kayıtçısında,
bitiş değeri ya da karşılaştırma değeri ise; OCRxA veya OCRxB kayıtçısında
belirlenir. Başlangıç değerinden itibaren sayma işlemi başlar. Sayma işlemi
sırasında karşılaştırma değerine ulaşıldığında kayıtçı sıfırlanacak-sıfıra
temizlenecek ve bir kesme fonksiyonu içerisine girilecektir. Bu
fonksiyon ISR(TIMERx_COMPy_vect) fonksiyonudur.
Buradaki “x” değeri timer numarası(0,1,2), “y” değeri ise karşılaştırma
kayıtçısı harfidir(A,B). Kayıtçılar sıfırlanacak demiştik. Bu nedenle kesme
fonksiyonu içerisinde kayıtçılara değerleri tekrar verilmelidir. Örneğin; 8 bitlik bir timer olsun. Timer’ın ilk
değeri 100, son değeri 250 olarak belirlensin. Bu değer her bir saat darbesinde
artacak olup 250’yi geçtiği anda sıfırlanacaktır ve kesme fonksiyonu içerisine
girilecektir. Zaman kesmesinin oluşma süresi aşağıdaki formül
ile hesaplanabilir: olur. Bu formülde Timer bitiş değerini 8 bitlik timer’da maksimum 255’e kadar, 16 bitlik timer’da maksimum 65535’e kadar değer girilerek kesme süresi değiştirilebilir. Formüldeki +1 ise 0’ın da dâhil olmasındandır. CTC zaman kesmesi örnek-1: void setup
() { cli(); //tüm kesmeler
durduruldu
//timer0 kesmesi TCCR0A = 0; //TCCROA register 0'lanıyor TCCR0B = 0; //TCCROB register 0’lanıyor TCNT0 = 0; //timer0 başlangıç değeri sıfırlandı OCR0A = 124; //timer0 bitiş/karşılaştırma değeri belirlendi TCCR0A |= (1 <<
WGM01); //CTC(Clear
Timer on Compare Match) mod açıldı TCCR0B |= (1 <<
CS01) | (1 << CS00); //prescalar değeri 64 yapıldı TIMSK0 |= (1 <<
OCIE0A); //timer0 OCR0A karşılaştırma
kesmesi aktif edildi
//timerl kesmesi TCCR1A = 0; //TCCR1A register 0’lanıyor TCCR1B = 0; //TCCR1B register 0'lanıyor TCNT1 = 0; //timer1 başlangıç değeri sıfırlandı OCR1A = 15624; //timer1 bitiş/karşılaştırma değeri belirlendi TCCR1B |= (1 <<
WGM12); //CTC(Clear Timer on Compare
Matah) mod açıldı TCCR1B |= (1 <<
CS12) | (1 « CS10); //prescalar değeri 1024 yapıldı TIMSK1 |= (1 <<
OCIE1A); //timerl OCR1A karşılaştırma
kesmesi aktif edildi
//timer2 kesmesi TCCR2A = 0; //TCCR2A register 0'lanıyor TCCR2B = 0; //TCCR2B register 0’lanıyor TCNT2 = 0; //timer2 başlangıç değeri sıfırlandı OCR2A = 249; //timer2 bitiş/karşılaştırma değeri belirlendi TCCR2A |= (1 <<
WGM21); //CTC(Clear Timer on Compare
Matah) mod açıldı TCCR2B |= (1 <<
CS21); //prescalar değeri 8 yapıldı TIMSK2 |= (1 <<
OCIE2A); //timer2 OCR2A karşılaştırma
kesmesi aktif edildi
sei(); //tüm
kesmelere izin verildi }
void loop() { //Do Nothing }
//CTC
zaman kesmesi olduğunda çalışacak kesme alt programı ISR(TIMER0_COMPA_vect) { //komutlar } ISR(TIMER1_COMPA_vect) { //komutlar } ISR(TIMER2_COMPA_vect) { //komutlar } CTC zaman kesmesi
örnek-2: #define LED_A_PIN
13 #define LED_B_PIN
8 void setup() { TCCR1A = 0; //Init Timer1A TCCR1B = 0; //Init Timer1B TCCR1B |=
B00000011; //Prescaler = 64 OCR1A = 20000; //Timer1 Compare1A Register OCR1B = 8750; //Timer1 Compare1B Register TIMSK1 |=
B00000110; //Timer1 OCR1A and OCR1B Compare
Interrupts Enable pinMode(LED_A_PIN, OUTPUT); pinMode(LED_B_PIN, OUTPUT); } void loop() { //Do Nothing }
ISR(TIMER1_COMPA_vect) { OCR1A += 20000; digitalWrite(LED_A_PIN, !digitalRead(LED_A_PIN)); } ISR(TIMER1_COMPB_vect) { OCR1B += 8750; digitalWrite(LED_B_PIN, !digitalRead(LED_B_PIN)); } b. Normal Mod ya da
Overflow Kesmesi Zamanlayıcı ön yükleme kesmesi anlamına gelir. TCNTx kayıtçısından başlangıç değerini verdikten sonra Timer bit sayısı durumuna göre, 8 bit ise 255’e, 16 bit ise 65535’e kadar sayar ve ardından taşma-overflow meydana gelir. Bu taşma sonucu kayıtçı sıfırlanmaz fakat sıfırdan tekrar başlar ve bir kesme fonksiyonu içerisine girilecektir. Bu fonksiyon ISR(TIMERx_OVF_vect) fonksiyonudur. Kayıtçı sıfırdan tekrar başlar demiştik. Bu nedenle kesme fonksiyonu içerisinde kayıtçıya değeri tekrar verilmelidir. Overflow kesme süresi aşağıdaki formülle
hesaplanır: Overflow kesmesi örnek: void setup
() { pinMode(9, OUTPUT); cli() ; //tüm kesmeler durduruldu
//Timerl için ayarlar yapılıyor TCCR1A = 0; //TCCR1A register 0’landı TCCR1B = 0; //TCCR1B register 0’landı TCCR1B |= (1 <<
CS11); // prescalar değeri 8
yapıldı. Yani 16/8 =2 Mhz TCNT1 = 40535; //timer1 başlangıç değeri belirlendi TIMSK1 | = (1 <<
TOIE1); //Overflow
kesmesi aktif edildi sei(); //tüm kesmelere izin verildi }
//Overflow
kesmesi olduğunda çalışacak kesme alt programı ISR(TIMER1_OVF_vect) { digitalWrite(9, !digitalRead(9)); TCNT1 = 40535; //timer1 başlangıç değeri tekrar belirlendi } Overflow kesmesinin bazı
dezavantajlarından bir tanesi istediğimiz frekans değerlerinin tam olarak
ayarlanabilmesinin zor olmasıdır. Çünkü her seferinde counter’ın sona kadar
arttırılıp kesmenin oluşması beklenmektedir. Bunun yerine daha hassas frekans
oynamaları yapabildiğimiz, timer’in bizim belirlediğimiz bir değere
ulaşmasından sonra kesmeye gidilmesini sağlayan CTC kesmesi daha verimlidir. Zaman kesmesinde harici
clock kullanımı: Zaman kesmesinde normalde Arduino’nun
frekansı clock sinyali olarak kullanılır ama istersek clock sinyalini dışardan
bir kaynaktan da kullanabiliriz. Yani herhangi bir elektronik devreden, NE555 entegresi
gibi bir kaynaktan üretilen clock sinyalini de timer kesmesi için kullanmamız
mümkündür.
Arduino Uno Atmega328p’de harici clock
kullanılırken; Timer0 kesmesi için clock sinyali 4. pinden, Timer1 kesmesi için
clock sinyali 5. pinden verilir. TCCR1B
register’ındaki ilgili CS…’ler set
edilir. Hangi CS’lerin set edileceği ve yükselen-düşen kenar seçimi yukarıdaki Timer tablolarında yer almaktadır. Bu
kesmede prescalar değeri yoktur. Dolayısıyla kesme süresi aşağıdaki formüldeki
gibi olur: Bu ayarlamalar dışında geri
kalan kod yazımı aynı olur. ÖNEMLİ: Harici clock sinyali ile ilgili 2 farklı
uygulama yaptık. Birincisi; buton kullanarak 5 nolu pinden clock sinyali verdik.
İkincisi; 3 nolu pinden PWM sinyali gönderip, bu pini bir direnç üzerinden 5
nolu pine bağlayarak clock sinyali verdik. Aslında Arduino’nun ürettiği PWM
sinyalini, tekrar Arduino’nun Timer1’i için harici clock kaynağı olarak
kullanmış olduk.
4-
Timer1 Giriş Yakalama Kesmesi Atmega328’e ait Timer1’de giriş yakalama işlevi
vardır. Giriş yakalama pininde (ICP1)
veya analog karşılaştırıcı çıkışında (ACO)
bir mantık seviyesi değişikliği meydana geldiğinde bir yakalama tetiklenir.
Gerekli ayarlamalar yapılarak kesmeye gidilmesi sağlanır. Timer1 giriş yakalama
kesmesi, 50. Konu olan “Analog Karşılaştırıcı Kullanımı” konusunda
detaylı olarak anlatılmış ve çeşitli uygulamalar yapılmıştır.
Timer’ları Kullanan
Fonksiyonlar: Zaman kesmesi konumuzda bahsettiğimiz
Timer’ları, Arduino, bazı komutlarında ya da fonksiyonlarında kullanmaktadır.
Bunlar: ·
Timer0, delay(),
millis() ve micros() gibi zamanlama fonksiyonları tarafından kullanılır. ·
Arduino Uno'daki timer1 veya Arduino Mega'daki timer5
servo kütüphanesi tarafından kullanılır. ·
Timer2, tone()
fonksiyonu tarafından kullanılır. ·
PWM için kullanılan analogWrite() komutu, 6 adet PWM çıkış pininden: v 5 ve 6. Pinler için; Timer0’ı v 9 ve 10. Pinler için; Timer1’i v 11 ve 13. Pinler için Timer2’yi kullanır. Timer’ları kullanırken aynı zamanda bu
fonksiyonlardan biri de kullanılacaksa, zaman sayacını değiştirdiğimizde bu
komutlar da etkilenebilir. Bu durum göz önünde bulundurulmalıdır. Kaynaklar: https://www.elektrobot.net/arduino-ile-timer-kullanimi/ https://sinanbir.com/arduino-timer-kullanimi-kesmeler-avr-8-bit/ https://www.instructables.com/Arduino-Timer-Interrupts/ https://maker.robotistan.com/arduinoda-kesme-islemleri/ https://www.mekinfo.net/arduino-dersleri-11-interrupt-kesmeler/ ____________________________________________________________________________________________________________________________________________________ |
0 comments:
Yorum Gönder