avatar_ete

PIC Basic Ders-06 (Kesme (INTERRUPT) Kullanımı)

Başlatan ete, 28 Ağustos 2011, 16:13:09

ete

Pullup direnci ile kesmenin ne şekilde olacağının bir bağlantısı yok. Olamazda.
Örnekle irdeleyelim.
Pullup lar aktif diyelim. Giriş pinine bir başka direnç bağlı değil ise veya zorunlu olarak bir tarafa çekilmiyor ise pin HIGH da bekliyor demektir.
Aynı pin için Yükselen kenarda kesme ayarladık diyelim. Pin zaten yükselen kenarda ancak kesme oluşması için pinin konum değiştirmesi gerekir. Bunu denemedim açıkçası sadece tahminde bulunuyorum.  Bu nedenle pin önce LOW olur ve ardından serbest bırakılırsa yeniden yükselen kenara ulaşacağı için kesme o anda oluşur.

Şimdi Pullup aktif ve kesmeyi düşen kenarda ayarladık. Pin High da bekliyor. LOW a düşer düşmez kesme oluşacaktır.
Bu açıklamalara bakınca Pullup lı olan pine düşen kenar kesmesi yakıştığını hemen anlarsın. Pulldown da bekleyen pine de yükselen kenar kesmesi yakışıyor öyle değilmi.

Ete

Hattuşa

Slm ete hocam
Interrupt ile ilgili bir sorum olacakti. Kod eklemedim, zira henuz yazmadim, soruma sormadan once programimin akisi  soyle olacak ve istedigimin olabilirligi varmidir.
Timer0 i kesme icerisinde kurdum ve 5ms surede sayaci degiskenimi sifirlayarak istedigim peryodu yakaladim, ana dongum yaklasik 30 ms ve yapmak istedigim program aNa dongude kostururken sayac degerini sifirladigim her 5ms de ana dongunun en basina programi getirmek, sozun ozu her 5ms de kod ana dongunun neresinde olursa olsun basa donmesini saglamak istiyorum. Sizce bunu yapabilirmiyiz
Not:(yaziyi tabletten yazdigim icin imla kurallarina uyamadim, kusuruma bakmayin)

ete

Aslında bu iş için direk komut var. Kesme den çıkarken,
RESUME
ENABLE
Şeklinde değil,
RESUME BASLA
ENABLE
Şeklinde çıkmak gerekiyor. Ancak bu işlem pek çok işlemcide stack taşması sorunu yaratıyor.
DEFINE NO_CLEAR_STKPTR 1     komutu bu sorunun çözümünde yardımcı olabilir dene istersen.
Stack sorunu meselesinde ben genellikle bir işaretçi kullanarak bu işi yaparım.
Kesme içinde bir bit değişkenini set ederim. (Kes=1) sonra ana döngü içinde bir veya bir kaç yere,
IF KES=1 THEN
   KES=0
   GOTO BASLA
ENDIF
Şeklinde komut dizisi eklerim. Böylece arada kesmeye gidilince kes=1 olur ve geri dönüşte bu komutlardan birine yakalanınca program başa döner.
Ete

Hattuşa

yanıtınız için tşk ederim ete hocam bahsettiğiniz resume başla etiketini denemek istiyorum, eğer bir sonuç elde edersem bildiririm.

efehurkan

Merhabalar Hocam (Kesme (INTERRUPT) Kullanımı) yardımcı olabilirmisiniz?

Butonun normal konumu sürekli kapalı konumda , buton açıldığında 40sn gecikme başlayacak, 40sn sonunda led yanacak, eğer buton 40sn dolmadan kapanırsa led yanmayacak , yardımlarınızı rica ederim.

@ __config _INTRC_OSC_NOCLKOUT & _WDT_OFF & _MCLRE_OFF & _LVP_OFF & _CP_OFF & _BODEN_OFF & _PWRTE_ON

DEFINE OSC 4

CMCON=7
TRISA=%11111111
TRISB=%00000000
PORTA=0
PORTB=0

