8051 Mikrokontrolcü Ailesi - 3

   6.   8051 Zamanlayıcı ve Sayıcılar

Zamanlayıcı ve sayıcılar aşağıdaki görevler için kullanılırlar.

   Zaman gecikmesi yaratmak için

   Pals zamanı veya zaman aralığı ölçmek için

   Pals veya oluşan olayları saymak için

   Çoklu işlem uygulamalarında (Multi-tasking)

   Kesme üretmek için

Standart 8051 iki zamanlayıcı/sayıcıya sahiptir. Bu zamanlayıcı/sayıcılar 8 bit veya 16 bit zamanlayıcı/sayıcı olarak kullanılabilir.  Aşağıda M1 ve M0 bitlerinin değerlerine bağlı olarak zamanlayıcı/sayıcıların hangi modlarda kullanılabileceği belirtilmektedir.

 TMOD

 M1 M0  FUNCTION                                                              

| 0  0  |    8 bit counter or 8 bit timer with / 32 scaler                 

| 0  1  |    16 bit timer/counter                                                 

| 1  0  |    8 bit timer counter with auto-reload to initial start for count up   

| 1  1  |    TC1 - disabled                                                       

   TH0 - TH0 is an 8 bit timer incremented by setting TR1.Interrupts  are channelled to .001Bh                                         

  TL0 - is an 8 bit timer/counter controlled by TMOD and TCON         

Zamanlayıcı/sayıcı  çalıştır bitleri TR1 ve TR0, TCON registerinde bulunur. Bu bitlerden birisi  "1" yapıldığında,  bu bite  karşılık gelen sayıcı çalışmaya başlar.  Bu bitlerin değeri "0" yapıldığında zamanlama/sayma işlemleri de bitirilmiş olur.  Kesme kontrolü registerinde (IE) bulunan ET1 ve ET0 bitleri, zamanlayıcı taşmasında kesme üretilip üretilmeyeceğini belirlemekte kullanılır.  Bit değerinin "1" olması, zamanlayıcı/sayıcı taşmasının kesme üretmesi anlamına gelir.

TMOD registerindeki C/T biti, zamanlaycı/sayıcıyı, sayıcı modunda veya zamanlayıcı modunda çalıştırmak için kullanılır.  Bu bitin değeri "1" yapıldığında zamanlayıcı/sayıcı, 8051 entegrenin TX giriş pinindeki olayları saymak üzere konfigüre edilmiş olur.

Bu bitin değeri "0" olduğunda zamanlayıcı/sayıcı, zamanlayıcı modundadır ve sistem osilatöründen gelen sinyali 12'ye bölerek çalışır.

TMOD registerindeki GATE biti, "1" yapıldığında, zamanlayıcı/sayıcı n'in aktif olması için, INTn ve TRn bitleri "1" yapılmalıdır.  GATE biti "0" yapıldığında zamanlayıcı/sayıcı n,in aktif yapılması için, TRn bitinin "1" yapılması yeterlidir.  GATE biti zamanı ölçmekte, olayların zamanını ölçmekte, pals genişliğini ölçmekte kullanılır.  INTx hattı "1" olduğu sürede, bu değerler sayıcya geçirilir. Sistem osilatörünün frekansı 12'ye bölünerek zaman sayması gerçekleşir. Buna göre 12 MHz osilatör kullanan bir sistemde, zamanlayıcının frekansı 1 Mhz olur.

 

T0 Giriş Ucundan Pals Sayılması zamanlayıcı 0 (mod 1)

                             ; T0 ucuna gelen dış sinyallerin sayılması

 MOV TH0, #0          ; zamanlayıcı/sayıcıyı sıfırla

 MOV TL0, #0          ;

 MOV TMOD, #5       ; zamanlaycı/sayıcıyı sayma moduna getir.

                             ; C/T=1, Mod 1

 SETB TR0               ; zamanlayıcı/sayıcıyı başlat

 ; Sayılan olay sayısı herhangi bir anda TH0/TL0 registerlerinin okunmasıyla ; elde edilebilir. Sayma olayı, mikrokontrolcünün asıl yaptığı işten bağımsız ; olarak geri planda sayılır.

 Yukarıdaki program parçasında frekansı yüksek olayların sayılması sırasında önemli bir problem ortaya çıkabilir.  Örneğin zamanlayıcı 0'ın içeriği okunup, program tarafından kullanılamadan zamanlayıcı 0 taşmış olabilir.

 Ön Düzenleme Kullanılarak Pals sayılması (mod 0)

