TMR0 kesmesi ile ilgili yardım

Başlatan hgungor, 21 Temmuz 2014, 14:28:13

hgungor

merhaba arkadaşlar , tmr0 kesmesi ile ilgili bir yazılım yaptım ama yazılımda interrupt vektöründe yaktığım b.1 portundaki ledi ana programda söndüremiyorum.

bu programda kesmenin 1296 mikro saniye sonra bir defa oluşup ledi interrupta yakmasını ve ana programda söndürmesini istiyorum ama olmuyor. Ana programa dönünce intcon.7 yi kapatmama ramen sürekli kesmeye giriyor.

uzman arkadaşların yardımlarını bekliyorum

teşekkürler şimdiden

;**** tmr0 deneme ****
lıst p=16f628a
ınclude "p16f628a.ınc"
__confıg _ıntrc_osc_noclkout & _wdt_off & _pwrte_on & _mclre_on & _boden_off & _lvp_off & _data_cp_off & _cp_off
kontrol equ 0x30
delay1 equ 0x31
delay2 equ 0x32

org h'000'
goto main

org h'004'
bcf ıntcon,7
bsf kontrol,0
bsf portb,1 ; ledi burada yaktım
bcf ıntcon,2
retfie

main:
bcf status,rp1
bsf status,rp0
movlw b'11111111'
movwf trısa
movlw b'00000000'
movwf trısb
bcf status,rp0

bsf status,rp0
movlw b'10000010' ; prescaler'i 8'e ayarladım
movwf optıon_reg
bcf status,rp0

bcf kontrol,0
movlw b'10100000'
movwf ıntcon
movlw d'94' ; 1296 mikro saniye sonra kesme gelmesini istiyorum
movwf tmr0

aa3: ; burada kesmeden gelip ana programa devam için bir şart koydum
btfss kontrol,0
goto aa3

;-------gecikme---------------
movlw d'255'
movwf delay2
loop2
movlw d'255'
movwf delay1
loop1
nop
nop
decfsz delay1,1
goto loop1
decfsz delay2,1
goto loop2

bcf portb,1 ; led sönmüyor burada
nop
nop
end

Tagli

Gecikme kodu ne kadar sürecek? Elbette kafamda sağlıklı çalıştırmam  mümkün değil ama içinde iki tane 255 görünce en az 65536 çevrim sürecek gibi geldi bana. Bu 4 MHz'de çalışan bir işlemci için 65 ms'den fazla yapar. Sen TMR0'ı 1296 us'ye göre kurduğunu söylüyorsun. Bu durumda sürekli olarak kesme gelmesi normal. LED sönse bile 1.2 ms sonra geri yanacak, bunu gözle fark edemezsin.
Gökçe Tağlıoğlu

hgungor

Tagil ben olayı kavrayamadım, şimdi timer0 ilk kesmeye girince ben onu kapatıyorum ( bu kapatma işini hem kesme vektöründe hemde ana programda defalarca denedim)  kapatmama ramen kesmeden çıkınca neden birdaha kesmeye giriyor.

Ben gecikmeyi 65ms sonra ledin sönmesi için yazdım yoksa ledin yanıp söndüğünü yakalayamazdım.

Sıkıntı kesmelerin hepsini kapatmama (bcf intcon.7)  ramen neden kesmeye giriyor.

Teşekkürler

RaMu

#3
Sen bu programın hatasız derlendiğine eminmisin,
Türkçe karakterler var içinde,
bu şekilde bu programın derlenmesi imkansız,
misal
ıntrc_osc diye birşey yoktur
INTRC_OSC diye yazacaksın
bcf ıntcon,7 olamaz
BCF INTCON,7 yazacaksın

yani ya büyük harfle I
yada küçük harfle i olarak yazacaksın,
ben genelde büyük harflerle yazarım programı
öncelikle bu syntax hatalarını düzelt yine bakalım.
Sorularınıza hızlı cevap alın: http://www.picproje.org/index.php/topic,57135.0.html

Tagli

Öncelikle, sık gördüğüm bir hata (aslında pek hata da sayılmaz) kesme kodu girişinde bcf INTCON,GIE yazılması. Bunun hiçbir etkisi yok, çünkü PIC kesmeye girdiğinde bunu zaten kendisi otomatik olarak 0 yapar. Böylece iç içe kesme gelmesi engellenmiş olur. Kesmeden çıkmadan önce bayrağı da indiriyorsun, burada da sorun yok. Ancak, sondaki retfie komutu INTCON,GIE'yi tekrardan 1 yapar. Normal return komutundan farkı da o. İki işi tek komutta yapması, yoksa bir özelliği yok. Aslında olması gereken de bu, kesme kodundan çıkarken, tekrardan kesme alabilmek için bunun açılması gerekir.