SURE VAR WORD[8]56
AKTIF VAR byte
I     VAR BYTE
pause 500
OPTION_REG=%00000001
INTCON=%10100000
ON INTERRUPT GOTO KESME
TMR0=0   
BASLA:
                     
IF PORTA.0=0  THEN       
PORTB.0=1
SURE[0]=3000                                             
'WHILE PORTA.0=0:WEND
ENDIF

GOTO BASLA

DISABLE
KESME:
      for I=0 to 0
        IF PORTB.0[I]=1 THEN
          SURE[I]=SURE[I]-1
          IF SURE[I]=0 THEN
             PORTB.0[I]=0
'             AKTIF.0[I]=0
          ENDIF
        ENDIF
        NEXT
        TMR0=0
        INTCON.2=0
        RESUME
        ENABLE
        END

ete

Bir şeyler karalamışsın ama sanki sağdan soldan toplanmış şeyler gibi duruyorlar. Çünki yapmayı planladığın işle programın yakından uzaktan bir alakası yok gözüküyor.
Böyle bir işi nasıl yaparım diye düşünmekle başlamalı insan işe. Nasıl Yaparım?. Temel kriter 40 sn sayacının elde edilmesidir.
Bunuda kesme ile yapalım demişsin o halde zaman kesmesi yaratacak kaynaklarımıza bakmamız gerekiyor. Bunlar TMR0 ve TMR1. Sen TMR0 kullanmışsın o nedenle TMR1 konusuna girmeyeceğim.
Şimdi bana ne lazım? 1sn lik zaman süresini elde etmem gerekiyor. Aslında 40 sn dir bu ama işlemci açısından çok büyük bir süre olduğu için en küçük birimi 1sn yi ele alacağız. TMR0 ile büyük zaman dilimleri elde etmenin tek yolu 1/256 bölme oranını kullanmaktır. Bu şekilde elde edebileceğim en büyük zaman dilimi ise 50ms olacaktır. 4 Mhz OSC frekansında TMR0 bir artması 1us lik bir sürenin geçmesini sağlar. 256 (0-255) sayarsa 256us lik bir zaman dilimi sayacaktır. Şayet ben Sayacı sıfırdan başlatırsam 256*256=65536 us yada 65,536ms lik bir süre geçer. Ancak küsüratlı olan bu değer benim işme yaramaz. Bana 1000'e tam olarak bölünebilecek bir değer gerekiyor. Zira 1sn=1000ms dir. Mesela TMR0 ile 100ms lik bir süre elde etsem ne güzel olurdu. 10 defa kesme oluşunca 1 sn geçmiş olurdu. Ama en büyük yaratılacak gecikme 65 ms olduğuna göre 50'yi tercih etsem daha uygun olacak demektir. 50 ms elde etmek için 50.000us/256=195 sayısnı bulurum.
O halde ben sayacı her seferinde 195 saydırırsam ve bölme oranınıda 1/256 alırsam sayac 195*256=49.920us lik bir süre geçiririm. Peki sayacı 195 saydırabilmek için ne yapmam lazım 256-195=61 rakamından saymayı başlatıp 256 ya ulaşmam gerekir. Süreyi 1us daha uzatmak için bunu 60 kabul ederim. Zira tam sonuç 50000 değil 49920 çıkıyor idi.
Böylece TMR0 sayacını 60 dan başlatıp kesme oluştururum. Kesmeleri sayarım 20 adet kesme bana 1 sn lik süreyi verecektir. Bu durumda her 20 kesmede bir SN sayacını bir artırırsam ve onunda 40'ı bulduğu anda ledi yakarsam sorun çözülmüş olacaktır.
Geriye diğer kriterimiz kalıyor. Buda buton 40 sn dolmadan kapanırsa!, hemen kesme iptal olacak sayaçlar sıfırlanacak ve led yanmayacak. Bunuda basit bir test ile halletmek mümkün.
Aşağıda bu anlattıklarımı içeren program bulunmaktadır. sim devresinide aynen kullanmanı öneririm böylece izleme penceresinden sayaçların nasıl saydığını görebilirsin. En güzel verdiğim dosyaları bir klasörde aç ve orada çalıştır.