Öndüzenleme mod 0 kullanılarak, girişte oluşan palslar  32 ye bölünebilir. Bu sayede çok hızlı olayların sayılması kolaylaşmış olacaktır. Zamanlayıcı/sayıcı girişte 32 olay oluştuğunda 1 artacaktır.

                               ;T0 ucunda oluşan olayları 32'ye bölerek say

 MOV TH0, #0            ; zamanlayıcı/sayıcıyı sıfırla.

 MOV TL0, #0            ;

 MOV TMOD, #4         ; zamanlayıcı 0 sayıcı modunda , C/T=1, Mod 0

 SETB TR0                 ; zamanlayıcı/sayıcıyı başlat

 Zaman dilimi yaratmak  Mod 1: 16 bit zamanlayıcı/sayıcı

 Zamanlayıcı/sayıcılar, işlemcinin servisine gerek duymadan geri planda çalışabildiklerinden, zamanlayıcı/sayıcılar kullanılarak zaman dilimi yaratmak ve gerçek zamanı saydırmak olanaklıdır.

 Eğer zamanlayıcı/sayıcının her iki registeri, 00h değeriyle yüklenirse, bir taşma meydana gelmeden önce, zamanlayıcı/sayıcı 65,536 sayma gerçekleştirecektir.  12 Mhz lik entegre osilatörü kullanılan bir devrede, bu yaklaşık olarak 66 milisaniyelik (65,536 mikrosaniye) zaman dilimine karşılık gelir.  Pek çok uygulamada genelde daha uzun zaman gecikmelerine gereksinim olduğundan, zamanlayıcı/sayıcı registerlerine ilave olarak bir 8 bit hafıza elemanı daha kullanılır.  Bu hafıza elemanın değeri her taşmada "1" azaltılarak gereken zaman dilimi yaratılır. TH0 ve TL0 registerlerinin başlangıç değerleri isteğe göre seçilebildiğinden hassas zaman dilimleri yaratmak olanaklıdır.  Örneğin TH0'a 80h, TL0'a 00h değerlerinin yüklenmesiyle zamanlayıcı sayıcı her 32,768 saymada taşacaktır. Taşma gerçekleştikten sonra, register değerleri tekrar 80h ve 00h değerleriyle yüklenmelidir. Aşağıdaki program parçası, gerçek gün zamanını ölçmek için zamanlayıcı/sayıcının nasıl kullanılabileceğini göstermektedir.

org 0000h          		; program başlangıç adresi
   JMP Anaprogram 
   org 000Bh        		; zamanlayıcı 0 kesme adresi
   JMP TC0kesme     		; zamanlayıcı 0 kesme programına git
   org 0100h          		; ana döngü başlangıcı
   Anaprogram:
   CALL Baslangıc		; RTC ilk değerlerini ver
   dongu: sjmp dongu  		; ana programın yapığı is
   
   ; R0 : uzun zaman dilimi yaratmak için kullanılan değişken
   ;TH0 ve TL0  0000h değerine ulaşınca kesme oluşturmak üzere programlansın
   
   Baslangıc:MOV R0, #20h	; R0 * 33ms  = 1sec
   MOV SAN, #00h        	;
   MOV DAK, #00h        	;
   MOV SAAT,  #00h      	; 
   MOV TH0,  #80h       	; 
   MOV TL0,  #00h        	; kesmeler arasında 33ms
   MOV TMOD, #01        	;C/T=0, mod 1 (16bit zamanlayıcı)
   MOV TCON, #10h       	;zamanlayıcı 0'ı başlat
   MOV IE,   #82h         	;tüm kesmeleri aktifle biti "1"
   ;zamanlayıcı "0" kesmesi aktif
   RET     			;Zamanlayıcı 0 olduğunda devreye girecek kesme programı

TC0kesme: DEC R0        ;sayıcı değişkeni azalt
   MOV A, R0           	;akümülatore al
   JNZ TC0CIK         	;sıfır değilse geri don
   MOV R0, #20h      	;R0'ın ilk değerini tekrar yükle
   INC SAN              ;saniye  = saniye + 1
   MOV A, SAN         	;
   SUBB A, #60        	;saniye  >= 60 ?
   JNZ TC0Cık     	;
   MOV SAN, #00      	;saniye = 0
   INC DAK      	;dakika = dakika + 1
   MOV A, DAK          	;dakika >= 60 ?
   SUBB A, #60         	;
   JNZ TC0CIK          	;
   MOV DAK, #00      	;dakika = 0
   INC SAAT            	;saat = saat + 1
   MOV A, SAAT        	;saat >= 24 ?
   SUBB A, #24         	;
   JNZ TC0CIK          	;
   MOV SAAT, #00    	;saat = 0
   TC0CIK:     MOV TH0, #80h; 
   MOV TL0, #00h     	;
   CLR TF0             	;
   RETI                	;
   SAN EQU R2         	;
   DAK EQU R3       	;
   SAAT EQU R4     	;
   End

Zaman Dilimi Yaratmak Mod 2: 8 bit Otomatik Yeniden-yükleme

(Auto-Reload)

Bir önceki örnekte, zamanlayıcı registerleri kesme programı içerisinde yeniden yüklenmek zorundaydı. Zamanlayıcı otomatik yeniden yükleme modunda kullanarak THx  registerindeki değerin otomatik olarak TLx değerine yüklenmesi olanaklıdır. THx yeniden yükleme değeri olarak adlandırılır ve TLx'de  normal zamanlayıcı görevini görmektedir. Bu yöntemin tek dezavantajı, sayma işleminin yalnızca 8 bit olmasııdır (Önceki örnekte 16 bit olduğuna dikkat ediniz). Aşağıda gün zamanı ölçümünün bu modda nasıl yapılabileceği bir örnekle verilmiştir.

