kesme sorunum var ???

Başlatan oguztkn, 02 Ekim 2011, 23:10:49

oguztkn

#15
hocam sona yaklaştım ama şimdiki sorum şu:
sensörlerden biri görünce motorlar dönüyor yani yazdığım komutu yapıyor kesme olduğunda kesmeyi yapıyor ama diyelim portc7 1 oldu motor dönüyor kesme oldu onu yaptı kesme bitti ama sensör hala 1 olmasına rağmen kesmeyi yapıyor yani sensörü 1-0-1 yaparsam sensöre dönüyor bunu nasıl çözebilirim umarım anlatabildim bu nasıl bir sorun acaba :Q

Kodların son hali bunlar :
@ DEVICE pic16F877a
@ DEVICE pic16F877a,WDT_OFF
@ DEVICE pic16F877a,PWRT_ON
@ DEVICE pic16F877a,PROTECT_OFF
@ DEVICE pic16F877a,XT_OSC
Define OSC 4
'******************************************************************************
DEFINE LCD_DREG    PORTD    
DEFINE LCD_DBIT 4  
DEFINE LCD_RSREG   PORTD
DEFINE LCD_RSBIT 1  
define LCD_RWREG   PORTD
define LCD_RWBIT    2
DEFINE LCD_EREG    PORTD      
DEFINE LCD_EBIT 3
DEFINE LCD_BITS 4  
DEFINE LCD_LINES 2  
'******************************************************************************
MOD1 var PORTA.2
MOD2 var PORTA.3
MOD3 var PORTA.4
CNY1 var PORTB.4
CNY2 var PORTB.5
CNY3 var PORTB.6
CNY4 var PORTB.7
Mz var PORTC.0
KIZIL1 var PORTC.1
KIZIL2 var PORTC.2
'******************************************************************************
CMCON=7
ADCON1=7
TRISA=%111111
TRISB=%11110000
TRISC=%00000111
TRISD=%00000000
TRISE=%000
INTCON=%10001000
PORTC=0
PORTD=0
PORTE=0
'******************************************************************************
TEMP VAR BYTE
DURUM VAR byte
'******************************************************************************
clear
low PORTD.2
lcdout $FE,1
ON INTERRUPT GOTO KES
pause 250
'******************************************************************************
BASLA:
    if Mz=1 then
    goSUB ILERI_GITME
    while Mz=1
    wend
    else
    gosub DUR
    endif
    if KIZIL1=1 then
    Gosub SAGA_DONME
    while KIZIL1=1
    wend
    else
    gosub DUR
    endif
    if KIZIL2=1 then
    gosub SOLA_DONME
    while KIZIL2=1
    wend
    else
    gosub DUR
    endif     
    goto basla   
   
SOLA_DONME:
    PORTC=0
    high PORTC.4
    high PORTC.7
    Return
SAGA_DONME:
    PORTC=0
    high PORTC.5
    high PORTC.6
    Return
ILERI_GITME:
    PORTC=0
    high PORTC.4
    high PORTC.6
    Return       
GERI_GITME:
    PORTC=0
    high PORTC.5
    high PORTC.7
    Return   
DUR:
    PORTC=0
    PORTC=0
    Return

DISABLE     
KES:
   IF PORTB.7=1 then     
   PORTC=0           
   High PORTC.7   
   While PORTB.7=1
   Wend   
   endif
   if PORTB.6=1 then
   PORTC=0
   high PORTC.6
   while PORTB.6=1
   wend
   endif
   
   if PORTB.5=1 then
   PORTC=0
   high PORTC.5
   while PORTB.5=1
   wend
   endif
   
   if PORTB.4=1 then
   PORTC=0
   high PORTC.4
   high PORTC.7
   while PORTB.4=1
   wend
   endif           
TEMP=PORTB
INTCON.1=0
RESUME
ENABLE
end

Kod penceresini kullanın lütfen daha anlaşılır oluyor.

ete

Kesme kısmında yer alan ve kesme bayrağını sıfırlamayı amaçlayan komut yanlış.
Kullandığın kesme PortB değişiklik kesmesi ama sıfırladığın bayrak PortB.0 bayrağı.
TEMP=PORTB
INTCON.1=0
RESUME
ENABLE
end


Bu komutlar arasında yer alan INTCON.1=0 komutu yerine INTCON.0=0 yazmalısın.

Ete

oguztkn