Şimdi, burada önemli bir nokta var: Kesme bayrakları, kesme izinlerinden bağımsızdır. Sen kesmeleri açsan da açmasan da, kesme şartı sağlandığında bayrak kalkar ve sen veya bazı özel durumlarda donanım indirine kadar öyle kalır. Kesme kapalıysa, bayrak 1 de olsa kesme koduna atlama olmaz tabi.

Senin kodda kesmeye girip LED'i yakıyorsun. Ancak ana programda bekleme döngüsüne girdiğinde, bu döngü bitmeden tekrar kesme geliyor. Zaten senin GIE de 1 olarak kaldı. Bu sebeple, her 1.2 ms'de bir LED'e zaten yanma emri geliyor. Bunun ilk akla gelen çözümü, kesme kodundan retfie yerine return ile dönmek. Ama bu pis bir yama olur. Öylesine deneme yapacaksan sorun değil ama normalde bir kodda asla bu şekilde GIE 0 bırakılarak kesmeden çıkılmamalı. Ayrıca, bu şekilde bir kullanımda kesme kullanmanın da bir anlamı kalmıyor.

Yukarıda bahsettiğim yama tek kullanımlık. GIE 0 kalsa bile, 1.2 ms sonra bayrak sessizce kalkacak ve sen GIE'yi 1 yaptığın anda kod kesmeye sıçrayacak ve tekrar LED yanacaktır.

Bu arada, kodun sonlanmasına asla izin vermemelisin. Kodun sonunda durması gereken yerde bir sonsuz döngü mutlaka olmalı. Bunu basitçe goto $ yazarak halledebilirsin.
Gökçe Tağlıoğlu

hgungor

#5
Ramu cevap için teşekkürler ama sanırım kopyala yapıştır yaparken bir sorun oldu derleyicinin içinde türkçe karakter gözükmüyor ve compile oluyor. Sorun ile ilgili başka fikirlerin varsada lütfen paylaş sorunu hala çözemedim.

Tagli senin cevabın içinde teşekkür ederim, benim yapmak istediğim aslında belirli bir frekansta gelen sinyali ölçmek olacak , gelen sinyal 1296 us boyunca 1 (+5v)  sonra yine aynı süre boyunca 0v ,  fakat bazen üst üste birkaç defa  1 yada 0 bilgisi gelebiliyor ,düzensiz yani.

Ben ilk olarak  ilk gelen bilgiyi ölçeyim sonrasına bakarım dedim ama , program sürekli kesmeye girince durdurmak istediğim yerde durmadı.

Şimdi ben kesmeden geri döner dönmezde  interruptı kapatıyorum ama sonuç aynı oluyor. Yani kesmeden retfi iile çıkınca bir şartlı döngü vardı a3 başlığı altında o döngüden çıkar çıkmaz bcf intcon,7 yapıyorum ama  kesmeler sürekli gelip led hep yanıp sönüyor. Senin dediğin gibi return komutu ile çıkmayı hiç denememiştim, fakat onuda deneyince hala led sürekli yanıp sönüyordu. En sonda ledi söndürünce birdaha interrupt gelip ledi yakıp söndürmesini istemiyorum. ( Ek olarak ledi söndürdükten sonraya bir geçikme daha yazdım ledin sönük kalma süresini görebilmek için )

Son olarak denediğim program

;**** tmr0 deneme ****
lıst p=16f628a
ınclude "p16f628a.ınc"
__confıg _ıntrc_osc_noclkout & _wdt_off & _pwrte_on & _mclre_on & _boden_off & _lvp_off & _data_cp_off & _cp_off
kontrol equ 0x30
delay1 equ 0x31
delay2 equ 0x32

org h'000'
goto main

org h'004'

bsf kontrol,0
bsf portb,1 ; ledi burada yaktım
bcf ıntcon,2
return

main:
bcf status,rp1
bsf status,rp0
movlw b'11111111'
movwf trısa
movlw b'00000000'
movwf trısb
bcf status,rp0

bsf status,rp0
movlw b'10000010' ; prescaler'i 8'e ayarladım
movwf optıon_reg
bcf status,rp0

bcf kontrol,0
movlw b'10100000'
movwf ıntcon
movlw d'94' ; 1296 mikro saniye sonra kesme gelmesini istiyorum
movwf tmr0

aa3: ; burada kesmeden gelip ana programa devam için bir şart koydum
btfss kontrol,0
goto aa3

