Makaleler Gecikme Kodları Hazırlama ve Gecikme Rutini Hazırlayıcı
Gecikme Kodları Hazırlama ve Gecikme Rutini Hazırlayıcı Yazan: Mustafa Tufaner, Düzenleyen: Canol Gökel - 31 Ocak 2007 Giriş Merhaba, bu makalemizde PIC mikrodenetleyicilerinde Assembly kodu kullanarak nasıl istediğimiz sürelik gecikmeler sağlayan altprogramlar oluşturabileceğimizi görecek ve Gecikme Rutini Hazırlayıcı yazılımı hakkında birkaç ipucu vereceğiz. Öncelikle gecikme kavramının ne olduğuna ve mikrodenetleyicimizde nasıl algılanacağına bakacağız. Gecikme Kavramı Mikrodenetleyici, hızından ötürü insanların algılayabileceğinden ya da daha geniş bir ifadeyle ortamın tepki verebileceğinden daha kısa sürede bir işlemini bitirir. Mikrodenetleyicinizin kendisinden daha yavaş başka birimlerle bağlantısı varsa, bağlı olduğu diğer birimlerin tepki süresi kadar beklemesi, yeni işleme geçmemesi ya da mikrodenetleyicinin her koşulda eşit sürede bir döngüyü tamamlaması gerekebilir. Bu durumlarda programımızın uygun satırları arasına gecikme yerleştirebiliriz ama mikrodenetleyiciye nasıl "biraz bekle" diyeceğiz? Çok çalışkan olan mikrodenetleyicimiz uyku hali dışındayken sürekli işlem yapacaktır. Bu özelliğini bildiğimiz için mikrodenetleyiciye ilgisiz işlemler yaptırarak onun boşa vakit harcamasını ve istediğimiz bir komuttan diğer komuta geçişte belirli bir süre gecikme olmasını sağlayabiliriz. Bu boş işlemler ne olabilir? Mikrodenetleyicinin, hazırlamak istediğimiz uygulamanın herhangi bir değişkenini veya mikrodenetleyicinin kendisinin giriş veya çıkışını değiştirmeyecek bir işlem yapmasını boş işlem olarak adlandırabiliriz ve bu işlemleri yaparken harcadığı zamanı göz önünde bulundurarak gecikme elde edebiliriz. Mikrodenetleyicinin bir işlemi yapma süresi o mikrodenetleyicinin mimarisi ve çalışma frekansıyla bağlantılıdır. Temel olarak PIC mikrodenetleyicisi clock girişinden elde edilen her 4 periyotta 1 işlem yapar. Dolayısıyla mikrodenetleyicinin bir işlem yapması için geçen süre 4T yani 4/f clock olur ve bu, bir komut döngüsü olarak adlandırılır.
t 0 T 2T 3T 4T 5T 1 komut işlenmesi için gereken süre 4 döngü Mikrodenetleyicinin mimarisinden dolayı her işlem aynı sürede yapılamayabilir. Komutların uygulanması için geçen süre, kullandığınız mikrodenetleyicinin datasheet'inde mevcut olacaktır. PIC mikrodenetleyicileri için genel olarak şu tanımı yapmamızda bir sakınca yoktur: Program akışını dallandırmayan (yönlendirmeyen) her komut, 1 komut döngüsü süresinde; program akışını dallandıran her komut, 2 komut döngüsü süresinde işlenir. Bu ifadeyle çelişebilecek gibi dursa da çelişmeyen bir durum vardır. Eğer siz PCL yazmacının içeriğini herhangi bir komutla değiştirirseniz program akışınız bozulacak, program başka bir komuttan devam edecektir. Fakat bu PCL yazmacının bir özelliği olduğu için PCL yazmacına uyguladığınız komut diğer yazmaçlarda ne kadar süre harcıyorsa PCL ile işlem yaparken de o kadar süre harcayacaktır. Bu bilgiler doğrultusunda birkaç komutun işlenme süresini inceleyelim. NOP MOVLW MOVWF ADDLW DECF GOTO : 1 komut döngüsü : 1 komut döngüsü : 1 komut döngüsü : 1 komut döngüsü : 1 komut döngüsü : 2 komut döngüsü (program akışını dallandırır) BTFSS : Eğer kontrol ettiğiniz bit 0 ise program akışı dallanmayacak ama eğer kontrol ettiğiniz bit 1 ise program akışı dallanacaktır. Yani test edilen bit 0 ise 1 komut döngüsü, test edilen bit 1 ise 2 komut döngüsü DECFSZ : Eğer sonuç 0 dan farklı ise (dallanma yok) 1 komut döngüsü, eğer sonuç 0 ise (dallanma var) 2 komut döngüsü Görüldüğü gibi önceden belirtilen komut işlenme süresi tanımı ile bu bilgiler örtüşmektedir. Böylece hangi komutun kaç komut döngüsünde işlendiğini hafızamızda tutabiliriz. Tekrar boş işlemlere dönelim. Yöntem olarak bu boş işlemleri farklı farklı seçebiliriz. Ben belli bir sayıdan geriye doğru sayma yöntemini seçip geri kalan kısımda kodları buna göre hazırlayacağım.
A işlemini yaptıktan sonra B işlemini yapmadan belli bir süre beklememiz gerektiğini düşünelim. A işlemini yap MOVLW D x MOVWF SAYICI DECFSZ GOTO $-1 B işlemini yap SAYICI ; x bir sayı ; SAYICI, kullanılmayan herhangi bir yazmaç İpucu: $ komutu şu anda işlenen satırı belirtirken -1 heksadesimal olarak 1 satır öncesine git anlamını taşımaktadır. Eğer GOTO $+12 olsa idi heksadesimal 12 yani desimal olarak 18 satır sonrasına git anlamını taşıyacaktı. Arada uygulamamızla ilgili olmayan kısma dikkat etmişsinizdir. Bu kısım bizim gecikme satırlarımız olacak. Şimdi x'e bağlı olarak ne kadar gecikme elde edebileceğimize bakalım. x değerini, SAYICI yazmacına (Adının SAYICI olmasına gerek yoktur, herhangi bir isme ya da doğrudan herhangi bir ram konumuna sahip olması yeterlidir ancak dikkat edilmelidir ki bu yazmacı değiştirmemiz bu değişkeni kullanan uygulamamızın diğer kısımlarında probleme sebep olmasın.) atamak için iki işlem yapıyoruz. MOVLW d x MOVWF SAYICI ; 1 komut döngüsü ; 1 komut döngüsü (şu ana kadar 2 komut döngüsü süre ; harcadık) Ardından SAYICI yazmacının içindeki değeri 1 azaltıyoruz Eğer sonuç 0 oluyorsa B işlemine geçiyoruz, eğer sonuç 0 dan farklı ise GOTO ile tekrar azaltma işlemine dönüyoruz. Bu satırların kaç defa işleneceğini x sayısı belirleyecektir çünkü x, 0 olana kadar bu satırlar tekrarlanacaktır. DECFSZ SAYICI ; Bu işlemin sonucu x-1 kere 0 olmayacak, 1 kere ; 0 olacak. Dolayısıyla bu komutta toplam x-1+2 ; komut döngü süresi harcanacak. GOTO $-1 ; DECFSZ komutu x-1 kere sıfırdan farklı olacağı için MOVLW D x MOVWF SAYICI ; bu komut x-1 kere işlenecek yani toplamda 2 x 1 ; komut döngüsü kadar süre bu komutta harcanacak. ; 1 komut döngüsü ; 1 komut döngüsü DECFSZ SAYICI ; x-1+2 komut döngüsü GOTO $-1 ; 2 x 1 komut döngüsü Yani A ile B işlemleri arasında toplam 3 x 1 4 komut döngüsü kadar süre harcanacak. Örnek olarak clock giriş sinyalimizin frekansı 4MHz olsun ve de 16 mikrosaniye gecikmeye ihtiyaç duyduğumuzu farz edelim. Giriş frekansı 4MHz ise 1 komut saykılı = 4/giriş frekansı = 1 mikrosaniye toplam gecikme=16 mikrosaniye= 3 x 1 4 1 mikrosaniye
buradan x=4 olur MOVLW d 4 MOVWF SAYICI DECFSZ SAYICI GOTO $-1 Yani bu kodlar 4MHz saat sinyali için 16 mikrosaniye gecikme sağlayacaktır Gecikme kalıbını program içerisinde farklı yerlerde birden fazla kullanacak olursak bu kalıbı altprogram halinde yazmamız daha mantıklı olacaktır. GECIKME MOVLW d x ; 1 komut döngüsü MOVWF SAYICI ; 1 komut döngüsü DECFSZ SAYICI ; x-1+2 komut döngüsü GOTO $-1 ; 2(x-1) komut döngüsü RETURN ; 2 komut döngüsü A işlemini yap CALL GECIKME ; 2 komut döngüsü B işlemini yap Gördüğünüz gibi program gecikme kalıbına girerken ve de gecikmeden çıkarken 2'şer komut döngüsü kadar zaman harcıyor. Bu durumda yeni formülümüz: toplam gecikme= 3 x 1 8 komut döngüsü şeklinde olur. Elde ettiğimiz formülden de görebileceğiniz gibi 4MHz saat frekansı için bu gecikme kalıbı bize maksimum gecikmeyi x=255 olduğunda 770 mikrosaniye olarak verecektir. Peki ya daha fazla gecikmeye ihtiyacımız olursa? Bu durumda da ikinci bir sayaç yazmacı kullanarak iç içe geçmiş bir döngü oluşturacağız. MOVLW D y MOVWF SAYICI1 KALIP MOVLW D x MOVWF SAYICI2 DECFSZ SAYICI2 GOTO $-2 DECFSZ SAYICI1 GOTO KALIP Bu döngüyü düzenlersek: GECIKME MOVLW D y MOVWF SAYICI1 ; 1 komut döngüsü ; 1 komut döngüsü
gecikme kalıbı ; (y) gecikme kalıbı = (y) (3(x-1) + 4) komut ; döngüsü DECFSZ SAYICI1 ; y-1+2 komut döngüsü GOTO $-2 ; 2 y 1 komut döngüsü SAYICI1 yazmacı 0'a ulaşana kadar y kere önceden belirttiğimiz gecikme kalıbını tekrarlayacak. Gecikme kalıbını 1 kere tamamlaması 3 x 1 4 komut döngüsü kadar sürdüğüne göre demek ki toplamda y 3 x 1 4 komut döngüsü kadar gecikme kalıbında vakit harcayacak. DECFSZ komutu y-1 defa 0 olmayacak, 1 defa 0 olacak. Bu durumda da DECFSZ SAYICI1 komutunda toplamda y-1+2 komut döngüsü süre harcanacak. y-1 defa DECFSZ komutu 0 olmayınca toplamda da y-1 defa GOTO komutu işlenecek. GOTO komutunda da 2 y 1 kadar süre harcanacak. Yani toplamda toplam gecikme= 3 y 1 y 3 x 1 4 4 komut döngüsü gibi bir formülü elde ederiz. Eğer gecikmeyi altprogram olarak hazırlarsak, 4 komut döngüsü kadar ekleme yapmalıyız. Bu durumda formülümüz şu şekilde olur: toplam gecikme= 3 y 1 y 3 x 1 4 8 komut döngüsü Gördüğünüz gibi 4 MHz saat frekansı için hazırladığımız 2 döngülü kalıp ile maksimum 196.100 mikrosaniye = 196,1 milisaniye gecikme elde edebiliyoruz. MOVLW D y MOVWF SAYICI1 KALIP MOVLW D x MOVWF SAYICI2 DECFSZ SAYICI2 GOTO $-2 DECFSZ SAYICI1 GOTO KALIP İpucu: GOTO KALIP demek yerine KALIP etiketini kaldırıp GOTO $-5 de diyebilirdik.
Eğer daha fazla gecikmeye ihtiyaç duyarsanız bu sefer de yukarıdaki kodları kalıp olarak kullanıp tekrar iç içe döngü kurabilirsiniz. İpucu: Hazırlanan üçlü döngünün gecikme formülünü ikili döngüde yaptığımız şekilde hazırlayabilirsiniz. MOVLW D z MOVWF SAYICI3 KALIP2 MOVLW D y MOVWF SAYICI1 MOVLW D x MOVWF SAYICI2 DECFSZ SAYICI2 GOTO $-2 DECFSZ SAYICI1 GOTO $-5 DECFSZ SAYICI3 GOTO KALIP2
Gecikme Rutini Hazırlayıcı s2.14 Makalenin bağlantılar kısmındaki bağlantıdan indirebileceğiniz gecikme programının yaptığı tek iş yukarıda elde ettiğimiz formüllere göre sizin istediğiniz gecikme süresini sağlayacak değişken ve komutları bulmak ve istediğiniz gecikme süresi mevcut döngülerle elde edilemiyorsa istediğinize en yakın gecikme süresini verecek şekilde altprogramı hazırlamaktır. Birazdan mantık olarak oldukça basit olan bu programı nasıl kullanacağınızı anlatmaya ve daha verimli kullanabilmek için birkaç ipucu göstermeye çalışacağım. Aslında bu ipuçları programın marifetleri değil tamamen sizin yazacağınız kodlarla ilişkili. Programda hazırlanan gecikme kodları size, gecikmenin bir altprogram olduğu kabul edilerek verilmiştir. Yani size verilen kodlara bir etiket verip ana programda herhangi bir yerde CALL komutuyla bu altprogramı çağırabilirsiniz. Programdaki tüm hesaplamalarda CALL komutunun gecikmesi de dahil edilmiştir. PIC özellikleri bölümünde en sık kullanılan 4 PIC mikrodenetleyicisinin bazı donanımsal özellikleriyle birlikte bacak şemaları verilmiştir. Program eğer istediğinizden farklı gecikme süresi elde ediyorsa ya da normalden farklı bir durum söz konusuysa açıklama kısmında gerekli uyarıları okuyunuz. Bazı durumlarda size yapılan açıklamalardan yola çıkarak sorunları nasıl aşabileceğinize dair birkaç ipucu: Bulunan sonuç istediğiniz gecikme süresinden x kadar eksik/fazla'dır. Bu uyarı genelde büyük gecikme süreleri istediğiniz zaman ortaya çıkar (Örneğin 50 saniye için 5.25 milisaniye fazla gecikme rutini hazırlanıyor.). Bu durumun üstesinden gelebilmek için istediğiniz sürenin belirli bir oranını alarak o süreyi isteyin. Yine 50 saniyeyi örnek verecek olursak biraz önce de dediğimiz gibi 50 saniyede 5.25 milisaniyelik bir hata söz konusu ama 25 saniyelik bir alt program hazırlattığınız zaman bu hata 1 mikrosaniye'ye düşüyor. Ana programınızda 50 saniyeye ihtiyaç duyduğunuz yerlerde 25 saniyeye göre hazırladığınız gecikme programını iki defa ard arda CALL komutu ile çağırırsanız 50 saniyelik gecikmeyi 2 mikrosaniye hata ile elde etmiş olursunuz. Bir başka deyişle ana programda sadece 1 satır daha fazla kullanarak daha hassas sonuç elde etmiş olursunuz. Bu yöntem programın bir sonraki versiyonunda otomatik hale getirilecektir. Eğer bu hata küçük değerler içinse önümüzde iki olasılık var. İlki hazırlanan gecikme rutininin istenilenden daha uzun olması. Bu durumda istediğiniz gecikme süresini azaltarak yeni bir gecikme rutini hazırlatın ve GOTO $+1 (2 komut döngüsü kadar gecikme yapar) ve NOP (1 komut döngüsü kadar gecikme yapar) komutlarını RETURN komutundan hemen önce kullanarak sürenizi tamamlayın. Eğer istediğinizden az bir gecikme elde etmişseniz yine GOTO ve NOP kullanarak bu sorunu çözebilirsiniz. Bu son
iki sorun küçük ve orta değerler için az rastlanmaktadır ancak yine de programın bir sonraki versiyonunda farklı kalıplar kullanılarak düzeltilecektir. Yan tarafta verilen kodları doğrudan program akışına yazmanız gerekmektedir. Eğer tek döngülü kalıbın hesaplayabileceğinden daha küçük değerlere ihtiyacınız varsa bu kodları doğrudan ana programa yazmalısınız. Bir uygulamada farklı gecikme sürelerine ihtiyaç duyabilirsiniz. Her gecikme süresi için ayrı kod yazmak programınızı şişirecektir. Bu yüzden ihtiyacınız olan gecikme sürelerinin ortak bölenine göre gecikme hazırlayıp birkaç defa CALL komutuyla çağırmak ya da ortak bölenleri yoksa GECIKME MOVWF SAYICI1 X komut döngüsü gecikme DECFSZ SAYICI1 GOTO $-2 RETURN gibi bir gecikme alt programı hazırlayıp ana programda verdiğiniz SAYICI1 değerine göre farklı gecikmeler elde eden bir altprogram kullanabilirsiniz. x gecikmesinin değerinin ne olması gerektiğine formülünüzden karar verip ona göre bir gecikme hazırlatabilirsiniz. toplam gecikme=sayici1 x 3 SAYICI1 1 7 Umarım bu makale ve program gecikme hazırlama ve hazırlanan gecikmenin süresinin hesaplanmasında size yardımcı olmuştur. Soru ve önerileriniz için hunrobotx@yahoo.com adresine eposta atabilirsiniz. Bağlantılar Gecikme Rutini Hazırlayıcı: http://robot.ee.hacettepe.edu.tr/dosyalar/gecikme_rutini_hazirlayici_s2.14.zip http://robot.ee.hacettepe.edu.tr/