Hocam dediğinizi yaptım ama sorun hala var kesme olayında sorun yok sadece kesmeden döndüğünde önceki sensör kesmeden önce ve sonrada 1 olmasına rağmen sensöre dönmüyor sensörü bir sıfır tekrar bir yaparsam o zmn oluyor bunun nedeni nedir acaba??

Şimdiden Teşekkürler...

ete

Dediklerini pek anlamadım desem yeridir.
Sensör bir giriş elemanı onu nasıl 1 yada sıfır yapıyorsun ?
Düşündümde kesme kısmında tüm portu okumak yerne belkide yalnızca sensörleri okumak gerekiyor.
TEMP=PORTB
INTCON.1=0
RESUME
ENABLE
end

yerine şunu yaz bakalım;
TEMP=PORTB & %11110000
INTCON.1=0
RESUME
ENABLE
end


Ete

oguztkn

Hocam bir siz çalıştırın isterseniz ben tam anlatamadım isis te mz80 var onu bir yapın sürekli 1 de kalsın sonra kesmelerden birini 1 yapın sonra kesme yi tekrar 0 yapın (bu arada mz80 sürekli 1 kalacak) ve mz80 e dönmediğini sizde bir görün


Şimdiden Teşekkürler.....

ete

Bir hex dosyası ve birde farklı programa ait bas dosyası vermişsin. Verdiğin Hex dosyasında bir şey göremedim. Ancak diğer dosyayı kullanınca gördümki kesme kısmı sorunsuz çalışıyor. Nasılmı?
Minisumo2.bas programında;
Vermen gereken pause komutlarını programda kesme kullanıldığı için kesme açılmadan vermen gerekiyor. Bu nedenle aşağıdaki değişikliği yapman lazım.
clear
pause 250
low PORTD.2
lcdout $FE,1
    lcdout $FE,$80,"(: MINIRO`YA :) "
    lcdout $FE,$C0,"  HOSGELDINIZ "
    pause 1500
    lcdout $FE,1
ON INTERRUPT GOTO KES

'******************************************************************************
MENU: 'artık bu satırın bir önemi kalmadı silinebilir.

'******************************************************************************
BASLA:


Kesmenin doğru çalıştığını görebilmen açısından aşağıdaki değişikliğinde yapılması gerekiyor.
    if Mz=1 then
    goSUB ILERI_GITME
    while Mz=1
    wend
    else
'    gosub DUR   'bu satırı kapatıyoruz. Çünki bu satır sayesinde MZ ye basılmaz ise sürekli olarak DUR işlemi yapılmaktadır.
    endif


Şİmdi programı çalıştır ve önce MZ ye bas ardından kesmeleri teker teker çalıştır. Ben çalıştırıyorum. Kesmelerin hepsi çalışıyor ve program kesme etiketine gidip geliyor. Kesmeden de çıkıp kaldığı yere gidiyor. Sorun yok .

Ben bir terslik göremiyorum. Senin gördüğün neyse daha detaylı açıkla bakayım.

Ete

oguztkn

Hocam tekrar rahatsız ediyorum uzun bir aradan sonra tekrar uğraşıyorum kesme ile son program ekte yanlış nerde acaba kesmeler çalışmıyor sanki mikrodenetleyici donuyor gibi oluyor. ?
Birde goto ...  ile gosub ... arasında ne fark var ?
Şimdiden Teşekkürler....

ete

#22
Programda mantık kusurları var.
En baştan başlayarak genel kusurlar ve kesme kusurlarını açıklayayım.

TRISA=%000000  komutunda TRISA registerine 6 bitlik bir değer vermişsin. Register 8 bitliktir. Tris registerlerine daima 8 bitlik değer verin. Aksi halde sistem yanlış çalışabilir.

16F876A işlemcisinde A portu default olarak Analog seçilmişti. Hemde iki türlü analog. Önce komparatör pinleri aktif onu kapatırsan bu sefer ADC giriş pinleri aktiflerdir. Sen ise digital giriş çıkış kullanıyorsun.
O halde Önce komparatörleri iptal etmek gerekiyor .Komutu  CMCON=7  (Unutma 16F876 da komparatör yoktur A serisinde vardır)
Sonra ADC girişlerini iptal etmek gerekiyor. Komutu ADCON1=7

PortB değişiklik kesmesi kullanmışsın. Ancak şema vermediğin için  PortB.4-PortB.7 girişlerinde pullup kullandınmı belli değil.
Normalde dahili pullup dirençlerini aktif edebilirdin. Komutu Option_REG.7=0
Böylece direnç bağlaman gerekmezdi.