org 0000h   		; program başlangıç adresi
   JMP Anaprogram
   
   org 0Bh     		; zamanlayıcı 0 kesme adresi
   JMP TC0kesme       	; zamanlayıcı 0 kesme programına git
   
   org 100h          	; ana döngü başlangıcı
   Anaprogram:
   CALL Baslangıc	; RTC ilk değerlerini ver
   dongu: sjmp dongu	; ana programın yaptığı iş
   
   ; R0 : uzun zaman dilimi yaratmak için kullanılan değişken
   ;TH0 ve TL0  0000h değerine ulaşınca kesme oluşturmak üzere ;programlansın
   
   Baslangıc:MOV R0, #20h	; R0 * 33ms  = 1sec
   MOV R1, #80h         	; R0 azaltılmadan önce kaç döngü
   MOV SAN, #00h        	;
   MOV DAK, #00h        	;
   MOV SAAT,  #00h      	;
   MOV TH0,  #00h       	; 256 kere
   MOV TL0,  #00h       	; kesmeler arasında 33ms
   MOV TMOD, #02        	;C/T=0, mod 2
   MOV TCON, #10h       	;zamanlayıcı 0'i başlat
   MOV  IE,   #82h         	;tüm kesmeleri aktifle biti "1"
   ;zamanlayıcı "0" kesmesi aktif
   RET  			;Zamanlayıcı 0 olduğunda devreye girecek kesme programı
   TC0KESME:  DEC R1           	;her 80h seferde R0'i azalt
   MOV A, R1                	;akumulatore al
   JNZ TC0CIK               	;sıfır değilse geri don
   MOV R1, #80h          	;R1'i tekrar yükle
   DEC R0                    	;
   MOV A, R0                	;
   JNZ TC0CIK               	;
   MOV R0, #20h           	; R0 ilk değerini tekrar yükle
   INC SAN                   	;saniye  = saniye + 1
   MOV A, SAN               	;
   SUBB A, #60              	;saniye  >= 60 ?
   JNZ TC0CIK               	;
   MOV SAN, #00           	;saniye = 0
   INC DAK                   	;dakika = dakika + 1
   MOV A, DAK               	;dakika >= 60 ?
   SUBB A, #60              	;
   JNZ TC0CIK               	;
   MOV DAK, #00           	;dakika = 0
   INC SAAT                  	;saat = saat + 1
   MOV A, SAAT             	;saat >= 24 ?
   SUBB A, #24              	; 
   JNZ TC0CIK               	; 
   MOV SAAT, #00        	;saat = 0
   TC0CIK:   MOV TH0, #80h     	;
   MOV TL0, #00h          	;
   CLR TF0                    	;
   RETI                        	;
   
   SAN   EQU      R2                        	;
   DAK   EQU      R3                        	;
   SAAT EQU      R4                         	;
   END 

Zamanlayıcı/Sayıcının Mod 3 de kullanımı
Bu modda zamanlayıcı/sayıcının TH0 ve TL0 registerleri iki bağımsız sayıcı olarak kullanılır. TCON ve TMOD registerlerindeki bit kontrolleri TH0 registerindeki taşmaları kontrol eder.  Kesme oluşumu TH0'ın taşması ile meydana gelir. 

Pals Genişliği veya olay zamanı ölçme (Gating)
Zamanlayıcı/sayıcı Mod 3 kullanılarak, pals genişliği, geçen zaman ve durum sayımı gerçekleştirilebilir. Kapılama biti (Gating) aktiflendiğinde, zamanlayıcı yalnızca, INTx girişi "1" olduğu sürece aktif kalır. Bu sayede, INTx  girişindeki bir sinyalin aktif olduğu zaman miktarını bulmak mümkündür.  Aşağıdaki örnek, böyle bir uygulamayı anlatmaktadır.

org 0000h              		; program başlangıç adresi
 JMP AnaProgram
 org 000Bh               	; Zamanlayıcı 0 kesme adresi
 SETB F0               		; F0 bitini tasma olduğunu belirtmek üzere aktifle
 RETI                       	; kesmeden dönüş
 
 org 001Bh             		; Zamanlayıcı 1 kesme adresi
 RETI                       	; Kesmeden dönüş
 
 Anaprogram: CALL BaslangIc
 lp1:          JNB P3.2, lp1   	;INT0 düşükse döngü
 lp2:          JB P3.2, lp2    	;INT0 yüksekse döngü
 
 ;Bu noktada, TL0 içerisinde, INT0 yüksek olduğu süredeki sayma değeri bulunmaktadır.
 ;Bu değer kolaylıkla zaman bilgisine çevrilebilir.
 
 lp3: JB F0, Hata      		; F0 "1" se Hata
 CALL Cevır       		;Tl0 daki değeri zaman bilgisine cevir
 CLR F0                		; F0'i temizle
 JMP lp1               		; tekrar don
 
 
 BaslangIc: MOV TH0, #0h      	;
 MOV TL0, #0h           	;
 MOV TMOD, #07h         	;C/T=1, Mod 3, Timer 0
 MOV TCON, #10h         	;zamanlayıcıyı başlat
 MOV IE, #82h             	;Kesmeleri aktifle
 CLR F0                  	;F= bayrağını temizle
 RET	        		;
 
 Hata:       JMP HataIsleme
 CevIr:
 RET				;
 end

 

  7.   8051 Kesmeler

Kesme isminden de anlaşılacağı üzere , bir kesme normal program çalışmasını kesen bir mekanizmayı tanımlamaktadır.  Mikrokontrolcüler programları sıra ile işleyen cihazlardır. Bu sıra yalnızca sıçra (JMP) ve çağır (CALL) gibi komutlarla değiştirilebilmektedir.  Kesmelerde ise normal program akışı, bir kesme ile kırılmakta ve kesme programı tamamlandıktan sonra normal program akışı, tam kesmeden önceki noktadan normal akışına devam etmektedir. Bu tür bir altprograma kesme hizmet programı (Interrupt Handler) adı verilir. Bu altprogram yalnızca bir kesme olduğunda çalışır.  Kesme olmaması durumunda programa hiç bir katkısı yoktur. Kesme yaratan mekanizma , "taşma (overflowing)", " ser porttan bir karakter okuma", seri porta bir karakter yazma", veya  INT0 ve INT1 uçlarına bağlı sinyallerin aktif olmasıyla gerçekleşebilir.

