Interrupt çıkmazı

Başlatan onurinci, 16 Şubat 2017, 02:30:52

onurinci

 Hocam selam
printer'den söktüğüm bir optik encoderim var ve gray kodu üretiyor,hızlı çevirirsem sapıtıyor yavaş çevirmede güzel çalışıyor,daha evvel 16F628 ile PortB kesmesi evvel iki adet bağımsız giriş ve çıkış yapmıştım,gayet güzel çalışmıştı,12F675 'e çevireyim dedim bir türlü başaramadım.

sistem iki adet birbirinden bağımsız çalışan oneshot, her giriş 0 olunca tek bir pulse üretiyor ,pulse'nin süresini ben ayarlıyorum ,sorunum galiba doğru INTCON bitlerini ayarlıyamadım diye düşünüyorum,
tek tık normal çalışıyor,fakat hala 0'da duruyorsam ,sürekli çıkış var bu birinci sıkıntım,kesme olmasına rağmen ,bir giriş verilen işi bitirmeden diğer girişi çalıştıramıyorum..

amacım encoder'den gelen Bounce ve Glitch'leri bir nebze disipline sokup sıçramaları önlemek..

@ Device PIC12F675,WDT_OFF,PWRT_ON,PROTECT_OFF, CPD_OFF,MCLR_OFF,BOD_OFF,INTRC_OSC_NOCLKOUT
DEFINE OSC 4
DEFINE OSCCAL_1K 1
TRISIO= %000011 : GPIO= 0

CMCON= 7
ANSEL= 0
OPTION_REG= %00000000
WPU= %00000011

INTCON= %10101000     ' Enable the GPIO port change interrupt

ON INTERRUPT GOTO Wake_up

Led_1 VAR GPIO.4
Led_2 VAR GPIO.5

Sw_1  VAR GPIO.0
Sw_2  VAR GPIO.1

Cnt   VAR BYTE

Start:


GOTO Start

DISABLE
'------------------------------------------------------------------------------- 
Wake_up:

IF Sw_1= 0 THEN S1
IF Sw_2= 0 THEN S2

GOTO Main
'-------------------------------------------------------------------------------
S1:

      Led_1= 1
      PAUSE  5
      Led_1= 0

   
GOTO Main
'-------------------------------------------------------------------------------
S2:

      Led_2= 1 
      PAUSE  5
      Led_2= 0 
   
    GOTO Main
'-------------------------------------------------------------------------------

Main:
   
'INTCON.0= 0 ' Clear the RB port change flag bit
INTCON.1= 0     ' Clear Interrupt flag
RESUME : ENABLE
END

ete

Basit bir programı karmaşık hale getirmişsin.
Öncelikle hiç kullanmıyor olsan da TMR0 kesmesini aktif etmişsin. Ama kesme içinde ona ait bir bayrak sıfırlama gözükmüyor.
Tmr0 sürekli çalışan bir sayactır ve 255 den tekrar sıfıra döner ve o anda da kesme oluşturur. Programın kesme alt etiketine (sende Wakeup) gider ve orada ne yapıalcak se yapıp kesmeden çıkar. Orada yaılacak işlerden birisi kesme bayrağını sıfırlamaktır. Tmr0 kesme bayrağı INTCON.2 dir. Sen kesme bayrağını sıfırlamayınca program kesmeden çıkıp tekrar kesmeye girer. Çünki geri planda pici yöneten işletim sistemi flag=1 ise kesmeye git diye ona emir verir.

Diğer taraftan ikinci kesme kaynağın olarak Port değişiklik kesmesini kullanmışsın. Onunda kesme bayrağı INTCON.0 dır ki onuda kapatmışsın aktif değil yani. Hiç alakası olmayan INT kesmesi bayrağı (INTCON.1) aktif edilmiş ki öyle bir kesme emrin yok. Tamamen çorba anlayacağın.
Düzeltmek için
INTCON=%10001000 değerini ver. Bu işlemcide birde IOC (Interrupt On Change) registeri var. Onada değer vermek zorundasın. Hangi pinler kesme oluşturacak ise onları 1 yapıp diğerlerini 0 vermelisin. 0 ve 1 nolu bitlerin giriş olduğuna göre IOC=%00000011 değerini vermen gerek. Bu komutuda INTCON registerinin üstüne yazıver.