Kesme içindeki kusurlara gelince, Kesme alt programı başlı başına bir ayrılmış bölümdür. Orasını bir normal bir alt program gibi düşünemezsin. Oraya girmeninde çıkmanında kuralları vardır.
Kesme etiketinden hemen önce DISABLE diye bir komut kullanıyoruz. Bu kesmeye girdiğin zaman (kesme oluştuğu zaman diyelim) programın yeniden kesme üretmesine mani olmak için Global kesme biti (INTCON.7) reset edilir.
Kesme içinde işlerini yaparsın ve en sonda ise kesmeyi oluşturan bayrağı resetlersin ve kesmeden Resume ve sonra ENABLE komutları ile çıkarsın. Enable yeniden Global kesmeleri aktif hale getirir.
Peki sen ne gibi bir kusur işlemişsin bakalım.
Dikkatlice bakarsan kesme içindeki programda;

Goto Sol
Goto Sağ
Goto ileri
Goto Geri
şeklinde komutlar kullanmışsın. Bu komutlar programın kesmeden çıkmasına neden olurlar. Peki normalde kesme den çıkmak için kural neydi? kural basit kendi çıkışından çıkacaksın. Zira kesmeye girerken kesme iptal edildi. Sende kendi çıkışından çıkmaz isen bir defa kesme yeniden aktif edilmemiş olur. Bir diğer sorun ise stack meselesidir. Program kesmeye giderken bulunduğu adresi stack içine atar. Kesmeden çıkarkende o adresi geri alır ve kaldığı yere gider. Böylece program kopukluk olmadan çalışmasına devam eder. Ama senin çıktığın gibi çıkarsan bir müddet sonra stack şişmesi meydana gelir.
Peki ne yapman gerekir? Yapılacak iş basit. Kesme içinde basılan tuşa bağlı olarak bir bit değişkenini set edersin.
Mesle SOLBIT , SAGBIT , ILERIBIT , GERIBIT şeklinde bit tipi değişkenler tanımlarsın.
Programda kesme kısmında , Goto SOL yazmak yerine  SOLBIT=1 dersin. Yada Goto SAG yazmak yerine SAGBIT=1 dersin.
diğerleri içinde aynı mantığı kullanırsın ve kesmeden çıkarsın.
Ana program içinde ;

Başla etiketinden sonraki ilke program parçasında şunlar yazılı;
    if mz80=0 then
    goto ileri
    while mz80=0
    wend
    else
    goto dur
    endif
Bunu şöyle değiştirebilirsin.
    if mz80=0  or ILERIBIT=1 then
        ILERIBIT=0      '..........................önce biti sıfırlamak gerekir
        goto ileri
        while mz80=0  'bu satırı sil çünki program buraya hiç ulaşamaz öncesinde Goto Ileri komutu bunu önler.
    wend  'buda silinecek
    else
    goto dur
    endif
Diğer kontrollerede aynı mantığı uygularsan programın kusursuz çalışacaktır.

Gelelim Goto ile Gosub farkına.
Goto bir emir komutu olup Goto kelimesinden sonra gelen isimli etikete programın direk alamasını sağlar. Geri dönüşü yoktur. GOTO CIK denildimi program işini bırakır ve CIK isimli etikete atlar ve işine oradan devam eder.

Gosub da bir emir komutu dur. Komuttan sonra gelen etiket ismine program atlar ancak orada mutlaka bir yerlerde RETURN komutu görmelidir. Return görüncede ilk geldiği yere geri döner. Örnek verelim. GOSUB EKRAN denildimi program EKRAN isimli alt programa gider orada işini yapar ama mutlaka EKRAN alt programında işin bitiminde birde RETURN komutu olmalıdır.
Program return u görünce GOSUB EKRAN komutu ile ayrıldığı yere geri döner ve Gosub Ekran komutundan bir sonraki satırdan çalışmasına devam eder. Bu komut dikkatli kullanılmayı gerektirir. Zira Gosub ile ayrılan program ayrılma adresini stack içine yazar. Return komutunu görünce de stack den adresi geri alır ve geldiği yere bu şekilde döner. Program peş peşe 5 adet Gosub komutu uygulayacak kadar stack hafızasına sahiptir. Üst üste 5 den fazla gosub verirseniz stack şişer ve geri dönüş adresini program kaybeder ve kitlenir kalır. Her Gosub komutu stack den bir adres yeri işgal eder. Ama her return komutu stack den alınan adres yerini geri iade eder. Ama bir Gosub verdin return görmeden birdaha gosub verdin iki adres gitti bir daha gosub verdin bir adres daha gitti. Sonuşta stack şişer. Buna dikkat etmek gerekir. Çok yapılan hatalardanbiriside Gosub ile gidilen yerden Return yerine Goto ile çıkılmasıdır. Buda stack in şişmesisine sebep olur ve program kitlenir. Hepsi bukadar.