8051 uygun bir şekilde programlandığı zaman bu kesmelerden birisi gerçekleştiğinde, program akışının kesme hizmet programına yöneltilmesi mümkündür. Bu kesme tamamlandığında program kaldığı yerden normal akışına devam edecektir. Ana program böyle bir sıçramanın farkında bile olmayacaktır. Normal program akışının bu şekilde kesilebilmesi, belli koşulları kontrol etmek açısından son derece önemli olabilir. Eğer kesmeler olmasaydı, ana program sürekli olarak zamanlayıcının taşıp taşmadığını, seri porttan bir karakter gelip gelmediğini veya INT0 ve INT1 uçlarının değerlerinin "1" olup olmadığını sürekli olarak kontrol etmek zorunda kalacaktı. Bu durumda yazılan kod hem çok uzun ve okunması zor olacaktı, hemde işlemci zamanının önemli bir kısmı, çok nadir olarak gerçekleşen bir olayın, gerçekleşip gerçekleşmediğini kontrol etmekle harcanacaktı. Örneğin elimizde 30 kilobaytlık, pek çok altprogramdan oluşan bir kodumuz olsun. Programımızın yapması gereken işlerden birisi de, örneğin zamanlayıcı 0 her taştığında, P3.0 bacağının değerini "1" se "0", "0" sa "1" yapmak olsun. Böyle bir işlemin kodu son derece kolaydır.

JNB TF0, SONRAKI_KOMUT
CPL P3.0
CLR TF0
SONRAKI_KOMUT: ...

Zamanlayici 0 her taştığında TF0 biti "1" olacağından, yukardaki kod her taşmada P3.0 bitinin değerini değiştirecektir.  Böylece program kodu istenilen görevi yapacak şekilde yazılmış olmaktadır. Bu kod istenen görevi yapmaktadır fakat  önemli ölçüde sistem zamanı kullanmaktadır.

Yukarıdaki kısa kodun ne kadar işlemci zamanı kullandığını hesaplamaya çalışalım.  JNB komutu 2 makine çevriminde tamamlanan bir komuttur. Zamanlayıcı 0'ın taşması durumunda, CPL ve CLR komutları işlenecektir. Bu komutların her biri bir makine çevriminde tamamlanan  komutlardır. Dolayısıyla  iki makine çevrimi de bu komutların işlenmesine gidecektir.  Matemetiği biraz kolaylaştırmak için, programın geri kalan kısmının 98 makine çeviriminden oluştuğunu varsayalım.  Böyle bir durumda, zamanlayıcı 0'ın taşıp taşmadığının kontrolü için 2 makine çevrimi, programın geri kalan kısmı için 98 makine çevrimi, toplam 100 makine çevrimi zaman geçecektir.  Zamanlayıcı 0'ın 16 bit zamanlayıcı modunda (mod 0) çalıştığını düşünelim. Bu durumda zamanlayıcı 0, her  65,536 makine çevriminde bir defa taşacaktır.  Bu zaman içerisinde 655 kere JNB komutu işlenmiş olacaktır.  655 JNB komutu 1310 makine çavrimi alacaktır.  Zamanlayıcı taştığında iki makine çevrimi de CPL ve CLR komutlarının işlenmesinde kullanılacaktır.  Buna göre zamanlayıcı 0 taştığında, P3.0 bitinin değerini değiştirebilmek için toplam 1312 makine çevirimi işlemci zamanı kullanmış olduk. Bu zaman, program işlenmesi zamanında geçen zamanın yaklaşık %2 sidir. Öte yandan her döngüde zamanlayıcı 0'ın taşıp taşmadığının kontrolü, taşma olduysa P3.0 bitinin değiştirilmesi, ana program içerisinde gerçekleştirildiğinden, program kodu da okunulabilirlik açısından kötüdür.

Kesmeler bize bu tür sorunları çözme olanağı vermektedir.  Kesme kullanımında, zamanlayıcı 0'ın taşıp taşmadığını bizim kontrol etmemiz gerekmeyecektir. Bu kontrolü mikroişlemci kendisi yapacaktır.  Taşma oluştuğunda, kontrolcü kesme hizmet programına sıçrayıp, kesme programını işleyecek ve normal program akışına geri dönecektir. Bunun için yazılması gereken kesme hizmet programı yalnızca 2 satırdır.

CPL P3.0
RETI

Öncelikle kod içerisinde "CLR TF0" komutunun kullanılmadığına dikkat ediniz.  Çünkü, 8051 zamanlayıcı 0 kesmesi için programlandığında, taşma olduğunda TF0 biti otomatik olarak mikroişlemci tarafından temizlenmektedir. 