Main altına da şunları yaz.
Main:
INTCON.0= 0     ' Clear Interrupt flag
TEMP=GPIO
RESUME : ENABLE
Temp=GPIO komutu portun okunup Temp değişkenine aktarılmasını sağlar. Bu kesmeden çıkış anında portun ne durumda olduğunu işlemciye söyler. Böylece PORT bu okunan değerden farklı bir değer aldığında özellikle IOC bitleri farklı konum aldığında hemen kesme oluşturulur. AKsi halde işlemci kararsız kalır. Çünki adı üzerinde PORT Değişiklik kesmesi. Önceki halini bilmez isen değişiklik olduğunu nasıl anlayacaksın?.
Hepsi bu kadar.
Kesme içinde bir sürü dallanma var bunların hepsi main altında çözülebilirdi.
DISABLE
'------------------------------------------------------------------------------- 
Wake_up:
IF Sw_1=0 THEN
  Led_1=1
  Pause 50  'bunun yandığını bile görmen mümkün değil 5 ms de led yanar ve söner sen hep sönük görürsün
  led_1=0
Else
  Led_2=1
  Pause 50
  Led2_0
ENDIF   
   
INTCON.0= 0 ' Clear the RB port change flag bit
RESUME : ENABLE
END

Ledler için 5 ms yanma süresi vermişsin ardından led söndürülüyor. 5ms de ledin yandığını göremezsin ve göremediğin içinde program çalışmıyor diye düşünebilirsin. Önce o 5 ms lik değeri 50 vyada daha iyisi 100 yap ki ledin yandığını gör.
Encoderi biraz yavaş çevir çünki pause ler hızlı okumanı engelleyecektir.

Ete

onurinci

#2
hocam ya biraz toparlayabildim ,yada daha berbat ettim,encoder Gray tablosuna göre 00 kodu her iki portunda çıkış 1 verebilmesi gerekir,oysa hala biri görevini bitirmeden diğeri pasif kalıyor,pause'leride döngü içinde denedim,
hocam en iyisi size böyle bir şey gerekseydi benim yazmaya çalışmayı yöntemi unutalım,siz nasıl bir şey yazardınız ? zira beceremeyeceğim galiba..

@ Device PIC12F675,WDT_OFF,PWRT_ON,PROTECT_OFF, CPD_OFF,MCLR_OFF,BOD_OFF,INTRC_OSC_NOCLKOUT
DEFINE OSC 4
DEFINE OSCCAL_1K 1
TRISIO= %000011 : GPIO= 0

CMCON= 7
ANSEL= 0
OPTION_REG= %00000000
WPU= %00000011
IOC=%00000011  '**********************
'INTCON= %10101000     ' Enable the GPIO port change interrupt
INTCON= %10001000     ' Enable the GPIO port change interrupt  *************

ON INTERRUPT GOTO Wake_up

Led_1 VAR GPIO.4
Led_2 VAR GPIO.5

Sw_1  VAR GPIO.0
Sw_2  VAR GPIO.1

Temp var byte

X var word
Y var word

Start:
goto Start


DISABLE
'------------------------------------------------------------------------------- 
Wake_up:

IF Sw_1= 0 THEN S1
IF Sw_2= 0 THEN S2

GOTO Main
'-------------------------------------------------------------------------------
S1:

FOR x= 1 TO 3500 : HIGH LED_1 : pauseus 1
NEXT x

FOR y= 1 TO 3500 : LOW  LED_1
NEXT y
 
GOTO Main
'-------------------------------------------------------------------------------
S2:

  FOR x= 1 TO 3500 : HIGH LED_2 : pauseus 1
NEXT x

  FOR y= 1 TO 3500 : LOW  LED_2
NEXT y 
    GOTO Main
'-------------------------------------------------------------------------------
   
Main:
INTCON.0= 0     ' Clear Interrupt flag
TEMP=GPIO
RESUME : ENABLE
'end

ete

Kesme kullanılan programlarda pause kullanmaktan kaçınırız sebebi basit pause işlenirken süre bitmeden program kesme etiketine gidemez. Bu nedenle direk pause kullanmak yerine döngüsel (küçük dilimli pauseler) gecikme kullanırız ki küçük gecikme dilimi bittiğinde program kesme etiketine atlayabilsin diye.
Ama Kesme içinde bunu yapmak gerekmez çünki aten kesme içindesin ve yeniden kesme oluşumu sen oradan çıkıncaya kadar otomatik engellenmiştir.