Ete

mg1980

Ete Hocam,
Çoktandır size bir soru sormayı düşünüyordum.Galiba tam zamanı.Kesmelerden hemen önce DISABLE komutu kullanıyoruz.Gerekçesini anladım . Benim sorum şu: Program başlayıp çalışırken kesme oluştuğunda doğrudan KESME etiketine gittiğine göre bu etiketin üstündeki DISABLE komutunu nasıl görüp de gereğini yapıyor ? Bu komutun KESME etiketinden sonra yazılması gerek mez mi?

Saygı ve selamlar.mg1980

oguztkn

Hocam dediklerinizi yaptım son hali ekte var bir kontrol edermisiniz birde bendeki tüm sensörler normalde +5 tetiklenince 0 oluyorlar kesmede bundan dolayı bir sorun olurmu?

ete

Mg1980,

Mantık sırasını düşünürsen önce yeni kesmelerin iptal edilmesi sonra kesme etiketine girilmesi daha doğru bir sıradır.
Bu nedenle kesme den önce disable kullanılır.

Ete

ete

Oguz1993,
Dediklerimi yapmamışsın. Yazdıklarımıda okumamışsın anlaşılan. Üstelik progamı traşlayarak daha da çalışmaz hale getirmişsin.
Yeniden son duruma göre kusurlarını açıklıyorum.
1. ILERIBIT .. SAGBIT gibi değişkenleri bit bazında tanımla demiştim çünki değeri ya sıfır yada bir olacak. O halde neden bunları byte cinsinden tanımladın. Bunlar düzeltilecek.

2. Başla satırından sonra şayet bir değişkene balı konum ileri etiketine gidilmeyi gerektiriyor ise (IF MZ80=0 THEN) oraya kesmede set edilen bitleride ilave et demiştim.
Bir düşün bakalım. Ne zaman ileri etiketine gidilecek ;
a) Şayet MZ80=0 ise
b) İleribit=1 ise
O halde bu ikisini birleştirir ve şöyle derim
  IF MZ80=0 OR Ileribit=1 then
      GOSUB ILERI      bak burada goto yerine Gosub kullandım. Neden Return ile dönülen bir yere Gosub ile gidilir. Sen goto yazmışsın. Mesajımda uzunca açıklamış idim. Ne zaman goto ne zaman gosub kullanılacak diye. Goto kullanarak gittiğin yerden ancak yeni bir Goto ile dönersin. Ama Goto ile gittiğin yerin son satırına Return yazmış isen oraya Gosub ile gidersin. Gittiğin yerde Return görüldüğü zaman program otomatik ilk ayrıldığı yere geri döner.

Basla etiketinden sonra programı İleri , Geri , Sola , Saga yönlendirecek hiç bir komut yok. Olanlarıda çıkarmışsın. Amacın ne idi? acaba.

Her neyse, Daha bir çok eksiklik var. Ama devre şeması vermediğin için kim ne yapıyor anlayamıyorum.
Ortada kesmeye bağlı 4 adet buton yada giriş var. Hadi bunlar ileri, geri, sağa, ve sola yönlendirmeleri yapıyorlar.
C portundaki girişler neyin nesidir. Programda da açıklama yok. Üstelik C portundaki girişlerin bir kısmını hiç kullanmamışsın.
Meslea,
pna1 var PORTC.0
pna2 var PORTC.1
pna3 Var PORTC.2
pna4 var PORTC.3
bu girişler ne işe yarıyorki hiç kullanmamışsın. İşe yaramıyorlarsa neden tanımladın?.
Programı olması gerektiği gibi yazdım. Ancak C portuna bağlı hiç bir şey yazmadım. Yazılanda yanlış çünki mz80 sıfır değilse program her halukarda dur etiketine gidecek ki bu yanlış . Her zaman durması gerekmez bence. Orada mantık hatası var mutlaka. Durma işini ayrı bir şarta bağlamalısın bence.
 @DEVICE pic16F876A