Aynı zamanda bir altprogramdan dönüşte kullanılan normal RET komutu yerine RETI ( return from interrupt) komutu kullanıldığına dikkat ediniz. RETI komutu RET komutu ile aynı işi yapar, fakat işlemciye kesme hizmet programının sonlandığını belirtir. Her kesme hizmet programı mutlaka RETI komutu ile sonlandırılmalıdır.

 Buna göre kesme kullandığımızda, P3.0'ın değerini değiştirmek için yalnızca 3 makine çevrimi zaman kullanmamız gerekiyor. Bir makine çevrimi CPL komutu için, 2 makine çevrimi de RETI komutu için kullanılacaktır.  Bu iki komut 65,536 makine çevrim zamanı içerisinde yalnızca bir kez işleme sokulmuş olacaktır. Kesme kullanılmadığında aynı görevi yapmak için 1312 makine çevrim zamanı kullandığımız düşünülürse, kesme kullanıldığında programımız 437 kere daha verimli bir şekilde işlemci zamanını kullanmaktadır! Öte yandan program daha kolay anlaşılabilir ve okunulabilir bir duruma gelmiştir. Çünkü program içinde sürekli olarak zamanlayıcı 0'ın taşıp taşmadığını kontrol etmek zorunda değiliz.  Yapmamız gereken yalnızca kesme programını yazmak ve unutmaktır. Gerektiği durumda işlemci kesme programını devreye sokacaktır.

 Aynı fikiri seri port haberleşmesinde veri alırken  zaman zaman son derece faydalı olmaktadır.  Seri porttan bir karakter okumak için kullanılabilecek yollardan birisi, sürekli olarak RI bitini kontrol etmek ve RI biti "1" olduysa, gelen karakteri SBUF registerinden okumaktır.  Böyle bir yaklaşımda, ana program kodu büyüdükçe gelen karakterlerden birini kaçırma riski de vardır.

 Çünkü biz RI bitini kontrol ettikten hemen sonra seri karakter gelmiş olabilir RI hattını ikinci kere kontrol edinceye kadar başka bir karakter daha gelebilir ve böylece birinci karakter kaybolmuş olur. Seri port kesmesi yardımıyla bu sorunu da çözebiliyoruz. Seri porttan bir karakter okunduğunda hemen kesme programımızı devreye sokuyoruz ve gelen karakteri okuyoruz. Program içerisinde de sürekli olarak karakter geldi gelmedi kontrolü yapmaktan kurtuluyoruz.

 

Hangi Olaylar Kesme Aktifleyebilir  ve  Bu Kesmeler Nasıl İşlenir

8051'in  temel kesme kaynakları aşağıda verilmiştir. 8051 bu kesmelerden biri veya birden fazlası kesme oluşturacak şekilde programlanabilir

  Zamanlayıcı 0 taşması

  Zamanlayıcı 1 taşması

  Seri bir karakter konması veya yazılması    

  Harici kesme 0

  Harici kesme 1

 Diğer bir deyişle 8051, zamanlayıcı 0 taştığında veya seri porttan bir karakter okunduğunda veya yazıldığında uygun kesme hizmet programı çağrılacak şekilde programlanabilir.

 Tabiki farklı kesmeler oluştuğunda, işlenmesi gereken kesme hizmet programı farklı olacaktır. Bunun için mikroişlemci içerisinde kesme hizmet programı başlangıç adresleri oluşturulmuştur. Bu adresler 8051'in standart adresleridir ve oluşan kesmeye göre program akışı bu adrese dallanacaktır.

 

Kesme

Bayrak

Kesme Adresi

Dış Kesme 0

IE0

0003h

Zamanlayıcı 0

TF0

000Bh

Dış Kesme 1

IE1

0013h

Zamanlayıcı 1

TF1

001Bh

Seri Kesme

RI/TI

0023h

 Yukarıdaki tablodan da anlaşılabileceği üzere, eğer zamanlayıcı 0 kesmesi oluşabilecek şekilde 8051 konfigüre edildiyse, zamanlayıcı 0'ınher taşmasında program akışı 000Bh adresine gidecektir. Bu adreste zamanlayıcı 0 taştığında yapılacak işlem kodları bulunmalıdır.

 Kesme Oluşumunun Programlanması

8051 entegresi ilk çalışmaya başladığında, tüm kesmeler engellenmiş durumdadır (disabled).  Kesmeler engelli durumda olduğunda, örneğin zamanlayıcı 0 taşsa bile, bir kesme oluşturmayacaktır. Kesmelerin aktiflenmesi için programda 8051 kesmeleri aktif hale getirilmeli ve hangi kaynakların kesme yaratacağı belirtilmelidir.  Kesmeleri aktif hale getirmek veya engellemek için özel fonksiyon registerlerinden kesme aktifleme registeri (IE, adres A8h) kullanılır IE registerinin bit adreslenebilir bir registerdir. Aşağıdaki tabloda bu registerin her bir bitinin anlamı gösterilmiştir.

Bit

İsim

Bit Adresi

Açıklama

7

EA

AFh

Genel kesme aktifle/engelle

6

-

AEh

Tanımsız

5

-

ADh

Tanımsız

4

ES

ACh

Seri kesme aktifle

3

ET1

ABh

Zamanlayıcı 1 kesmesi aktifle

2

EX1

AAh

Dış kesme 1 aktifle

1

ET0

A9h

Zamanlayıcı 0 kesme aktifle

0

EX0

A8h