Öncelikle Grey kodun ne olduğunu öğren ve encoderin bir turda hangi %BA kodlarını ürettiğine bir bak istersen.
Sen Encoder kodunun yalnızca %11 versiyonunu kullanıyorsun yada %01 ve %10 kodlarınıda kullanıyorsun diyelim.
Ama %00 da bir koddur ve oda üretilmektedir ve %00 üretildiği zamanda program kesmeye girer.
Bu durumda ya kesme başına IF (GPIO AND %00000011)=0 then MAIN deyip programı kesmeden çıkarman gerekiyor.

Programda bir kusur göremedim. Ama hala neden Kesme kısmını benim dediğim gibi yapmıyorsun anlamış değilim.

Ete

onurinci

hocam yapmadığımdan değil yapamadığımdan :D
(Ama hala neden Kesme kısmını benim dediğim gibi yapmıyorsun anlamış değilim.)

bazı şeyleri nereye koyulması gerekir ona vakıf değilim örneklere bakarak ilerleyebiliyorum,eğer derleyebilirseniz ,
denemek isterim..

simulatorda bir butonu kapalı hale getirip ,diğerine dokunursanız hep GP.4'ün aktif olduğunu göreceksiniz ,açıklama bulamadığım bunun tam dersini yaptığımızda yani diğer butonu kapalı tutup diğerine tıkladığınızda yine GP4'ün aktif olduğunu göreceksiniz,burada GP5'e öksüz evlat muamelesi yapılıyor,reaksiyon vermiyor..

kesme konuları bana yabancı,acaba kesme içinde kesmemi gerekiyor..

daha evvel GP2 external kesmesi ile bir uygulama yapmıştım,mükemmel çalışıyor ne varki bir işlemcide bir tane bulunuyor......

ete

#5
Öksüz evlat dediğin yerde bir sorun olduğu kesin. Oraya bakman gerekirdi. Baksaydın orada ledi söndüren kısımda
Led2_0 ifadesini görebilirdin. Bu aslında Led_2=0 olması gerekiyor tabiiki. Ne hikmet ise derleyici o yanlış ifadeye bir şey demiyor. Kabul ettiği bir komut şekli olsa gerek.
Bu düzeltmeyi yaparsan sistem sorunsuz çalışıyor.

Ete


onurinci

hocam dediniz yeri düzelttim evet let söndü ama diğer switch işlevsiz kaldı ,acaba nerede hata yapıyorum...
@ Device PIC12F675,WDT_OFF,PWRT_ON,PROTECT_OFF, CPD_OFF,MCLR_OFF,BOD_OFF,INTRC_OSC_NOCLKOUT
DEFINE OSC 4
DEFINE OSCCAL_1K 1
TRISIO= %000011 : GPIO= 0

CMCON= 7
ANSEL= 0
OPTION_REG= %00000000
WPU= %00000011
IOC=%00000011  '**********************
'INTCON= %10101000     ' Enable the GPIO port change interrupt
INTCON= %10001000     ' Enable the GPIO port change interrupt  *************

ON INTERRUPT GOTO Wake_up

Led_1 VAR GPIO.4
Led_2 VAR GPIO.5

Sw_1  VAR GPIO.0
Sw_2  VAR GPIO.1

Temp var byte

X var word
Y var word

Start:
goto Start


'DISABLE
''------------------------------------------------------------------------------- 
'Wake_up:

' IF Sw_1= 0 THEN S1
' IF Sw_2= 0 THEN S2

' GOTO Main
''-------------------------------------------------------------------------------
'S1:

' FOR x= 1 TO 3500 : HIGH LED_1 : pauseus 1
' NEXT x

' FOR y= 1 TO 3500 : LOW  LED_1
' NEXT y
 
' GOTO Main
''-------------------------------------------------------------------------------
'S2:

'  FOR x= 1 TO 3500 : HIGH LED_2 : pauseus 1
' NEXT x

'  FOR y= 1 TO 3500 : LOW  LED_2
' NEXT y 
'    GOTO Main
''-------------------------------------------------------------------------------
DISABLE
'------------------------------------------------------------------------------- 
Wake_up:
IF Sw_1=0 THEN
  Led_1=1
  Pause 50  'bunun yandığını bile görmen mümkün değil 5 ms de led yanar ve söner sen hep sönük görürsün
  Led_1=0
Else
  Led_2=1
  Pause 50
  Led_2=0
ENDIF
   