Ete

efehurkan

Teşekkürler ETE Hocam, nasihatlariniz de dersleriniz kadar  çok etkili ve faydalı  :D . Butona 40sn den çok basılı tutulursa LED yanıyor, fakat butonu bıraktığımda LED in sönmesi  gerekli , oysa LED sürekli yanık kalıyor,

IF PORTA.0=1 THEN PORTB.0=0

satırını resimde gösterdiğim yere eklediğimde istediğim gibi çalışıyor, doğru mu yapıyorum acaba?

ete

Led in sönmesi gerektiğini yazmamıştın. O nedenle sönme işlemini yapmadım.
Koyduğun şeklii ile çalışır ama bence doğru değil. Zira tuşu bıraktığın zaman zaten program otomatikman while:wend döngüsünden çıkacaktır.
O halde yapılacak iş WEND satırından sonra,
PORTB.0=0
şeklinde bir komut satırını direk yazmak olacaktır.
Tekrar ediyorum. Tuş ayrık olduğu sürece program while ile wend arasında gidip gelir. Tuşu bırakınca otomatikman wend satırından sonraki satıra geçer program orayada led i söndürecek komutu yazarsan istediğin olur.

Ete

efehurkan

 ETE hocam WEND satırından sonra,"PORTB.0=0 " satırını ekledim isteğim gibi buton kapanınca LED sönüyor, dersleriniz için teşekkürler.

Hattuşa

#99
...
sorun giderildi.  ;D

muratdumlu

Arkadaşlar, bu çalışmada butona her basıldığında rakam 3 kere yansın sönsün istiyorum.. Bunu kesmelerle nasıl yapabilirim bilen varmı?
Yardımcı olursanız sevinirim..

Program Kodu;

#include <16f877a.h>
#fuses XT,NOWDT,NOPROTECT,NOBROWNOUT,NOLVP,NOPUT,NOWRT,NODEBUG,NOCPD
#use delay (clock=4000000)

#define sh_cp     pin_e0
#define ds        pin_e1
#define st_cp     pin_e2

#define artir     pin_b0

int sayi=0;

const int digit[11]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x00};

//==============================================================================
void gonder(unsigned char veri)
{
   unsigned char i;
   for(i=0x80;i>0;i>>=1)
      {
         if(i&veri)output_high(ds);
            else
               output_low(ds);
               output_high(sh_cp);
               output_low(sh_cp);
      }
}
//==============================================================================

void main()
{
   setup_adc_ports(NO_ANALOGS);
   setup_adc(ADC_OFF);
   setup_psp(PSP_DISABLED);
   setup_spi(SPI_SS_DISABLED);
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
   setup_timer_1(T1_DISABLED);
   setup_timer_2(T2_DISABLED,0,1);
   setup_comparator(NC_NC_NC_NC);
   setup_vref(FALSE);
   
   while (true){
   
   if(!input(artir)){delay_ms(30);
     
      if(sayi==9)
         sayi=0;
         else{
         sayi++;
         }
   }   
   gonder(digit[sayi]);
     
   output_high(ST_CP);
   output_low(ST_CP);
   delay_ms(170);   
   }
}

Not: İsis simülasyonu ve c kodları ektedir...

karabayram

Hocam kolay gelsin sizin derslere çalışmaya devam ediyorum.
Derslerinizdeki portb(rb4-rb7)değişiklik kesmesine çalışıyordum şimdi isis de çalışıyor fakat fiziksel olarak led sürekli yanıp sönüyor. Sanki sürekli kesmeye gidiyor neden acaba?

enginkanat


karabayram

Program ete hocanın derslerindeki programla aynı.

ete

Bende deniyorum ama öyle bir şey olmuyor.

Ete

Powered by EzPortal