Dış kesme 0 aktifle

 Yukarıdaki tablodan da görülebileceği gibi, her bir kesme IE registerinde kendi aktifleme/engelleme bitine sahiptir.  Herhangi bir kesmeyi aktiflemek için IE registerinde o kesmeye ait bit  aktiflenmelidir. Örneğin zamanlayıcı  1 kesmesini aktiflemek için ya,

 MOV IE,#08h  veya   SETB ET1

 komutunu vermek gereklidir.  Yukarıdaki komutlardan her ikiside IE registerinin 3 nolu bitini, yani zamanlayıcı 1 kesmesini aktiflemektedir. Bu kesme aktiflendiğinde, ne zaman TF1 biti "1" olsa 8051 001Bh adresine gidip orada bulunan kesme programını işleyecektir.

 Bununla beraber, zamanlayıcı 1 kesmesinin tam anlamıyla katiflenmesi için aynı zamanda genel kesme aktifleme bitinin de (bit 7 ) "1" yapılması gereklidir.  Bu bit bütün kesmeleri aktifler veya engeller.  Başka bir deyişle bit 7 "0" olduğunda,  diğer kesme aktifleme bitleri "1" olsa bile kesme oluşmayacaktır. Bu bit "1" yapıldığında, seçilen kesmeler aktif hale gelecektir. Bu durum, zaman kritik kodlarda önemli yararlar sağlar.  Belli bir zaman içerisinde mutlaka işlenip bitirilmesi gereken bir kod varsa ve bu kodun kesmeler tarafından kesilmesi istenmiyorsa, bu kodun başlangıcında tüm kesmelerin engellenmesi yerinde olacaktır.

 Özetlemek gerekirse, örnek olarak zamanlayıcı 1 kesmesini aktif hale getirmek için gereken kod yalnızca iki satırdır.  Önce zamanlayıcı 1 kesme aktifleme biti "1" yapılır. Daha sonra genel kesme aktifleme biti "1" yapılır.

SETB ET1
SETB EA

Bu iki satırla, zamanlayıcı 1 kesmesi aktif hale gelmiş demektir. Bundan sonra ne zaman zamanlayıcı 1 taşması oluşsa program 001Bh adresindeki kesme programını çalıştıracaktır.

8051'in kesme oluşumunu kontrol etmesi

8051 otomatik olarak her bir komuttan sonra bir kesme oluşup oluşmadığını kontrol eder.  Kesme koşullarını konrol ederken, hangi kesmenin oluştuğunu belli bir sırada kontrol eder.  Bu konrol sırası aşağıdaki gibidir. 

   Dış kesme 0

   Zamanlayıcı 0 kesmesi

   Dış kesme 1

   Zamanlayıcı 1 kesmesi

   Seri port kesmesi

Buna göre örneğin, seri port kesmesi ve dış kesme 0 aynu anlı olarak oluşmuşsa, önce dış kesme 0 programı işlenecektir. Dış kesme 0 programı tamamlandıktan sonra da seri kesme programı  tamamlanacaktır.

Kesme Öncelikleri 

8051 kesme önceliği için yalnız iki seviye tanımlamaktadır; düşük ve yüksek kesme önceliği. Kesme önceliklerini kullanarak aynı zamanlı oluşan kesmelerden hangisinin daha önce işleme sokulacağını belirlemek mümkündür. 

Bit

İsim

Bit Adresi

Açıklama

7

-

-

Tanımsız

6

-

-

Tanımsız

5

-

-

Tanımsız

4

PS

BCh

Seri port önceliği

3

PT1

BBh

Zamanlayıcı 1 önceliği

2

PX1

Bah

Dış kesme 1 önceliği

1

PT0

B9h

Zamanlayıcı 0 önceliği

0

PX0

B8h

Dış kesme 0 önceliği

  Örneğin, zamanlayıcı 1 her taştığında, zamanlayıcı 1 kesmesi oluşacaktır. şekilde ve seri port üzerinden bir karakter geldiğinde seri port kesmesi aktiflenecek şekilde 2 kesme kullandığımızı varsayalım.  Programınızda, seri porttan bir karakter geldiğinde bunu okumak, zamanlama kesmesinden daha önemli olabilir. Bu durumda eğer seri kesme geldiğinde, zamanlayıcı 1 kesmesi çalışır durumdaysa, seri port kesmesinin zamanlayıcı 1 kesmesini durdurmasını ve öncelikle seri port kesmesi işlemini tamamlamasını isteyeceksiniz.  Seri port kesmesi tamamlandıktan sonra kontrol tekrar zamanlayıcı 1 kesmesine geçecektir. Bu amaçla yapmanız gereken sadece, seri port kesmesine yüksek öncelik, zamanlayıcı 1 kesmesine düşük öncelik vermek olacaktır. Kesme önceliği kontrolü, kesme önceliği (Interrupt Priority, IP) özel fonksiyon registeri (adres B8h) kullanılarak yapılır. Kesme önceliği kontrol registeri  bit adreslenebilir bir registerdir ve aşağıdaki bitlerden oluşmuştur.

Kesme öncelikleri ile ilgili aşağıdaki kurallar geçerlidir.Yüksek öncelikli bir kesme, başka yüksek öncelikli bir kesme tarafından kesilemez. Yüksek öncelikli bir kesme düşük öncelikli bir kesme akışını keser. Düşük öncelikli bir kesmenin çalışabilmesi için yüksek öncelikli bütün kesmelerin çalışıp tamamlanmış olması gerekir.