;-------gecikme--------------- ------------------
movlw d'255'
movwf delay2
loop2
movlw d'255'
movwf delay1
loop1
nop
nop
decfsz delay1,1
goto loop1
decfsz delay2,1
goto loop2
;----------------------------------------------------------------------

bcf portb,1 ; led sönüp kalmıyor burada , sürekli döngüye girip yanıp sönüyor.

;----------------gecikme -------------------------------------------
movlw d'255'
movwf delay2
loop22
movlw d'255'
movwf delay1
loop11
nop
nop
decfsz delay1,1
goto loop11
decfsz delay2,1
goto loop22
;-------------------------------------------------------------------
end

RaMu

#6
Programın ilk yazdığın gibi birebir kalsın,

aa3: ; burada kesmeden gelip ana programa devam için bir şart koydum
btfss kontrol,0
goto aa3

bu kısmın hemen altsatırına

CLRF  INTCON ;(daha doğrusu kesmeyi kapatmak için ne yüklemen gerekiyorsa yükle, ama clrf de çalışır)

ve programında  tagli nin dediği gibi
bitiği yere sonsuz döngü koy,
şuanda end den hemen önce
goto  $ yazman yeterli.

Bu iki düzeltmeyi yapınca programın çalışıyor,
isiste denedim,
led bir defa yanıp sönüyor.
Sorularınıza hızlı cevap alın: http://www.picproje.org/index.php/topic,57135.0.html

hgungor

Takrar teşekkürler tagli

Ben bu programı sürekli bu şekilde çalıştırmak istiyorum ( tabi bazı eklemeler ile), end den önce sonsuz döngü koyarsam bu istediğim olmaz, end den önce yine bir şartlı döngü koysam  mesela

a1
btfss porta,1
goto a1
goto main
end

ledi bir kere yakıp söndürdükten sonra a1 portuna bağlı bir buton olabilir, buna basınca aynı işlemleri bir daha tekrarlasa benim işime çok daha yarayacak, bunu bir iki kere denedim olmadı fakat birazdaha deneyeceğim sanırım buton için yazdığım algoritma eksikti.


Ekstradan başka bişey sormak istiyorum, bir gecikme yazalım mesela bu gecikmede 10 satır var diyelimki her satır 1us de işleniyor bu 10us eder, bunuda 100 lük bir döngüye soksak 1ms eder , bu geckmenin, tmr0 ın saydığı 1ms den eksiği yada fazlası olurmu, kesme vektöründeki programın aynısını ben yine ana programa yazabileceğimi farzedelim. ( Niyetim 1296 us lik bir gecikme yazmak)

RaMu

Sonsuz döngünün amacı şudur;
md. (mikrodenetleyici)ye yazdığın kod
tek tek senin yazdığın goto vs. ile gönderdiğin şekilde işlenir,
ve her zaman işleyeceği bir kod olmak zorundadır,
yani programı şu şekilde yazarsın