Main:   
INTCON.0= 0 ' Clear the RB port change flag bit
TEMP=GPIO
RESUME : ENABLE
END
 
'Main:
'INTCON.0= 0     ' Clear Interrupt flag
'TEMP=GPIO
'RESUME : ENABLE
'END

ete

Ufak bir kusurumuz olmuş Wakeup kısmını aşağıdaki şekilde düzelt;
Wake_up:
IF Sw_1=0 THEN
  Led_1=1
  Pause 50  'bunun yandığını bile görmen mümkün değil 5 ms de led yanar ve söner sen hep sönük görürsün
  Led_1=0
ENDIF

IF SW_2=0 THEN
  Led_2=1
  Pause 50
  Led_2=0
ENDIF

onurinci

hocam sabrınıza sığınıyorum,portlar çıkışı kaybetti,Debugger ile GİE ve GPIO yu gözlemeye aldım sanki herşey yolunda gibi ama ELSE'li versiyonda en azından bir port çalışıyordu,şimdi ikiside gitti son hali....belki bir yeri atladım mazeret değil biliyorum ama sizden üç yaş küçüğüm..

@ Device PIC12F675,WDT_OFF,PWRT_ON,PROTECT_OFF, CPD_OFF,MCLR_OFF,BOD_OFF,INTRC_OSC_NOCLKOUT
DEFINE OSC 4
DEFINE OSCCAL_1K 1
TRISIO= %000011 : GPIO= 0

CMCON= 7
ANSEL= 0
OPTION_REG= %00000000
WPU= %00000011
IOC=%00000011  '**********************
'INTCON= %10101000     ' Enable the GPIO port change interrupt
INTCON= %10001000     ' Enable the GPIO port change interrupt  *************

ON INTERRUPT GOTO Wake_up

Led_1 VAR GPIO.4
Led_2 VAR GPIO.5

Sw_1  VAR GPIO.0
Sw_2  VAR GPIO.1

Temp var byte

X var word
Y var word

Start:
goto Start



'    GOTO Main
''-------------------------------------------------------------------------------
DISABLE
'------------------------------------------------------------------------------- 


''Wake_up:
''IF Sw_1=0 THEN
''  Led_1=1
''  Pause 50  'bunun yandığını bile görmen mümkün değil 5 ms de led yanar ve söner sen hep sönük görürsün
''  Led_1=0
''Else
''  Led_2=1
''  Pause 50
''  Led_2=0
''ENDIF
   
Wake_up:
IF Sw_1=0 THEN
  Led_1=1
  Pause 50  'bunun yandığını bile görmen mümkün değil 5 ms de led yanar ve söner sen hep sönük görürsün
  Led_1=0
ENDIF

IF SW_2=0 THEN
  Led_2=1
  Pause 50
  Led_2=0
ENDIF






Main:   
INTCON.0= 0 ' Clear the RB port change flag bit
TEMP=GPIO
RESUME : ENABLE
END
 
'Main:
'INTCON.0= 0     ' Clear Interrupt flag
'TEMP=GPIO
'RESUME : ENABLE
'END

onurinci

hocam IF şartlarındaki Pause yetersiz kalmış ondan çıkış alamamışım,Led'lere  osilaskobu dayayıp puls'ları görünce bu gizemi hallettim,

sandığımdan zor imiş, TTL mono flop'lar ile yapmaya karar verdim, zira simulasyondaki bir butonu basık tutarak,diğerine bastığınızda alakası olmadığı halde diğeride tepki veriyor, kesme rutin'ide olsa pic belki yapısı gereği bağımsız olamıyor tabi bu benim kanaatim, hocam en basitinden bir elektronik piyano düşünürsek aynı anda iki tuşa basabiliyoruz yani tuşlar bir birinden tamamen bağımsız. yardımlarınız için çok teşekkür ederim...

ete

Burada da iki tuşa hatta varsa 3 tuşa bile basabilirsiniz. Bunların hepsi port için birer değişikliktir ve kesme yaratırlar.
Enbaştan söylemiştim bir ledin yanması yananın görülmesi için gereken zaman aşağı yukarı 80-100 ms dolayındadır. Altında olursa makinada hızlı ise göremezsiniz.
O kadar da zor değil mekanizmayı bilirseniz gerisi zor değil gerçekten ve kesme tepkisi epeyce hızlıdır. Yetmiyorsa 12F1822 kullanın daha yüksek frekanslarda çalıştırmak mümkündür.
Ete

Powered by EzPortal