Eğer iki kesme aynı zamanlı oluşmuşsa önce yüksek öncelikli kesme çalışacaktır. Eğer yüksek öncelikli iki kesme aynı anlı oluşmuşsa, 8051 kontrol sırasında daha önce sırada olan kesme önce işleme sokulacaktır.

Bir kesme oluştuğunda 8051 entegrenin yaptığı işlemler

Bir kesme oluştuğunda 8051 otomatik olarak aşağıdaki işlemleri gerçekleştirir.  Program sayıcısı yığına yazılır, önce program sayıcısının düşük baytı daha sonra program sayıcısının yüksek baytı yığına yazılır. Aynı öncelikli ve düşük öncelikli diğer kesmeler bloke edilir.

Zamanlayıcı kesmesi ve dış kesmelerde, kesmeye karşılık gelen kesme bayrağı temizlenir. Program çalışması kesme vektör adresine geçirilir.Kesme programı çalıştırılır.

 Üçüncü adıma tekrar dikkat edelim.  Eğer işlenen kesme zamanlayıcı kesmesi veya dış kesmelerden biriyse, bu kesmeye karşılık gelen kesme bayrağı otomatik olarak temizlenmektedir.  Bu nedenle program içerisinde bu bayrakları temizlemeye gerek yoktur.

Bir Kesme Sonunda 8051 entegrenin yaptığı işler

Bir kesme programı, RETI komutu ile sonlandırılır. RETI komutuna rastlandığında 8051 otomatik olarak aşağıdaki iki işlem yapılır. Yığına yazılan program sayıcısı değeri yığından geri alınır. Kesme statüsü kesmeden önceki durumuna getirilir.

Seri Port Kesmeleri

Seri port kesmeleri diğer kesmelerden bazı farklılıklar gösterir. Bunun sebebi seri port kesmesinin iki farklı kesme bayrağına (RI ve TI) sahip olmasıdır. Eğer bu bayraklardan birisi aktif olursa seri port kesmesi aktiflenmiş olacaktır.   Daha önceki tartışmalardan da hatırlanabileceği gibi seri porttan bir karakter okunduğunda RI kesmesi, seri porta bir karakter yazıldığında ise TI kesmesi aktiflenecektir.  

 Buna göre eğer bir seri port kesmesi oluşmuşsa, ya bir karakter okunmuştur, yada bir karakter yollanmıştır.  Dolayısıyla yazılacak kesme programı bu iki durumdan hangisinin gerçekleştiğini anlamak ve ona göre gerekli işlemleri yapmak durumunda kalacaktır.   Aynı zamanda 8051 RI ve TI bayraklarını otomatik olarak temizlemediği için , yazılan kod bu bayrakları kendisi temizlemek durumundadır. Aşağıda basit bir seri kesme programı gösterilmektedir.

SERI_KESME :

JNB RI,CHECK_TI            ; RI "0"  ise TI_KONTROL

MOV A,SBUF                ; RI = 1, karekteri oku                                                     

CLR RI                         ; RI bitini temizle

CHECK_TI:  

JNB TI, KESME_SONU    ; TI "0" ise  KESME_SONU                                 

CLR TI                         ;TI bitini temizle                                                             

MOV SBUF,#�A�            ;Seri porta "A" karakteri yolla           

KESME_SONU: RETI                                                                                                              

 Yukarıdaki kodda da görülebileceği gibi,  program  iki seri port kesme bayrağını kontrol etmektedir.  Eğer her iki bayrakta aktif durumdaysa, kodun iki bölümü de çalıştırılacaktır.  Dikkat edilmesi gereken diğer bir nokta da her iki bölümün sonunda da  ilgili kesme bayrağı temizlenmektedir. Eğer kesme bayrağını temizlemeyi unutursanız, kesme tekrar  tekrar  sonunda kesme bayrağı temizleninceye kadar çalışacaktır. Bu nedenle seri kesme programının sonunda, kesme yaratan bayrağı temizlemek son derece önemlidir.

 Kesmelerde Registerlerin Korunması

Kesmelerle ilgili unutulmaması gereken çok önemli bir kural vardır.  Kesme programı sonucunda, mikroişlemci  tamamen kesme başlamadan önceki duruma gelmelidir.  Çünkü kesme mentalitesi, ana programın hiç haberi olmayan bir program parçasının kendiliğinden ve gelişigüzel bir zamanda devreye girmesi demektir.  Fakat şimdi aşağıdaki kodu dikkate alalım.

CLR C               ; Elde bayrağını temizle
MOV A,#25h    ;  Akümülatöre 25h değeri yükle
ADDC A,#10h  ;  10h değerini elde ile birlikte akümülatöre ekle

 Yukarıdaki kod tamamlandığı zaman akümülatörde 35h değeri bulunacaktır.  Fakat MOV komutundan hemen sonra bir kesme oluştuğunu varsayalım.  Bu kesme programı, elde bayrağını "1" yapıyor ve akümülatöre 40h değeri yüklüyor olsun.  Kesme programı bittiğinde, program akışı tekrar ana programa dönecek ve ADDC A, #10h komutu ile program çalışmaya devam edecektir. Kesme programı içerisinde elde bayrağı "1" yapıldığı ve akümülatöre 40h değeri yüklendiği için toplama işlemi sonucunda akümülatörde 51h değeri kalacaktır.  Bunun ana program için anlamı açıktır. Ana programda 25h ve 10h değerleri toplandığında elimizde kalan sonuç 51h olacaktır ?  Böyle bir sonuç son derece anlamsız olduğundan kesme programları ile fazla çalışmamış bir programcı işlemcinin bozulduğunu düşünecektir.

 Aslında ortaya çıkan olay, kesme programının, kullandığı registerleri koruma altına almamış olmasıdır. Tekrar belirtirsek: Bir kesme programı işlemciyi, kesme başlamadan önceki durumda bırakmalıdır. Bu kurala göre, eğer kullandığınız kesme programı, akümülatörü kullanıyorsa, akümülatörün değeri kesme başında ve sonunda aynı olmalıdır. Bu olay genelde PUSH ve POP komutları kullanılarak yapılır. Aşağıdaki kod bu kullanıma bir örnektir.

 PUSH ACC