A
şunu şunu yap
B
bunu bunu yap
C
onu yap
D
yapacağın birşey yok D ye git (bu boş sonsuz döngüdür.

veya
A
şunu şunu yap
B
bunu bunu yap
C
onu yap
D
A ya git  (buda sonsuz döngüdür, ve bütün program baştan sona tekrarlanmaktadır.


Senin öncelikle programın algoritmasını yazman lazım,
algoritma kod ile yazılmaz,
bildiğin kağıt üzerinde şöyle olursa buu yap
böyle ise şunu yap,
şeklinde yazılır.

Misal
1 başla
2 maine git
3 kesme altprogramı
4 kesmeye girildi değişkenini set et ve ledi yak
5 main ledi çıkış yap, kesmeyi 1096 us için kur
6 kesme gerçekleşti mi? (kontrol değişkeni 1 oldumu?)
7 hayır > tekrar kontrol et (6 ya git)
8 evet kesme gerçekleşti
9 kesmeyi kapat
10 ledi söndür
11 sonsuza kadar burada bekle (11 e git)

Şimdi bu şekilde istediğin gibi programını kuracaksın
sonra koda çevireceksin
bu sayede mantık hatası yapmazsın.


Timer ile veya gecikme döngüsüyle yapacağın bekleme programlarının
birbirinden hiçbir farkı olmaz,
ikisininde temel taşı aynıdır, mikrodenetleyicinin clock kaynağı,
(eğer tmr a dışarıdan clock vereceksen bu durum değişir)
timerin faydası
eğer başka bir işin var ve sürekli bekleme döngüsünü çalıştıramayacak durumdaysan
timer kesmesi ile keskin bekleme süresi elde edersin
ve bu esnada program yapması gereken diğer işleri yapar,
yani bir yardımcıdır
eleman tutmuşsun sana sürekli abi 1096 us oldu haberin olsun der,
sen bunun hesabını tutmaz kendi işini yaparsan
elemanın seni uyardığında döner o işi yaparsın.
Sorularınıza hızlı cevap alın: http://www.picproje.org/index.php/topic,57135.0.html

Tagli

hgungor, aslında ulaşmaya çalıştığın sonucu, yani programın tam olarak ne yapmasını istediğini adım adım açıklarsan daha rahat ilerleme kaydederiz. Senin kod üzerinde düşünmek zor oluyor benim için, çünkü benim soruna yaklaşımım muhtemelen daha farklı olacaktır. Aynı anda iki farklı şekilde düşünemiyorum.

Normalde her komut 1 çevrim sürer ama istisnaları var. PC'yi (program counter) değiştiren komutlar (goto, return gibi) 2 çevrim sürer. Aslında işin doğrusu, hiç gecikme kodu yazmayıp, zaman gecikmelerini tamamen timer ile çözmektir.

Şimdi baştan alalım: Ulaşmaya çalıştığın sonuç, 1296 us sönük, 65 ms yanık kalan ve bunu sürekli tekrarlayan bir LED mi? 1296 us 1, 1296 us 0 olan bir sinyali ölçmekten bahsetmişsin. Bu sinyalin nesini ölçtüğünü anlamadım. Frekansı ve iş zamanı (duty cycle) zaten belli. Genlik de belli. Kafam karıştı.

Dediğim gibi, tam olarak ne yapmak istediğini anlat, ben de bir yol haritası çizeyim.
Gökçe Tağlıoğlu

hgungor

Ramu ve Tagli cevaplarınız için çok teşekkür ederim, aslında benim program işinde biraz acemi olmama bu tür sorunların üstesinden gelemememe sebep oluyor sanırım. Şimdi sizin yazdıklarınız üzerine aklımda bir iki fikir oluştu, Ramunun dediği gibi programın tamamını yazınca programı sonsuz bir döngüye sokmak işe yarayabilir.Benim bu konuda çıkmaza girmem sanırım programın tamamının beşte birini öncelikle çalıştırıp sonraki aşamalara geçmek oldu, ilk kısmıda sonsuz döngüye sokmadım tabi.

Benim yapmak istediğim aslında gelen 15 adet herzaman aynı olmayan 1 ve 0 ları tespit edebilmek.

Bu bilgiler ışığı altında ben bir iki gün denemeler yapayım sonrasında tekrardan durumu bildiririm.

Herşey için teşekkürler arkadaşlar.

hgungor

Merhaba arkadaşlar
Çalışmalara başladımda, şöyle bir algoritma oluşturdum  acaba düşündüğüm gibi çalışırmı

1296us lik bir gecikmeye ihtiyacım vardı , 4mhz kristali olan bir pikin 1us sürede bir komut işlettiğini okumuştum, bazı komutlar 2us olabiliyordu.

movlw d'255'
movwf sayıcı
a:
nop 
nop 
nop 
decfsz sayıcı,1
goto a

burada her döngüde 3 adet nop komutu 1 adet de decfsz komutu ve bir adetde goto komutu var toplamda 5 komut yapıyor yani 5us, bu döngüyü 255 defa tekrarlarsak 1275us eder , sanırım döngüden önceki bir iki komut daha var onlarda 2-3us katarsa gecikmeye 1280us eder ve bu benim işimi görür.

Acaba bu algoritma bu şekilde çalışırmı yani 1280us gecikme olurmu, nop komutlarını pic gerçekten komut olarak görüp 1us demi işliyor ?

Benzer bir algoritma öneriside önermek isterseniz çok sevinirim daha çok uygulama ,bu işi öğrenmemde işe yarayacaktır.

Tagli

Kabaca 1536 çevrim yapar. 3 tane nop, 1 tane defsz (atlama yapmazsa 1 çevrim sürer), 1 tane goto da 2 çevrim. Döngü başına 6 çevrim yapıyor. 256 * 6 = 1536. Dediğim gibi, kabaca hesapladım.
Gökçe Tağlıoğlu

hgungor

Tamamdır Tagli denmelerde nopları 2 ye düşürdüm yaklaşık olarak 1280us gecikme yapıyor olmalı şimdilik benim işimi görüyor program istediğim gibi çalışıyor. Bundan sonra programı ileriki safhalara taşıyabilirim, bundan sonra pek sıkıntı yaşamayacağım gibi geliyor.

Tagli ve Ramu ikinizede çok teşekkür ederim, sayenizde bilmediğim birkaç şey öğrendim, umarım konuyu izleyenlere de faydalı olmuştur.