@DEVICE pic16F876A,WDT_OFF
@DEVICE pic16F876A,PWRT_ON
@DEVICE pic16F876A,PROTECT_OFF
@DEVICE pic16F876A,MCLR_OFF
@DEVICE pic16F876A,XT_OSC
'****************************************************************
Define OSC 4
'****************************************************************
TRISA=%00000000     ;PORTA nın tüm bitleri çıkış
TRISB=%11110000   ;PORTB nin son 4 biti giriş ilk 4 biti çıkış
TRISC=%11111111   ;PORTC nin tüm bitleri giriş
INTCON=%10001000
ADCON1=7
CMCON=7
Option_REG.7=0
;****************************************************************
in1  var PORTB.0
in2  var PORTB.1
in3  var PORTB.2
in4  var PORTB.3
pna1 var PORTC.0
pna2 var PORTC.1
pna3 Var PORTC.2
pna4 var PORTC.3
mz80 var PORTC.4
;****************************************************************
Temp      var BYTe
sagbit    var bit
solbit    var bit
ileribit  var bit
geribit   var bit
durbit    var bit
on interrupt Goto KESME
;****************************************************************
clear
pause 500
;****************************************************************
Basla:
    if mz80=0 then
    GOSUB ileri
    else
    goto dur Bunu buraya yazarsan mz80=0 değilse mutlaka dur etiketine gidilir. Halbuki illaki durması gerekmiyor!!!!!!.
    endif

    IF ILERIBIT=1 THEN
      ILERIBIT=0
      GOSUB ILERI
    ENDIF

    IF GERIBIT=1 THEN
       GERIBIT=0
       GOSUB GERI
    ENDIF

    IF SAGBIT=1 THEN
       SAGBIT=0
       GOSUB SAG         
    ENDIF

    IF SOLBIT=1 THEN
      SOLBIT=0
      GOSUB SOL
    ENDIF

BURADAN İTİBAREN C PORTUNDAKİ GİRİŞLERİN DURUMU TEST EDİLEREK ONALARA BAĞLI İŞLEMLERE YER VERMELİSİN.

    goto Basla
;****************************************************************   
ileri:
    high in1
    low  in2
    high in3
    low  in4
    return
geri:
    low in1
    high in2
    low in3
    high in4
    return
dur:
    low in1
    low in2
    low in3
    low in4
    return
sag:
    high in1
    low  in2
    low  in3
    high in4
    return
sol:
    low  in1 
    high in2
    high in3
    low  in4
    return
;**************************************************************
disable
Kesme:
   IF PORTB.7=0 then     
   solbit=1 
   While PORTB.7=0 
   Wend   
   endif
   if PORTB.6=0 then
   sagbit=1
   while PORTB.6=0
   wend
   endif
   if PORTB.5=0 then
   ileribit=1
   while PORTB.5=0
   wend
   endif
   if PORTB.4=0 then
   PORTC=0
   geribit=1
   while PORTB.4=0
   wend
   endif           
   TEMP=PORTB
   INTCON.1=0
   RESUME
   ENABLE
   end


Ete

oguztkn

Hocam ben sizin yazdıklarınızı tabiki okuyorum ve eksiklerimi tamamlamaya çalışıyorum kendimce.Devre şeması demişiniz ben minisumo ile uğraşıyorum portb de ilk dört bitte motor sürücü (l293d)  son dört bitte ise 4 tane qrd1114 var kesme olarak kullandığım.Portc de ise 3 tane sensör (ön-sag-sol) var.Ben kodları size yollarken sadece 4 tane sensörün 3 ünü silmeye çalıştım yani 1 sensörle çalıştırabilirsem diğerlerinide sonradan eklerim diye.Çünkü 4 tane sensör ile kontrol yapabiliyorum kesme yi beceremiyorum.ön sağ ve sol için sadece program yazıyorum robot güzel çalışıyor ama iş kesmeye gelince takılıyorum.Bu son yazdıklarınızı akşama deneyebileceğim.

ete

Akşama dene bakalım. En azından kesme ler çalışacaktır mutlaka.
Ete

oguztkn

Hocam programı denedim fakat portb 4,5,6,7 de motor sürücü bağlıydı onları portc ye aldım çünkü option reg motorları çalıştırtmıyordu.şimdi mz80 görünce motorlar ileri gidiyor görmeyince duruyor görüyorken kesmeleri deniyorum bir değişiklik olmuyor yani hiç yokmuş gibi devam ediyor yoluna mz80 görmüyorken kesmeleri deniyorum gene birşey yok ama kesme sensörlerinden herhangi birini kapatıp mz80 görünce ileride gitmiyor bu nasıl bir sorun acaba ?

Powered by EzPortal