PUSH PSW
MOV A,#0FFh
ADD A,#02h
POP PSW
POP ACC

Yukaridaki kesme programı temel olarak MOV ve ADD komutlarından oluşmuştur.  Bu komutlardan her ikisi de akümülatörün içeriğini değiştirmektedir. Öte yandan ADD komutu elde bayrağının durumunu değiştirmektedir.  Bir kesme programı, registerlerin kesme başındaki durumlarını korumak zorunda olduğuna göre, kesme programı başında PUSH komutlarıyla korunacak registerler yığına yazılır. Bu registerler yığına yazıldıktan sonra kesme programı içerisinde, bu registerleri istendiği gibi değiştirme özgürlüğü yakalanmış olur. Kesme programı tamamlandığı zaman, registerlerin orjinal değerleri yığından geri kalınır ve kesme programı RETI komutu ile sonlandırılır. Dolayısıyla bir kesme oluştuğunda, ana program kesme oluşup oluşmadığını hiç bir şekilde bilmeyecektir.

 Genelde kesme programları aşağıdaki registerleri korumaya almalıdır. 

      PSW

      DPTR (DPH/DPL)

      ACC

      B

      R0-R7 registerleri

Bu registerlerden PSW çeşitli 8051 komutları ile değişebilen bitlere sahip bir registerdir. Dolayııyla, yaptığınız işten hiç şüphesiz emin olmadığınız durumlarda, PSW registeri korunması gereken bir registerdir.

 Öte yandan pek çok assembler,

PUSH R0

gibi bir komuta izin vermez. Çünkü böyle bir  komut seçilen register banka bağlı olarak 00h, 08h, 10h, veya 18h iç hafıza elemanına karşılık gelecektir. Dolayısıyla R0, PUSH ve POP komutlarının kullanabileceği geçerli bir hafıza adresini göstermemektedir. Dolayısıyla, kesme programınızın içerisinde bir "R" registeri kullanıyorsanız, doğrusu direkt olarak register adresini PUSH etmektir.  Örneğin, PUSH R0 yerine, kullanılan register bankına bağlı olarak,

PUSH 0H, PUSH  8H, PUSH  10H veya PUSH 18H  komutlarından birini kullanmak gerekir

Kesmelerle İlgili Çok Karşılaşılan Problemler

Kesmeler 8051 programcısının kullanabileceği güçlü programlama kavramlarıdır.  Fakat yanlış kullanılmaları durumunda, kesmelerden kaynaklanan hataların tespit edilmesi son derece zordur.  Eğer programlarınızda kesme kullanıyorsanız, ve programlarınız zaman zaman hiç beklenmedik hatalara neden oluyorsa, aşağıdaki önemli kuralları dikkatlice incelemeniz faydalı olacaktır.

 Register Koruması:  Kesme programlarını da, önemli registerlerin mutlaka korunduğundan emin olun. Eğer ana programınızda da kullanılan registerlerden birini korumayı unutursanız, çok garip sonuçlarla karşılaşabilirsiniz.  Eğer register değerlerinin beklenmedik bir şekilde değişimini gözlüyorsanız veya bazı işlemler beklenmedik sonuçlar üretiyorsa, büyük olasılıkla, kesme programında, korumayı unuttuğunuz bir registerden dolayıdır.

 Korunan değerlerin tekrar yerine konulmasının unutulması: Diğer önemli problemlerden birisi, registerleri yığına sakladıktan sonra, kesme programı bitiminde, register değerlerinin yığından geri alınmasının unutulmasıdır.  Örneğin, kesme programı başlangıcında, ACC, B ve PSW registerlerini yığına sakladıysanız, kesme bitiminden hemen önce bu değerleri yığından geri almalısınız. Değerleri yığından geri alırken, en son sakladığınız değeri en önce almanız gerektiğini unutmayın. Mutlaka yığına yazılan sayıda registeri, geri almalısınız. Yığına korunan register sayısından fazla veya az registerin geri alınması RETI komutunun tamamen ilgisiz bir adrese dönüşüne yol açar. Böyle bir durumda, çoğunlukla program kilitlenir.

RETI komutu yerine RET komutu kullanılması:

 Çok karşılaşılana hatalardan birisi de kesme programı dönüşünde, RETI komutu yerine yanlışlıkla RET komutunun kullanılmasıdır.  RETI komutu yerine RET komutu kullanıldığında, ilk başta programınız normal çalışıyor gibi görünebilir. İlk kesme geldiğinde, kesme programı doğru çalışacaktır. Fakat daha sonraki kesmelerde kesme hizmet programı devreye girmeyecektir.

Dr. Cengiz Birlikseven
Alıntı:
www.ume.tubitak.gov.tr

1
2
3
4
5
6
7