CCS ile ilgili bir HATA
Diyelimki siz Interrupt_RB ile portB RB4-7 de oluşan bir değişiklikte
RB1 pinindeki LED i yakıyorsunuz bunu bır ISR ile gerçekleştirdiğinizde
gayet güzel çalışıyor ve Ana Programda ise LED tekrar sönuyor ;)
Fakat LED i PortA RA1 bağlandığında program bir türlü ISR i terketmiyor
ve Ana Programda ise LED sönmeli fakat sönmüyor daha iyi anlanması için
kodları ekliyorum
#include "interrupt.h"
#define LED PIN_B1 // sorun burada bunu A1 yaptığınızda Çalışmıyor
#int_RB // Interrupt
LED_YAK()
{
disable_interrupts(GLOBAL);
output_high(LED);
delay_ms(500);
enable_interrupts(GLOBAL);
}
void main() {
set_tris_a(0b00000);
set_tris_b(0b00110000); // RB4 ve RB5 giris
setup_counters(RTCC_INTERNAL,RTCC_DIV_2);
ext_int_edge(L_TO_H);
enable_interrupts(INT_RB);
enable_interrupts(GLOBAL);
while (1)
{
output_low(LED); //LED söndür
}
}
Bununla ilgili önerileriniz Acaba bu CCS bir hatası olabilirmi??
Saygılarımla
elbette olmaz pic ilk çalışmada PORTA'yı analog atar bunu digital'e çevirmen gerekli
setup_adc_ports(NO_ANALOGS);
setup_adc(ADC_OFF);
ayrıca ISR içinden diğer ISR'ler yada GLOBAL kapatılıp açılmaz.
@Ahmetu cevap verdiğin için teşekkürler
devrede kullanılan PIC 16f84, bildiğim kadarıyla bunlarda bütün portlar zaten digital olarak çalışmakta.
ISR içinde olan global açmayı sildim sonuç yine değişmedi
Yanlış anlaşılmasın program ilk çalıştığında led sönük sonra ISR gereği Led
yanıyor fakat sonra ISRden çıkıp Led sönmüyor halbuki bu ccs c tarafından otomatik yapıldığı yazılıyor fakat bu portA da olmuyor
İsteyen arkadaşlar deneyebilirler bence bu ccs den kaynaklanıyor
acaba INTCON registere manual ulaşabilinirmi :roll: :roll:
LST dosyasındanda pek bir şey belli olmuyor
Örneklerdede hep portB kullanılmış bu durumda program zaten çalışıyor
portA da ise durum farklı ISR den normal programa bir türlü gidilmiyor
Arkadaşlar bu konuda görüşlerinizi bekliyorum
saygılarımla
Program asm halini de koyabilirmisin? C derleyici int rutinini terkederken neler yapiyor oran bakariz.
INTCON regi int dan cikarken yeniden init etmeyi dene.
(INT rutini icinde 500 ms bekleme yapmak bana biraz ters geliyor.)
programı denedim dediğiniz gibi yapıyor. rb intterruptu yerine ext interruptu deneyince bir sorun olmadığını gördüm. eğer rb'yi kullanmak zorunda değilseniz ext (b0) interruptunu kullanabilirsiniz. zaten bu tip sorunlar ccs için olağan.
açıkçası kim ne derse desin ccs amatör bir compiler zaten c ilede çokta yakından alakası yok. adamlar c adı altında yeni bir dil yapmışlar sanki. zaten ccs'nin kendi forumunda da dalga geçiyorlardı eğer yeni bir optimizasyon yapıldı diye duyuru yapılırsa kesin bir-iki gün sonra yeni optimizasyon için düzeltme yapıldığı haberi geliyor diye.
herhalde en sık update'i çıkan compiler budur.
tabi benim canımı asıl sıkan şey büyük bir projenin tam ortasında olmayacak hatalar yapmaya başlaması ve sonra işin tamamen çığrından çıkması. en başta işler güzel giderken proje büyüdükçe sorunlar çıkarmaya başladı. bundan dolayı bir ay yeni compiler aramakla geçti. asıl önemlisi bir sürü rezillik çektim. tam projenin sonuna geldik bitti bitiyor derken herkes birşey beklerken kendinizi bu halde bulduğunuzu düşünün.
şimdi microchip c18 kullanıyorum ve çok memnunum eğer gerçek c tadı yaşamak istiyorsanız kesinlikle tavsiye ederim. ayrıca hiç sorun yaşamadım şimdiye kadar. tabi sadece 18 serisi picleri destekliyor. aslında bence 16 serisi picler piyasadan kalkmalı artık ama.
Alıntı yapılan: "bunalmis"(INT rutini icinde 500 ms bekleme yapmak bana biraz ters geliyor.)
doğru usta sorunda oradan zaten delay esnasında sürekli INT aktif oluyor
16f84 kullanığınızı bilmiyordum neyse kurallara uyunca herşey mümkün işte çalışan kod;
#include <16F84.h>
#fuses NOWDT,HS,NOPUT,NOPROTECT
#use delay(clock=4000000,RESTART_WDT)
#define LED PIN_A1
BOOLEAN ledyak=FALSE;
void ledkontrol() {
if (ledyak)
{
ledyak = FALSE;
output_high(LED); //LED yak
delay_ms(500);
}
output_low(LED); //LED söndür
}
#int_RB
void RB_ISR() {
if (input_b() && 15)
ledyak = TRUE;
else
ledyak = FALSE;
ledkontrol();
}
void main() {
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
set_tris_a(0);
set_tris_b(0b00110000); // RB4 ve RB5 giris
ext_int_edge(L_TO_H);
enable_interrupts(INT_RB);
enable_interrupts(GLOBAL);
while(1);
}
Arkadaşım,
interrupt rutininde işin bitince flagi resetleyerek çıkman lazım. Yoksa tam çıkıyorum derken flag set edildiği için tekrar interrupta dönersin. Yani sonsuz döngüye girmişsin.
Şunu programına ekle.
#bit rbif=0x8b.0
interruptın sonunda
rbif=0;
CCS bana kalırsa son derece mükemmel bir dil. ANSI C olmamış olması beni etkilemiyor. 877 üzerinde %98 kod alanına sığacak son derece karmaşık programları bile mükemmel bir şekilde derliyor. Optimizasyonu harika. Tek eksikliği program parçalarını 2 K page alanına tam sığdırmaya çalışıyor. Bunu yapamadığında out of rom hatası veriyor. Bunu da altprogramların bazılarının başına "#separate" koyarak çözüyorum. Stack kritik olunca biraz tecrübe ile sorunu başka şekilde çözüyorum.
CCS en mükemmeli demiyorum ama neyi nasıl yaptığını bilirseniz çok mükemmeldir derim.
Alıntı yapılan: "Petek"CCS bana kalırsa son derece mükemmel bir dil.
ben yazdıklarım başıma gelmeden önce 2 seneden fazla ccs kullandım ve aynen böyle düşünüyordum. ccs ile 10'a yakın büyük sayılabilecek proje yaptım küçükleri saymıyorum. fakat bu söylediklerim başıma gelince ve c18 kullanmaya başlayınca aklım başıma geldi. insan iyisini görmeden kötünün ne olduğunu anlayamıyor. sizde zor yoldan öğrenmeyin derim burada tecrübe varken. zaten bu olaylar başıma gelince yaptığım araştırmalarda dünyada bir çok kişinin benim gibi düşündüğünüde gördüm. bu arada benim söylediğim şey ccs'nin amatör olduğu prof. olarak kullanmıyacak, amacı ufak tefek işler yapmak olan kimselere lafım yok. (yanlış anlaşılmasın bu yazdıklarım size değil sayın petek ben genel anlamda yazıyorum)
ccs küçük projeler için başarılı ufak tefek işlerde hala kullanıyorum fakat büyük işlere asla girmem.
interruptun başında flagı reset etmenize gerek yok çünkü 16f84'te int içerisinde yeni int gelirse işlemler bitirlmeden çıkılmaz. sonundada resetlemenize gerek yok çünkü ccs bunu otomatik yapıyor zaten (lst dosyasına bakın.)
ayrıca int içinde delay yapmak pratikte kesinlikle kullanılacak bir şey değil int rutinleri olabildiğince kısa olmalıdır. çünkü int içindeyken yeni int gelirse uygun flag set edilir ve mevcut int'in işini bitirmesi beklenir. işi biter bitmez yeni int gerçekleştirilir. fakat işi bitmeden önce bir int daha gelirse bu durumda flag zaten set olduğundan bu yeni int kaybolacaktır.
ahmetu hocam int içinde delay olmasından kaynaklandığını söylemişsiniz sorunun. halbuki yazdığınız program da int içinde delay yapıyor. int içinden çağırdığınız fonksiyon yine int içinde sayılır.
bundan da öte ccs'de böyle basit programlarda trislerle uğraşmanıza gerek yok. siz output_high dediğiniz de yazdığınız pinin trisi otomatik olarak output yapılır. bunu kapatmak için özellikle bir komut yazmanız lazım (fast io). birde ext_int_edge fonksiyonu rb0 interruptunun hangi kenarda gerçekleşeceğini belirler rb interruptu ile alakası yoktur.
@Ahmetu verdiğin kod çalışıyor fakat RB4 ve RB5 aynı anda Low olduğunda ISRe atlama yapmıyor dolayısıyla ISR tam olarak görev yapmıyor uğraştığın ve yazdığın cevaplar için çok teşekkürler fakat problem hala çözülmüş değil
@Petek yazdığın işlemi yaptım sonuç degişmedi ıntcon.0 ISRden sonra değişmiyor denedim. Tam programı verebilirmisin ayrıca cevabın için
teşekkürler :idea: :idea:
CCS C böylesine ufak programda sorun çıkarmasına pek anlam veremedim belkide Erkan gench haklı
Arkadaşlar bu bir Bug mu sizce CCs C programlayan arkadaşlar bunu sadece benmi farkettim yoksa sizde böyle sorunlar yaşadınızmı ??
:cry: :cry:
Görüşlerinizi bekliyorum
saygılarımla
programın olması gereken şekli şöyle:
#define LED PIN_a1 // sorun burada bunu A1 yaptığınızda Çalışmıyor
int1 ledyak=0;
#int_ext // Interrupt
LED_YAK()
{
ledyak=1;
}
void main() {
setup_counters(RTCC_INTERNAL,RTCC_DIV_2);
enable_interrupts(INT_ext);
enable_interrupts(GLOBAL);
while (1)
{
output_high(led);
if(ledyak)
{
output_low(LED); //LED söndür
delay_ms(500);
ledyak=0;
}
}
}
fakat bu int_ext için yazılmış hali ayrıca normalde yanan led butona basınca söndürülüyor. rb int'ini daha önce hiç kullanmadım. açıkçası hiç gereği olmadı. int'i rb yapınca kod çalışmıyor neden olduğunu bilmiyorum belki ccs'den belkide benim rb int'i konusundaki tecrübesizliğimden. fakat interrupt kullanma mantığınız bu olmalı yani int oldukça kısa olmalı uzun işleri ana programa yaptırmalısınız.
Alıntı yapılan: "Erkan Gench"Alıntı yapılan: "Petek"CCS bana kalırsa son derece mükemmel bir dil.
ben yazdıklarım başıma gelmeden önce 2 seneden fazla ccs kullandım ve aynen böyle düşünüyordum. ccs ile 10'a yakın büyük sayılabilecek proje yaptım küçükleri saymıyorum. fakat bu söylediklerim başıma gelince ve c18 kullanmaya başlayınca aklım başıma geldi. insan iyisini görmeden kötünün ne olduğunu anlayamıyor. sizde zor yoldan öğrenmeyin derim burada tecrübe varken. zaten bu olaylar başıma gelince yaptığım araştırmalarda dünyada bir çok kişinin benim gibi düşündüğünüde gördüm. bu arada benim söylediğim şey ccs'nin amatör olduğu prof. olarak kullanmıyacak, amacı ufak tefek işler yapmak olan kimselere lafım yok. (yanlış anlaşılmasın bu yazdıklarım size değil sayın petek ben genel anlamda yazıyorum)
ccs küçük projeler için başarılı ufak tefek işlerde hala kullanıyorum fakat büyük işlere asla girmem.
interruptun başında flagı reset etmenize gerek yok çünkü 16f84'te int içerisinde yeni int gelirse işlemler bitirlmeden çıkılmaz. sonundada resetlemenize gerek yok çünkü ccs bunu otomatik yapıyor zaten (lst dosyasına bakın.)
Erkan Bey, 2 yıl kadar Jal ile programlamadan sonra CCS gözüme son derece mükemmel göründü. Jal de pek çok şeyi assembler da yapıyormuşsunuz gibi yapmanız gerekiyor. Bu alışkanlıktan dolayı olsa gerek flagi resetlemek gerektiğinden bahsetmiştim. Sonradan farkına vardım tabi. CCS donanım hakkında çok fazla bilgisi olmayanlar için geliştirilmiş ve pek çok şeyi otomatik hallediyor. Geçenlerde 12F675 için program yazmıştım. OSCCAL değerini atamak için kodlar ekledim. Sonradan LST den baktım ki CCS zaten onu (ve portu analog yada dijital nasıl kullanmış isek) ona göre kodları eklemiş. IO portları için de oldukça kullanışlı compiler direktifleri var. Hata yapmak gerçekten zor. Eski versiyonlarının birinde stack overflow olmuş fakat hata vermemiş. Program 0 stack seviyesine dönmemişti. Onu da başka türlü halletmiştim. Ama neredeyse her gün yeni versiyon çıkarttıkları için bu sorunların hallolduğunu sanıyorum. Bir versiyon sonrasında bile optimizasyonda baya iyileştirmeler görmüştüm. Out of rom hatasını hiç sevmedim. Değişik yollardan çözüyorum ama açık söylemek gerekirse oldukça saçma bir mantıkla bu hata çıkıyor. Düzeltirler diye bekledim ama bu ilk versiyonlarda bile var olan birşeymiş. Gülün dikeni gibi yani.
Erkan Bey, sizin CCS de karşılaştığınız sorunlar neler paylaşırsanız sevinirim.
C18 derleyicisi bende de var (updateleri de var). Sorun elimde numune 2 adet 452 ve 2 adet 242 var. Bunlarla henüz ciddi anlamda uğraşamadım. Elimde daha önceden yaptığım projeler vardı ve elimdeki eski işlemcileri de eritmem gerekiyordu. O nedenle CCS de devam ediyorum. 18 serisine geçmeyi çok istiyorum ama biraz da maliyetleri düşsün diye bekliyorum. Yoksa benim en büyük sıkıntım 16 serisindeki yetersiz stack alanı. 8 stack alanında çok fazla menü derinliği oluşturamıyorum. Menünün en derin kısımlarında ( ne güzel bir tabir oldu :) sub program kullanamıyorum. interrupt rutinlerinde stack tüketecek işlem yapamıyorum. LCD ve i2c rutinlerini bile 3 stack götürecek şekilde yeniden düzenledim. Yani baya göbek attım.
Kalman, Programı ISIS üzerinde debug ederek hatanın ne olduğu bulunabilirsin. Coff dosyasını ISISte yüklemen yeterli. Debug edip, adım adım programı çalıştır. Program akışını izle nerede takıldığını görürsün.
Tartışmayı alevlendirmek için int içerisindeki kod kısa olmalı kesinlikle delay olmamalıya karşı çıkayım.
mesela rs232 interrupt ı düşünün, bir devre var ve bu mesela triyak ile lamba kontrol ediyor, normalde hiç uart ile uğraşmıyor ve zero cross a göre lambayı tetikliyor falan...
ama uart dan veri geldiğinde bir interrupt oluşuyor ve program int alt programına gidiyor, orada delay kullanarak veri alış verişi yapıyor, gelen verilerin doğruluğunu kontrol ederek karşı tarafa okey sinyali yolluyor.
bu şekilde çalışan yüzlerce uygulama var ve aslında buradaki sözünüz doğru ama onu şu şekilde değiştirmeliyiz diye düşünüyorum;
Alıntı Yapayrıca int içinde delay yapmak pratikte kesinlikle kullanılacak bir şey değil int rutinleri olabildiğince kısa olmalıdır. çünkü int içindeyken yeni int gelirse uygun flag set edilir ve mevcut int'in işini bitirmesi beklenir.
Eğer int alt programı içerisinde int i kapatıp, program bitiminde tekrar açmıyor ise int kodu oldukça kısa olmalıdır yoksa isr içerisinde iken yeni bir int geldiğinde o veri kaybolacaktır.
Bu şekilde olursa daha iyi olacağı kanısındayım.
CCS çok iyi değildir demişsiniz, peki hangisi gerçekten iyidir (asm hariç)?
Alıntı yapılan: "SpeedyX"
Eğer int alt programı içerisinde int i kapatıp, program bitiminde tekrar açmıyor ise int kodu oldukça kısa olmalıdır yoksa isr içerisinde iken yeni bir int geldiğinde o veri kaybolacaktır.
Bu şekilde olursa daha iyi olacağı kanısındayım.
CCS çok iyi değildir demişsiniz, peki hangisi gerçekten iyidir (asm hariç)?
Hocam, int geldiğinde interrupta gidiyorsun ya, zaten o arada GIE biti 0 oluyor. Assemblerdan hatırla, interrupt dönüşü retie değil mi. Bu global interruptı enable yapıyor. Şunu derseniz katılırım, interruptan çıkmadan önce set edilen flag resetlenmeli. Bunu da zaten CCS (Default yada Global interruptan biri hariç) hepsi için yapıyor. Öyle değil mi?
İnterrupta istenildiği kadar kod yazılabileceğini ben de uygulamalarımdan biliyorum. Hatta bir uygulamada interrupt içerisinden subroutine bile çağırmıştım. Yeterki worst case stack kullanımı sınırını aşmasın.
Alıntı yapılan: "Petek"Hocam, int geldiğinde interrupta gidiyorsun ya, zaten o arada GIE biti 0 oluyor. Assemblerdan hatırla, interrupt dönüşü retie değil mi. Bu global interruptı enable yapıyor.
Gie otomatik olarak 0 mı oluyor?
Ben onu olmuyor diye biliyorum, mesela şöyle bir program olsun:
#include <16F84.h>
#use delay(clock=3276800,RESTART_WDT)
#fuses NOWDT,XT,NOPUT,NOPROTECT
#include "lcd.c"
int x;
#int_rtcc
void RTCC_ISR() {
x++;
if(x==200) x=0;
}
}
void main() {
setup_counters(RTCC_INTERNAL,rtcc_div_8);
enable_interrupts(int_rtcc);
enable_interrupts(global);
set_tris_b(0x00);
lcd_init();
lcd_gotoxy(1,1);
Lcd_putc("\fSpeedyX");
delay_ms(2000);
while(true)
{
lcd_gotoxy(1,2);
Lcd_putc("x=");
printf(lcd_putc,"S:%02lu",x);
delay_cycles(1);
}
}
bu şekliyle çalışacaktır, birde şu şekilde değiştirelim:
#int_rtcc
void RTCC_ISR() {
disable_interrupts(global);
x++;
delay_ms(5000); // 5 Saniye bekle
if(x==200) x=0;
enable_interrupts(global);
}
}
bana göre bu şekliylede çalışacaktır fakat;
#int_rtcc
void RTCC_ISR() {
x++;
delay_ms(5000); // 5 Saniye bekle
if(x==200) x=0;
}
}
yine bana göre şu şekliyle düzgün çalışmaz, iç içe interrupt alır.
Eğer ISR içerisinde gie otomatik olarak kapatılıp, çıkışta aktif yapılıyorsa yeni birşey daha öğrenmiş olurum.
@Arkadaşlar verdiginiz cevaplardan dolayı herkese teşekkürler :lol:
Fakat tabiri caizse eskilerin dediği gibi bir arpa boyu yol alamadık bu konuda :lol: :lol:
@erkan coff ile denedim önce ISR e gidiliyor fakat sonra ISR terk edilmiyor PİC CPU REGISTER e baktığımda INTCON Registerin ilk biti
sıfırlanamıyor veya resetlenemiyor Petek in RBıf=0 öneriside bir şey değiştirmedi tek çare belkide ISR in içinde bunu ASM ile yapmak
ama o haldede ccs in avantajı yok olmazmı ???
C18 sizce tek çözümmü aslında CCS C ide bayağı beyenmiştim neyse
Büyük ustalardanda henüz bir cevap yok ;) ;)
Öğrenilmesi kolay denilen bir derleyicinin hatalı olduğu halde tavsiye edilmesi bence doğru değil ve bu açıkca belirtilmesi gerekir
Ufukta C18 gözüküyor 8) 8)
herkese başarılar
saygılarımla
Alıntı yapılan: "SpeedyX"Tartışmayı alevlendirmek için int içerisindeki kod kısa olmalı kesinlikle delay olmamalıya karşı çıkayım.
Merhaba benim söylediğim şey tabiki birden fazla int'in kullanıldığı programlarda geçerli veya tek int kullanılıyorsa int'in her gelişini takip etmenin önemli olduğu programlarda.
İyi ama böyle devrelerde de bu bekleme işini int içinden yapmak zorunda değilsiniz ki. int içerisinde bir flag set olur ana program bunun üzerine gereken yere dallanarak işini yapar. sizin dediğiniz şekilde de iş halledilebilir olsada bu mantığa alışmak bence en iyisi çünkü büyük işlerin altına girdiğinizde bu tür alışkanlıklar sizi baş ağrılarından kurtarıyor.
Alıntı yapılan: "SpeedyX"
CCS çok iyi değildir demişsiniz, peki hangisi gerçekten iyidir (asm hariç)?
bildiğim şey ccs profesyonel bir program değil sık sık hata yapmasını bekleyebilirsiniz, c18 ise çok güzel ama 16 serisi için kullanamazsınız. peki 16 serisi için hangisi iyi derseniz bilmiyorum. hi-tech iyi gibi duruyor ama hiç kullanmadım bilmiyorum.
gie biti int içine girildiğinde otomatik olarak reset olur retfie komutu ilede otomatik olarak set olur(16f84a datasheet s.29). int içerisinde gie'yi kapatmanızın bir anlamı yok fakat açmanız tehlikeli olabilir çünkü int içinden çıkılmadan yeni int gelme ihtimali var.
petek dediğim gibi bende uzun zaman ccs kullandım ve çok memnundum taki büyük bir işte beni rezil edene kadar. ama şunuda söyleyim ben hala küçük işlerde ccs kullanıyorum. ccs gerçekten çok kolay çok kullanışlı ama profesyonel değil sorun burada.
ben daha önce stack problemi ile hiç karşılaşmadım sorun sizin program yazma stilinizden kaynaklanıyor olabilirmi acaba?
karşılaştığım sorunlara gelince birincisi yukarıda anlattıklarım. ikincisi ccs ile pic'e ve yazdığınız programa tam anlamıyla hakim olmanızın zorluğu (örneğin ccs her interrupta girdiğinizde bütün registerleri kaydeder ve sizin int rutininiz 2 bayt bile olsa toplamda bu 30-40 baytı geçer buna müdahele edemiyorsunuz) tabi işler kolaylaştıkça hakimiyetin zorlaşması doğal bir şey. üçüncüsü pointer kullanımındaki sıkıntılar (picin flash'ında bir string yaparsanız buna pointer ile ulaşamıyorsunuz x = TABLE [5]; bu oluyor ama bu olmuyor ptr = &TABLE
;), sonra mevcut rtos'lardan (işletim sistemi) ccs için olanını ben hiç görmedim ama c18 için çok var. ve daha bir çok şey tabi bunlar kötü tarafları iyi taraflarının listesi daha uzun.
şunuda belirteyim ki c18 biraz zordur özellikle ccs'nin rahatlığına alıştıktan sonra fakat buna karşılık alacağınız verim çok daha fazla.
18 serisinin maliyetinin yüksek olması talebin azlığından kaynaklanıyor yoksa gerçekte aradaki fiyat farkı çok az. aslında herkes 16 serisini bırakıp 18'e geçse fiyatta ucuzlar bulmakta kolaylaşır. zaten 18'i biraz kullanınca insanın bir daha 16larla uğraşası gelmiyor çünkü çok fark var.
bu arada kalman o resimdeki elf'mi ork'mu ben çözemedim ikisinede benziyor yoksa karıştırmışlarmı :)
Alıntı yapılan: "SpeedyX"
#int_rtcc
void RTCC_ISR() {
x++;
delay_ms(5000); // 5 Saniye bekle
if(x==200) x=0;
}
}
yine bana göre şu şekliyle düzgün çalışmaz, iç içe interrupt alır.
Eğer ISR içerisinde gie otomatik olarak kapatılıp, çıkışta aktif yapılıyorsa yeni birşey daha öğrenmiş olurum.
Bu şekilde çalışmaz. Nedeni ise 2000 ms beklediğinde timer interrupt flagi set edilmiş olur. İnterruptan çıktığın anda ise o flag set edildiği için tekrar interrupta döner. Ama interrupt rutininin sonunda timerflagini resetlersen çıkışta set edilmiş flag olmadığı için normal programa dönersin.
Teşekkürler arkadaşlar, birşey daha öğrenmiş olduk(GIE).
CCS içinde iyi düşüncelerim vardı, bunlar biraz sarsıldı. CCS ile şimdiye kadar basit sayılabilecek projeler yaptım, assembly ile 6000 satırlık programlar yazdım hiç sorunsuz çalıştılar, kolaylık ve C merakımdan dolayı CCS ile devam etmeye karar verdim ama görüyorumki onun hakkında kötü düşünceler var. Bakalım, daha rezil olmadım hiç ama rezil olma ihtimalinede hazırlıklıyım artık. :)
Şöyle diyebilirmiyiz; ASM>C18>CCS>PBP
Saygılar.
Alıntı yapılan: "Erkan Gench"
ben daha önce stack problemi ile hiç karşılaşmadım sorun sizin program yazma stilinizden kaynaklanıyor olabilirmi acaba?
Program yazma stilimden kaynaklanamaz, çünkü alt programdan döndüğünde, başka bir alt programın ortasından başlaması ya page yada stack probleminden kaynaklanır. Çözümü alt programların yerlerini değiştirerek bulmuştum.
Alıntı Yap
karşılaştığım sorunlara gelince birincisi yukarıda anlattıklarım. ikincisi ccs ile pic'e ve yazdığınız programa tam anlamıyla hakim olmanızın zorluğu (örneğin ccs her interrupta girdiğinizde bütün registerleri kaydeder ve sizin int rutininiz 2 bayt bile olsa toplamda bu 30-40 baytı geçer buna müdahele edemiyorsunuz) tabi işler kolaylaştıkça hakimiyetin zorlaşması doğal bir şey.
Evet. Şu an yaptığım programda context saving 30-40 adım götürüyor. Bu adımlar kadar timer setinginden eksilterek istediğim zamanı elde ediyorum. abi bu sorun 16 serisi işlemcilerin mimarisinden kaynaklanıyor. En düşük kapasiteli 8051 serisinde bile 11 vektörel interrupt var. Timer için ayrı, port değişimi için ayrı, kılı için, tüyü için ayrı interruptlar var. 16 serisi piclerde tek interrupt olduğu için, kullanıcı kolay ayırt edebilsin diye CCS de interrupt ta her flagi tek tek kontrol ederek ilgili interrupt rutinine dallanıyor. Bu da tabi interruptta gereksiz zaman kayıplarına neden oluyor. Ben birden fazla interrupta gerek duymadığım için (uart haberleşmesini ana programda rcif, txif polling yaparak izliyorum) CCSnin stantart yöntemini kullandım. Çok hassas iş yapacak olsam #INT_GLOBAL seçeneğini seçerim. Context savingler için ayrı alt programlar yapar, interruptta çağırırım. Bir defa çağırılacağı için CCS bunu alt program olarak değil, normal kod içerisine yerleştiriyor. Amacım interrupt içerisinde bir bit set edip çıkmak ise zaten ona da gerek kalmaz (bitset bit clear status registerinin içeriğini, wregi, fsr yi, pclathi değiştirmediği için).
Alıntı Yap
üçüncüsü pointer kullanımındaki sıkıntılar (picin flash'ında bir string yaparsanız buna pointer ile ulaşamıyorsunuz x = TABLE [5]; bu oluyor ama bu olmuyor ptr = &TABLE ;),
Bunda haklısınız. Bir sorun da string içerisinde 0 rakamını yerleştiremiyorsunuz. 0 ı görünce string sonu olarak görüyor. Oysa LCD deki ilk 8 baytta kendim karakter tanımlıyorum ve 0. bayttaki karakteri bastırtamıyorum.
Jal de flash_get, flash_put komutları vardı. Benzeri CCS de de var. Bunlarla ROM alanında istenilen şeyler yapılabilir ama tabi standart C den ayrılıyorsunuz. Bu yöntemle bir adrese 2 karakter sığdırılabiliyor. 14 bit üzerinde 2 karakter sığdırılabiliyor. Ama bu da zahmetli bir iş. Bir ara (sanıyorum) CCS'nin bunu otomatik yaptığını okumuştum.
Alıntı Yap
sonra mevcut rtos'lardan (işletim sistemi) ccs için olanını ben hiç görmedim ama c18 için çok var. ve daha bir çok şey tabi bunlar kötü tarafları iyi taraflarının listesi daha uzun.
RTOS lar ile hiç çalışmadım. O nedenle de tam olarak bir yorum veremeyeceğim. CCS'nin bir dezavantajı da object kod üretmiyor. O nedenle object kodlu yabancı sub programlar CCS rutinleri ile birlikte link edilemiyor. CC5X te bu var.
Alıntı Yap
şunuda belirteyim ki c18 biraz zordur özellikle ccs'nin rahatlığına alıştıktan sonra fakat buna karşılık alacağınız verim çok daha fazla.
18 serisinin maliyetinin yüksek olması talebin azlığından kaynaklanıyor yoksa gerçekte aradaki fiyat farkı çok az. aslında herkes 16 serisini bırakıp 18'e geçse fiyatta ucuzlar bulmakta kolaylaşır. zaten 18'i biraz kullanınca insanın bir daha 16larla uğraşası gelmiyor çünkü çok fark var.
Bu görüşlerinize katılıyorum. Ama 16F84 üzerinde (video çıkışı ve 2 oyun konsolü bağlı) tetris ve tenis oyun programı yapıldığına göre 16 serisinde hala çok kabiliyet var. Yeterki bizde kodlamada optimizasyon alışkanlığı gelişsin.
CCS de sıkıntı da şurada gördüm. Diyelim 16 bit büyüklüğünde bir structure tanımlayacaksınız. Bunun ilk 5 biti integer olsun. Sonraki 4 biti integer olsun diyemiyorsunuz. Çünkü 8 biti aştınız. 5 bitlik tanımdan sonra en fazla 3 bitlik bir değişken tanımlayabiliyorsunuz.
Bir dezavantaj da 24 bitlik değişken tanımlayamıyor olmamız. Tabi bunun avantaj ve dezavantajları var. Bütün programda 32 bitlik aritmetik yapmıyor iseniz 24 bit tanımlar aritmetik işlemlerde hem hız hem boyut açısından avantaj sağlıyor. Ama karışık kullanıyorsanız bu sefer hem 32 bit için hem 24 bit için aritmetik işlem rutinleri programa yerleşiyor ve bu da program alanınızın kapasitesini arttırıyor.
Alıntı yapılan: "kalman"
Öğrenilmesi kolay denilen bir derleyicinin hatalı olduğu halde tavsiye edilmesi bence doğru değil ve bu açıkca belirtilmesi gerekir
Buna kesinlikle katılmıyorum. Her derleyicide bug olabilir ve sonraki versiyonlarda bu giderilir. Ben ticari olarak pazarlanan LAHEY fortran derleyicisinde bile bug bulmuştum. Aynı program LAHEY f77 de farklı, Linux altındaki g77 farklı sonuç veriyordu. İlginç tir g77 doğru hesaplamıştı (IBM Risc6000 ile kontrol etmiştim).
Senin programın için CCS nin neresi hatalı olduğunu söyleyebilirmisiniz? Programın tamamını ve ISIS dosyasını biryere yükleyin, ben bakıp size sizin hatanız göstereyim.
Alıntı yapılan: "Petek"sorun 16 serisi işlemcilerin mimarisinden kaynaklanıyor.
buradaki context saving ile interrupt geldiğinde hangisinin servis göreceğinin belirlenmesi ayrı bir şey. int geldiğinde hangisine dallanılmasına karar verme ihtiyacı pic'lerin genelinde var
Fakat benim bahsettiğim ve sizinde değindiğiniz context saving olayı sizin int içine girdiğinizde yapacağınız işlemler eğer register'lardan bazılarını etkileyecekse bunların int'e girmeden kayıt edilmesi ve çıkışta tekrar geri yüklenmesi olayı.
aslında normalde siz int rutininizi yazarsınız int içerisinde etkilenen reg'leri lst dosyasından bulursunuz ve bunları (eğer otomatik save edilmiyorsa) kaydedersiniz ve çıkışta geri yüklersiniz. fakat ccs böyle yapmıyor sizin int içinde hiç bir reg etkilenmese bile hepsini kaydediyor ve çıkışta geri yüklüyor. siz aman int kısa olsun fazla yer kaplamasın diyorken bir sürü zaman kaybediyorsunuz. aslında 16 serisinde bu o kadar büyük bir kodda üretmiyor (nispeten) fakat 18 serisine gelince ciddi miktarda gereksiz zaman kaybına neden oluyor.
buraya dikkat ederseniz aslında ccs'nin böyle yapması hobi amaçlı kullanıcılara en uygun şey çünkü kimse her bir int yazdığında lst dosyasını kurcalayıp zahmete girmek istemez bunu ccs'nin yapması büyük kolaylık fakat iş profesyonel olunca ve mikro saniyeler önem kazanınca dediğim şey anlaşılmaya başlıyor sanırım. bu zaten bir örnek sadece ve ileride bunu düzeltmeleri fikrimi değiştiremez çünkü compiler'ın mantığı belli.
ancak bu anlattıklarım ccs düşmanlığı olarak algılanmasın :) benim amacım büyük sayılabilecek işlere ccs ile girip sıkıntı yaşamamanızı istiyor olmam yoksa ben ccs'yi kullanabiliyor olmaktan memnunum.
bu arada string içerisine 0 yerleştirebilirsiniz fakat bu diziyi karakter dizisi olarak kullanamazsınız çünkü karakter dizilerinde 0 rakamı (aslında NULL karakteri) dizi sonunu gösterir. bu c'nin bir özelliği ayrıca çok kolaylık sağlayan uygulamaları var.
Alıntı yapılan: "Erkan Gench"Alıntı yapılan: "Petek"sorun 16 serisi işlemcilerin mimarisinden kaynaklanıyor.
buradaki context saving ile interrupt geldiğinde hangisinin servis göreceğinin belirlenmesi ayrı bir şey. int geldiğinde hangisine dallanılmasına karar verme ihtiyacı pic'lerin genelinde var
Fakat benim bahsettiğim ve sizinde değindiğiniz context saving olayı sizin int içine girdiğinizde yapacağınız işlemler eğer register'lardan bazılarını etkileyecekse bunların int'e girmeden kayıt edilmesi ve çıkışta tekrar geri yüklenmesi olayı.
aslında normalde siz int rutininizi yazarsınız int içerisinde etkilenen reg'leri lst dosyasından bulursunuz ve bunları (eğer otomatik save edilmiyorsa) kaydedersiniz ve çıkışta geri yüklersiniz. fakat ccs böyle yapmıyor sizin int içinde hiç bir reg etkilenmese bile hepsini kaydediyor ve çıkışta geri yüklüyor. siz aman int kısa olsun fazla yer kaplamasın diyorken bir sürü zaman kaybediyorsunuz. aslında 16 serisinde bu o kadar büyük bir kodda üretmiyor (nispeten) fakat 18 serisine gelince ciddi miktarda gereksiz zaman kaybına neden oluyor.
Erkan Bey, biliyorum ikisinin farklı olduğunu. Ben context saving haricinde bir de kullanıcı hangi interrupt için rutin yazmışsa onun şartı oluşmuş mu belirleyen ilave kodlar koyduğundan bahsetmek istemiştim. Bir tek interrupt rutinim var ve onda bile flag set edilmişmi diye bakıyor ve onunla ilgi rutini yerleştirdiği yere goto yapıyor bu da gereksiz yer ve zaman kaybı oluşturuyor demek istiyordum.
Sizin dediğinize katılmadım anlamı çıkmasın. Örneğin context savingde mesela hiç kullanmadığım halde 32 bit integer yada floating point için kullandığı 8 baytı alıp saklıyor ve rutinden çıkarken geri yerleştiriyor. Bunlar gereksiz şeyler bence de. Derleyicinin 32 bit aritmetik kullanıp kullanılmadığını tespit etmesi gerekir ve kullanılmamış ise bu adımları pas geçmesi gerekir. Fazladan gereksiz yere 30un üzerinde adım ve program alanı kaybı oluşuyor. Benzer şekilde interruptta ayrıca fsr ve indf kullanmıyor olsam da bunları saklıyor. Bunda hemfikiriz zaten. İşte bunun için profesyonel kullanıcılara yönelik "#int_global" direktifini eklemişler diyorum. Kullanıcı kendi ihtiyacına göre interrupt rutinlerde context savingini kendisi yapabilmesi için gerekli esnekliği sağlamışlar.
Benzer esneklik (aynısı değil) C18 de de var ve opsiyon olarak kullanıcı hangilerinin saklanmasını istediğini belirtebiliyor.
Alıntı Yap
buraya dikkat ederseniz aslında ccs'nin böyle yapması hobi amaçlı kullanıcılara en uygun şey çünkü kimse her bir int yazdığında lst dosyasını kurcalayıp zahmete girmek istemez bunu ccs'nin yapması büyük kolaylık fakat iş profesyonel olunca ve mikro saniyeler önem kazanınca dediğim şey anlaşılmaya başlıyor sanırım. bu zaten bir örnek sadece ve ileride bunu düzeltmeleri fikrimi değiştiremez çünkü compiler'ın mantığı belli.
ancak bu anlattıklarım ccs düşmanlığı olarak algılanmasın :) benim amacım büyük sayılabilecek işlere ccs ile girip sıkıntı yaşamamanızı istiyor olmam yoksa ben ccs'yi kullanabiliyor olmaktan memnunum.
bu arada string içerisine 0 yerleştirebilirsiniz fakat bu diziyi karakter dizisi olarak kullanamazsınız çünkü karakter dizilerinde 0 rakamı (aslında NULL karakteri) dizi sonunu gösterir. bu c'nin bir özelliği ayrıca çok kolaylık sağlayan uygulamaları var.
Öyle olduğunu biliyorum ve başka yolu denedim.lcd_putc(0) ama o da çalışmıyor. Jal de bunlar hiç sorun olmuyordu.
Bir de CCS de şunu yapamıyorum. örneğin "const char z[10]={4,"al",3,2,"ma"}" yani "Çalışma" kelimesini yükleyeceğim. Ç,ı,ş LCD sembolü olarak tanımlanmış. Bunda ben mi hata yapıyorum, tam olarak anlayamadım. Her birini karakter olarak yüklemek istedim {4,"a","l",3,2,"m","a"} buda olmadı. Oturup ta a, l, m nin ascii karşılıklarını yazsam olacak ama bu durumda da program takibi zorlaşacak. Böyle bir şeyi siz nasıl yapardınız?
Konu dışına mı çıktık acaba ? :D
@petek
program deneme amaçlı sadece interrupt deneniyor tümü ilk başta yazdığım program zaten onuda ekledim :? :?
benim amacım ccs de interrupt denemekti sen istersen bunu isis le deneyebilirsin ve çalışan bir programı yazar verirsen buda herkese ulaşır
Arkadaşlar bakıyorum derin konulara girmişsiniz tebrikler fakat problemle
ilgili çözüm pek konuşulmuyor eminim herkes bu konuda merakla çözüm bekliyor CCS bunu becerebiliyormu!!!! bu konuda Petek e katılmıyorum
eğer ccs bu konuda başarızsa bu bence BUG olayını aşar çünkü MCU lar
genelde ISR kaynaklarıyla değer kazanır ve bir çok konuda ISR kullanlır
eğer bunu CCS tam anlamıyla yapamıyorsa ve diğer derleyicilerdede hatalar var demeniz ve bunu bir tutmanız bence doğru değil hata her derleyicide olabilir önemli olan hatanın hangi şartlarda çıktığı
Saygılarımla
Alıntı yapılan: "kalman"@petek
program deneme amaçlı sadece interrupt deneniyor tümü ilk başta yazdığım program zaten onuda ekledim :? :?
benim amacım ccs de interrupt denemekti sen istersen bunu isis le deneyebilirsin ve çalışan bir programı yazar verirsen buda herkese ulaşır
CCS örnek programlarında zaten bir örnek var. Adam klavye yapmış ve hangi tuşa basıldığını tespit ediyor.
Programının başında işlemcinin ne olduğu yazılmamış. Eğer onlar interrupt.h içerisinde ise onu da gönderiver bi zahmet. Öyle kontrol edelim.
Alıntı Yap
Arkadaşlar bakıyorum derin konulara girmişsiniz tebrikler fakat problemle
ilgili çözüm pek konuşulmuyor eminim herkes bu konuda merakla çözüm bekliyor CCS bunu becerebiliyormu!!!! bu konuda Petek e katılmıyorum
eğer ccs bu konuda başarızsa bu bence BUG olayını aşar çünkü MCU lar
genelde ISR kaynaklarıyla değer kazanır ve bir çok konuda ISR kullanlır
eğer bunu CCS tam anlamıyla yapamıyorsa ve diğer derleyicilerdede hatalar var demeniz ve bunu bir tutmanız bence doğru değil hata her derleyicide olabilir önemli olan hatanın hangi şartlarda çıktığı
Saygılarımla
CCS'nin interrupt rutinlerinde hata olamaz. Defalarca denemiş ve örnek programda paketine eklenmiş. Sen kodun tamamını gönder öyle bir daha bakalım.
Her yeni versiyon çıkmadan önce "test suit" denilen örnek programlar tekrar denenir ve önceki versiyonda çalışan, yeni versiyonda çalışmaz ise çalışıncaya kadar düzeltilir ve piyasaya sürülür. O nedenle CCS'nin interrupt rutinlerinde hata yok. Sadece hantallık var. Ama profesyoneller için de esneklik var diyorum.
Alıntı yapılan: "SpeedyX"Tartışmayı alevlendirmek için int içerisindeki kod kısa olmalı kesinlikle delay olmamalıya karşı çıkayım.
Iyi bende alevlendireyim o zaman:
Interrupt olayini gunluk hayatta arkadasinizla konusurken (yada kafa kafaya vermis is yaparken) 3. kisinin gelip konusmaya aradan dalma istegine benzetebiliriz.
Eger 3.kisi lavugun teki ise genelde hastir len deriz. (Hatta cok kizmissak, sana ..k yemek duser diyip bir sure gelmesin diye kapisini kitleriz)
Ama gelen bir mudur ise konusmamizi keser evet efendim sizi dinliyorum gibi yalakalik moduna geceriz.
Mudurun bir an once basimizdan def edilmesi gerekir cunku arkadasimizla yaptigimiz sohbetimiz (is calismasi) engellemistir.
Ancak her an icin ayni yada daha yuksek mevkide bir baska mudurun gelmesi olasidir ve istegi kesinlikle yerine getirilmelidir. Aksi halde kendinizi kapi onunde bulabilirsiniz. Bu durumda araya giren isi en kisa zamanda yapabilmeli yada gorevi birilerinin ustune yikabilmelisiniz. Aksi halde hem asil isinizi hemde yeni angarya isi sizin yapmaniz ve basarili olma zorunlulugunuz bulunmaktadir.
Sirket (Donanim) , mudurleri siraya sokan genel istekleri duzenleme muduru gibi bir mudure sahip değilse (Interrupt priority controller) mudurler zirt pirt basiniza ususur sizden, kendi mevkisine bakmadan sirf mudur oldugu icin is talebinde bulunur ve hemen yapilmasini ister bu durumda bazi mudurlerin isleri yapsaniz dahi oncelikli mudurlerin isleri yapmadiginiz icin kapi onune konursunuz.
Zira dur bekle su anda ilk mudurun isine basladim ama sonuclanmadi sonuclana kadar cay icecegim (500ms beklemek gibi) sonra gel diyemezsiniz.
---------------------------
Donanimda interrupt kaynaklari cokca ve isteklerin hemen cevaplanmasi gerekiyorsa intterrupt programlari hizli calisan turden yazilmalidir.
Ayrica ayni interrupt kisa zaman araliklariyla pes pese gelebilir. Donanim bunlarin sayisini da tutamiyorsa genelde siz sadece 2 tanesini cevapliyabileceksiniz demektir.
Tabiki yukarda yazdigim senaryo kritik islemeri konu almistir, ancak int kodlarini kisa yazmak genelde ana amac olmali ve aliskanlik haline getirilmelidir.
Kalman, Port A ve Port B icin yazilan programlarin ayri ayri asm kodlarini gonderseydin su ana kadar sorunun nerde oldugu coktan anlasilacakti.
Kalman,
sen yazdığın programı gerçek devre üzerinde mi deniyorsun yoksa isis üzerinde mi?
ISIS ta baktım, interrupta giriyor, fakat çıkışta rbif i resetlemiyor. CCS resetlemek için gerekeni yapmış. Bir de ben interrupt rutininde kendim intcon,rbif i resetlemeye çalıştım ama ISIS bu flagi resetlemiyor. ISISte bug var. Zaten ISIS te debug işlemlerinde arasıra hata çıkıyor. 6.2 versiyonunda breakpoint yerlerini bile şaşırıyordu. LED'i pin_b1 e bağlayınca flag resetleniyor.
@ selam Arkadaşlar
İşte çalışan versiyonu
#include <16F84A.h>
#fuses NOWDT,XT, NOPUT, NOPROTECT
#use delay(clock=4000000)
#define LED PIN_B1 // Çalisan versiyon
#int_RB // Interrupt
LED_YAK()
{
disable_interrupts(GLOBAL);
output_high(LED);
delay_ms(100);
}
void main() {
set_tris_a(0b00000);
set_tris_b(0b00110000); // RB4 ve RB5 giris
setup_counters(RTCC_INTERNAL,RTCC_DIV_2);
enable_interrupts(INT_RB);
enable_interrupts(GLOBAL);
while (1)
{
output_low(LED); //LED söndür
}
}
Buda çalışmayan versiyonu
#include <16F84A.h>
#fuses NOWDT,XT, NOPUT, NOPROTECT
#use delay(clock=4000000)
#define LED PIN_A1 // Çalismayan versiyon
#int_RB // Interrupt
LED_YAK()
{
disable_interrupts(GLOBAL);
output_high(LED);
delay_ms(100);
}
void main() {
set_tris_a(0b00000);
set_tris_b(0b00110000); // RB4 ve RB5 giris
setup_counters(RTCC_INTERNAL,RTCC_DIV_2);
enable_interrupts(INT_RB);
enable_interrupts(GLOBAL);
while (1)
{
output_low(LED); //LED söndür
}
}
İşte çalışan versiyonun LST file
Filename: G:\testler\interrupt16f84.LST
ROM used: 113 words (11%)
Largest free fragment is 911
RAM used: 8 (12%) at main() level
9 (13%) worst case
Stack: 2 worst case (0 in main + 2 for interrupts)
*
0000: MOVLW 00
0001: MOVWF 0A
0002: GOTO 050
0003: NOP
0004: BTFSC 03.5
0005: GOTO 00A
0006: MOVWF 0E
0007: SWAPF 03,W
0008: MOVWF 0F
0009: GOTO 00F
000A: BCF 03.5
000B: MOVWF 0E
000C: SWAPF 03,W
000D: MOVWF 0F
000E: BSF 0F.1
000F: MOVF 0A,W
0010: MOVWF 13
0011: CLRF 0A
0012: BCF 03.7
0013: SWAPF 0E,F
0014: MOVF 04,W
0015: MOVWF 10
0016: MOVF 0C,W
0017: MOVWF 11
0018: MOVF 0D,W
0019: MOVWF 12
001A: BCF 03.5
001B: BTFSS 0B.3
001C: GOTO 01F
001D: BTFSC 0B.0
001E: GOTO 043
001F: MOVF 10,W
0020: MOVWF 04
0021: MOVF 11,W
0022: MOVWF 0C
0023: MOVF 12,W
0024: MOVWF 0D
0025: MOVF 13,W
0026: MOVWF 0A
0027: SWAPF 0F,W
0028: MOVWF 03
0029: BCF 03.5
002A: SWAPF 0E,W
002B: BTFSC 0F.1
002C: BSF 03.5
002D: RETFIE
.................... #include <16F84A.h>
.................... //////// Standard Header file for the PIC16F84A device ////////////////
.................... #device PIC16F84A
.................... #list
....................
.................... #fuses NOWDT,XT, NOPUT, NOPROTECT
.................... #use delay(clock=4000000)
002E: MOVLW 14
002F: MOVWF 04
0030: MOVF 00,W
0031: BTFSC 03.2
0032: GOTO 042
0033: MOVLW 01
0034: MOVWF 0D
0035: CLRF 0C
0036: DECFSZ 0C,F
0037: GOTO 036
0038: DECFSZ 0D,F
0039: GOTO 035
003A: MOVLW 4A
003B: MOVWF 0C
003C: DECFSZ 0C,F
003D: GOTO 03C
003E: NOP
003F: NOP
0040: DECFSZ 00,F
0041: GOTO 033
0042: GOTO 04D (RETURN)
....................
.................... #define LED PIN_B1 // Çalisan versiyon
....................
....................
.................... #int_RB // Interrupt
.................... LED_YAK()
.................... {
.................... disable_interrupts(GLOBAL);
0043: BCF 0B.7
0044: BTFSC 0B.7
0045: GOTO 043
.................... output_high(LED);
0046: BSF 03.5
0047: BCF 06.1
0048: BCF 03.5
0049: BSF 06.1
.................... delay_ms(100);
004A: MOVLW 64
004B: MOVWF 14
004C: GOTO 02E
....................
.................... }
....................
004D: BCF 0B.0
004E: BCF 0A.3
004F: GOTO 01F
.................... void main() {
....................
0050: CLRF 04
0051: MOVLW 1F
0052: ANDWF 03,F
.................... set_tris_a(0b00000);
0053: MOVLW 00
0054: TRIS 5
.................... set_tris_b(0b00110000); // RB4 ve RB5 giris
0055: MOVLW 30
0056: TRIS 6
....................
.................... setup_counters(RTCC_INTERNAL,RTCC_DIV_2);
0057: CLRF 0C
0058: BTFSS 0C.3
0059: GOTO 062
005A: MOVLW 07
005B: CLRF 01
005C: MOVLW 81
005D: MOVWF 04
005E: MOVF 00,W
005F: ANDLW C0
0060: IORLW 0F
0061: MOVWF 00
0062: CLRWDT
0063: MOVLW 81
0064: MOVWF 04
0065: MOVF 00,W
0066: ANDLW C0
0067: IORWF 0C,W
0068: MOVWF 00
.................... enable_interrupts(INT_RB);
0069: BSF 0B.3
.................... enable_interrupts(GLOBAL);
006A: BSF 0B.7
....................
....................
....................
....................
.................... while (1)
.................... {
.................... output_low(LED); //LED söndür
006B: BSF 03.5
006C: BCF 06.1
006D: BCF 03.5
006E: BCF 06.1
....................
.................... }
006F: GOTO 06B
....................
.................... }
....................
0070: SLEEP
Configuration Fuses:
Word 1: 3FF9 XT NOWDT NOPUT NOPROTECT
Buda çalışmayan versiyonunun LST File
Filename: G:\testler\interrupt16f84.LST
ROM used: 113 words (11%)
Largest free fragment is 911
RAM used: 8 (12%) at main() level
9 (13%) worst case
Stack: 2 worst case (0 in main + 2 for interrupts)
*
0000: MOVLW 00
0001: MOVWF 0A
0002: GOTO 050
0003: NOP
0004: BTFSC 03.5
0005: GOTO 00A
0006: MOVWF 0E
0007: SWAPF 03,W
0008: MOVWF 0F
0009: GOTO 00F
000A: BCF 03.5
000B: MOVWF 0E
000C: SWAPF 03,W
000D: MOVWF 0F
000E: BSF 0F.1
000F: MOVF 0A,W
0010: MOVWF 13
0011: CLRF 0A
0012: BCF 03.7
0013: SWAPF 0E,F
0014: MOVF 04,W
0015: MOVWF 10
0016: MOVF 0C,W
0017: MOVWF 11
0018: MOVF 0D,W
0019: MOVWF 12
001A: BCF 03.5
001B: BTFSS 0B.3
001C: GOTO 01F
001D: BTFSC 0B.0
001E: GOTO 043
001F: MOVF 10,W
0020: MOVWF 04
0021: MOVF 11,W
0022: MOVWF 0C
0023: MOVF 12,W
0024: MOVWF 0D
0025: MOVF 13,W
0026: MOVWF 0A
0027: SWAPF 0F,W
0028: MOVWF 03
0029: BCF 03.5
002A: SWAPF 0E,W
002B: BTFSC 0F.1
002C: BSF 03.5
002D: RETFIE
.................... #include <16F84A.h>
.................... //////// Standard Header file for the PIC16F84A device ////////////////
.................... #device PIC16F84A
.................... #list
....................
.................... #fuses NOWDT,XT, NOPUT, NOPROTECT
.................... #use delay(clock=4000000)
002E: MOVLW 14
002F: MOVWF 04
0030: MOVF 00,W
0031: BTFSC 03.2
0032: GOTO 042
0033: MOVLW 01
0034: MOVWF 0D
0035: CLRF 0C
0036: DECFSZ 0C,F
0037: GOTO 036
0038: DECFSZ 0D,F
0039: GOTO 035
003A: MOVLW 4A
003B: MOVWF 0C
003C: DECFSZ 0C,F
003D: GOTO 03C
003E: NOP
003F: NOP
0040: DECFSZ 00,F
0041: GOTO 033
0042: GOTO 04D (RETURN)
....................
.................... #define LED PIN_A1 // Çalismayan versiyon
....................
....................
.................... #int_RB // Interrupt
.................... LED_YAK()
.................... {
.................... disable_interrupts(GLOBAL);
0043: BCF 0B.7
0044: BTFSC 0B.7
0045: GOTO 043
.................... output_high(LED);
0046: BSF 03.5
0047: BCF 05.1
0048: BCF 03.5
0049: BSF 05.1
.................... delay_ms(100);
004A: MOVLW 64
004B: MOVWF 14
004C: GOTO 02E
....................
.................... }
....................
004D: BCF 0B.0
004E: BCF 0A.3
004F: GOTO 01F
.................... void main() {
....................
0050: CLRF 04
0051: MOVLW 1F
0052: ANDWF 03,F
.................... set_tris_a(0b00000);
0053: MOVLW 00
0054: TRIS 5
.................... set_tris_b(0b00110000); // RB4 ve RB5 giris
0055: MOVLW 30
0056: TRIS 6
....................
.................... setup_counters(RTCC_INTERNAL,RTCC_DIV_2);
0057: CLRF 0C
0058: BTFSS 0C.3
0059: GOTO 062
005A: MOVLW 07
005B: CLRF 01
005C: MOVLW 81
005D: MOVWF 04
005E: MOVF 00,W
005F: ANDLW C0
0060: IORLW 0F
0061: MOVWF 00
0062: CLRWDT
0063: MOVLW 81
0064: MOVWF 04
0065: MOVF 00,W
0066: ANDLW C0
0067: IORWF 0C,W
0068: MOVWF 00
.................... enable_interrupts(INT_RB);
0069: BSF 0B.3
.................... enable_interrupts(GLOBAL);
006A: BSF 0B.7
....................
....................
....................
....................
.................... while (1)
.................... {
.................... output_low(LED); //LED söndür
006B: BSF 03.5
006C: BCF 05.1
006D: BCF 03.5
006E: BCF 05.1
....................
.................... }
006F: GOTO 06B
....................
.................... }
....................
0070: SLEEP
Configuration Fuses:
Word 1: 3FF9 XT NOWDT NOPUT NOPROTECT
Hepsi bu kadar umarım bu yeterli gelir
Saygılarımla
Alıntı yapılan: "bunalmis"Iyi bende alevlendireyim o zaman
...
Tabiki yukarda yazdigim senaryo kritik islemeri konu almistir, ancak int kodlarini kisa yazmak genelde ana amac olmali ve aliskanlik haline getirilmelidir.
Katılıyorum, sadece int içinde delay kesinlikle kullanılmaza karşı çıktım.
Birden fazla int kullanılan bir ortamda tabiki interrupt alt programları olabildiğince kısa olmalıdır. Mantıklı ve doğru olan da budur.
Aslında bu tartışma çok güzel ilerliyor, öğretici bir tartışma oluyor. Birilerinin derin mevzulara girmesi gerekiyor :)
Derslerden ve kedimden vakit buldukça bende katılırım.
Bu resmi niye verdim bilmiyorum
Alıntı yapılan: "Petek"Kalman,
sen yazdığın programı gerçek devre üzerinde mi deniyorsun yoksa isis üzerinde mi?
ISIS ta baktım, interrupta giriyor, fakat çıkışta rbif i resetlemiyor. CCS resetlemek için gerekeni yapmış. Bir de ben interrupt rutininde kendim intcon,rbif i resetlemeye çalıştım ama ISIS bu flagi resetlemiyor. ISISte bug var. Zaten ISIS te debug işlemlerinde arasıra hata çıkıyor. 6.2 versiyonunda breakpoint yerlerini bile şaşırıyordu. LED'i pin_b1 e bağlayınca flag resetleniyor.
Unuttuğum bir şey daha var eklemek istiyorum. Interrupt rutininde en az debounce süresi kadar bir delay olmalı. Tabi bu portb<7:4> seviye değişimini butonla yapıyorsan gerekli. Yoksa her interrupt dönüşünde (debounce süresince) tekrar tekrar interrupta gitme ihtimalin var.
Bir hata da L_TO_H seviye değişiminde interrupt'a git demişsin. Bu external interrupt için (pin_b0) gerekli. #Int_rb de port_b<7:4> hem L_TO_H, hem de H_TO_L geçişlerinde interrupt üretir. Butona bastın interrupt, çektin interrupt dallanması olur. Debouns süresince seviye sıkça değiştiği için bu interrupta birkaç defa gidebilirsin. Senin programda bu önemli değil zira 500ms delay koymuşsun, bu arada defalarca flag set edilir ama 25-50 ms kadar sonra (bir de butondan elini çekince) durulur. Zaten 500 ms de herşey bittiği için interrupt dönüşünde CCS tarafından rbif reset ediliyor.
Kalman,
ISIS te hem pin_b1 e hem de pin_a1 e led bağladım. Simulasyon düzgün çalıştı. her ikisi de yanıp sönüyor. Sorun ISISte.
pin_b4 e clock kaynağı bağla (periyodu 2 saniye olsun). Her çıkşta ve inişte interrupt tetikleniyor. her iki led de yarım saniye yanıp sönüyor.
@Petek
galiba haklısın ben bunu isisle simule ediyorum belkide bu yüzden
bu hatayla karşılaşıyorum belkide gerçek devrede bu oluşmaz aslında bu
Rotary encoder devresinin ilk deneme aşaması isisle simuledemi bir sorun var bilmiyorum başka hangi programla deneyebiliriz fakat her şeye rağmen verdiğin cevaplar dolayı teşekkürler ve en kısa zamande gerçek devreyle deneyip sonucu sizlere bildiririm
Aslında ISR içinde delay kullanmak bencede doğru değil fakat benim söylemek istediğim portRB ile oluyorsa neden PortRA olmasın bunun mantığını pek anlamadım ve bu konuyu bu sizle paylaşmak istedim
Güzel olan cevaplar hızlandı çoğaldı buda herkesi memnun ediyor sanıyorum
@bunalmış Lst dosyasında bir şeyler bulabildinmi?? sencede bu ISIS ten kaynaklanabilirmi
Saygılarımla
Asm kodlarda portun A yada B olusu disinda hic bir fark yok.
RBIF bitini silecek kod da 04DH adresine yerlestirilmis.
Bu durumda neden B portu yerine A portu kullanildiginda program sapitiyor ve RBIF hic silinemiyor?
Sanirim cevabi DS35007B 17.sayfada, RBIF'in surekli set olma durumu anlatilmis.
Sorun A portu ile calisilirken, interrupt programinin en sonuna asagidaki kod eklentisiyle duzelebilir
1. PortB yi oku,
2. RBIF'i oku, 1 ise 0 yap, 0 ise adim 4 e atla
3. 1.adima git
4. Islem tamam
Uretilen kodlari inceledikten sonra bu compiler ile ciddi islere girilemeyecegi konusuna Erkana katiliyorum.
C ASM nin bir ustudur, hizlidir denir. Adamlar islemci yavas calissin diye ellerinden geleni yapmislar.
@Bunalmış,
Bunu daha öncede denedim olmadı RBif her nedense resetlenmiyor
Sen isisde deneyip programı tümünü verebilirmisin!!!
Petekde aynı yöntemden söz etmişti sonuç malum olmuyor :roll:
herkese başarılar
saygılarımla
1. PortB yi oku,
2. RBIF'i oku, 1 ise 0 yap, 0 ise adim 4 e atla
3. 1.adima git
4. Islem tamam
aynen bu mantigi uygulayip interrupttan cikmayi denedinmi? C komutlari ile bence bunu dene. ilk satirdaki PORT B oku komutu cok onemli.
Ben hic bir sey denemedim. (Isis falan yuklu değil)
Eger zamanin olursa yukaridaki kismi dener sonucunu yazarsan sevinirim.
(Benim duzenegi kurmam kod yazmam kompilerlari yuklemem cok uzun is simdi)
RB7.4 pin change int ozelligini bu gune kadar hic kullanmadim. Ancak anladigim kadariyla RB portunu hic okumazsaniz bu ozellik dogru calismiyor.
Yani bu pini klasik external int pini gibi dusunmemek gerekiyor.
En son B portunu okudunuz bu hafizaya aliniyor portta bir degisim olursa int uretiyor. Ilk yapmaniz gereken seylerden birisi portB yi tekrar okuyup yeni degeri hafizaya aldirmak.
Hata compilerin uygun kod uretmemesi olabilir.
Tabiki benim kisa bir incelemeden sonra cikarttigim sonuc bu. Tamamiyla yaniliyor da olabilirim. PIC'e uzun yillardir elimi surmedim.
Tereddutlu olarak yazdigim yukaridaki cevabim uzerine dusunme firsatiniz oldumu yada denedinizmi?
Sonucu ben de cok merak ediyorum.
@herkese selamlar,
Sonunda bu problem çözüme kavuştu CCS de eğer RB4-7 ınterruptunu
kullanacak olursanız mecburu portb i okumanız gerekli yoksa flag resetlenmiyor bu durumdada maalesef RB İnt.ex i kullanamıyorsunuz.
Kısaca anlatayım ISR içinde portB i okuyorsunuz ve andliyorsunuz bu işlemden sonra RBIF resetleniyor sonrası size kalmış ister ana programa veya başka fonksiyona atlama yapabilirsiniz :P :P
@Bunalmış aslında tahminlerin doğru Portb okunmadan olmuyor
herkese katkılarından dolayı teşekkürler
Evet şimdi size çalışan programı veriyorum
#include <16F84A.h>
#fuses NOWDT,XT, NOPUT, NOPROTECT
#use delay(clock=4000000)
#define LED PIN_A1 // nihayet calisan versiyon
#Byte STATUS = 0x6 //portB adresi
#define RBIE 3
bekle()
{
delay_ms(500); //bekleme süresi
}
#int_RB // Interrupt
LED_YAK()
{
output_high(LED);
STATUS &= ~RBIE; // püf noktasi
bekle();
}
void main() {
set_tris_a(0b00000);
set_tris_b(0b11110000); // RB4 den RB7e kadar giris
setup_counters(RTCC_INTERNAL,RTCC_DIV_2);
enable_interrupts(INT_RB);
enable_interrupts(GLOBAL);
while (1)
{
output_low(LED); //LED söndür
}
}
Bir yandan heralde bu kadar zamandır boşuna konuşuyoruz diye düşünürken bir yandanda olması gereken kodu gönderiyorum bende.
#byte portb = 6
#define LED PIN_A1
int1 ledyak=0;
char b;
#int_rb
LED_YAK()
{
b = portb;
ledyak=1;
}
void main() {
setup_counters(RTCC_INTERNAL,RTCC_DIV_2);
enable_interrupts(INT_RB);
enable_interrupts(GLOBAL);
while (1)
{
output_low(led);
if(ledyak)
{
output_high(LED);
delay_ms(500);
ledyak=0;
}
}
}
Bence olması gereken kod bu değil.
INTRB rutininine girilince led yakılmalı, timer başlatılmalı ve INTRP yeni isteklere kapatılmalı.
Timer int programı, 500ms sonunda ledi söndürüp tekrardan INTRB interruptını açmalı.
Ana programın akışının da uzun süreli kesintilere uğramaması da ana amaclardan biri olmalı.
Alıntı yapılan: "bunalmis"Bence olması gereken kod bu değil.
INTRB rutininine girilince led yakılmalı, timer başlatılmalı ve INTRP yeni isteklere kapatılmalı.
Timer int programı, 500ms sonunda ledi söndürüp tekrardan INTRB interruptını açmalı.
Ana programın akışının da uzun süreli kesintilere uğramaması da ana amaclardan biri olmalı.
hocam dedikleriniz çok mantıklı işi bir adım öteye taşıdığımızda dediğiniz gibi yapmalıyız bu çok daha profesyonelce olur. (basit bir led yakma programı ne hale geldi :D)
zaten benim dikkat çekmek istediğim int kullanımında dikkat edilmesi gerekenler ve tris kullanmanın gereksizliği
@Erkan,
Bu konuda üstteki mesajı okusaydın konunun çözüme kavuştuğunu
görürdün ;) ;)
Senin verdiğin programda çalışıyor fakat her nedense intcon ilk biti
RBIF hiç değişmiyor
Interrupt geldiğinde 1 ISR terk edildiğinde ise 0 olmalı sende bu olmuyor
bunu denedim RbIF hep aynı kalıyor bence buna bir bakman gerekecek
tekrar ediyorum vermiş olduğum program hatasız çalışmakta
@bunalmış yazdığın gibi ISR de Led yanıyor sonra bir süre bir başka foksiyona gidip bir süre bekliyor sen bunu banamı yoksa erkanamı
yazıyorsun bunu pek anlamadım :roll: :roll:
herkese başarılar
Ben zaten sizin çözüme kavuştu dediğiniz mesaja karşılık yazdım o kodu çünkü o kadar zamandır yazılan şeylere hiç dikkat etmemişsiniz.
RBIF bir oluyor isis'te coff dosyasını kullanarak debug ettim ve bunu gördüm (zaten bir olmazsa int'e nasıl girdiğini düşünüyorsunuz). burada yazdıklarımızı kafadan sallayıp yazdığımızı sanmayın ben bunları hep deneyerek göndermeye çalışıyorum.
bunalmis hocamda mesajı bana yazdı bunuda "olması gereken kod" cümlesinden anlayabilirsiniz.
Arkadaşlar,
RBIF'i restelenmediği ni gördüğünüz ISIS'in versiyonu kaç. Ben 6.5SP5 te simule ediyorum. Daha sonraki versiyonlarda bu sorun acaba giderilmiş olabilir mi?
Kalman, int_ext'in port_b<4:7> (yada int_rb) durum değişim interruptı ile ilgisi yok. "bu durumda malesef int_ex kullanamıyorsunuz" demişsin. Int_ex sadece ve sadece pin_b0 ın durumu ile ilgilidir. Bana biraz karıştırıyorsun gibi geliyor.
Erkan, CCS de bir sorunum daha olmuştu. Onu da ileteyim.
#define hi(x) *(&x + 1)
şeklinde tanımladıktan sonra int16 tanımlı data isimli bir değişkeni byt tanımlı zz ile ilişkilendirirsek CCS de şöyle bir durum ortaya çıkıyor.
zz = hi(data); // bu data nın MSBaytını aktarıyor. Sorun yok.
ama
hi(data)=zz ;
yaptığınızda zz yi MSBayta aktarmasını bekliyorsunuz ama LSBaytına aktarıyor.
Bu hatayı anlayıncaya kadar bir kaç saatim gitmişti. Sorunu yine değişik yoldan şöyle çözmüştüm:
*(&data + 1) = zz;
Petek,
Benim anlatmak istediğim olay şöyle diyelim int_rb i açtınız ve aynı zamandada int_ex i açtınız ve interrupt geldiğinde sizce ne yapar önce İNTcon Registerde duruma bakıp hangi kaynaktan geldiğine bakar ve o kaynağın ISR ine atlama yapılır diye biliyorum pekala ikisi aynı anda gelse sizce hangisi öncelikli olur???
bildiğim kadarıyla her interrupta 04h ya atlama yapılıyor ve interrupt
önceliği pıc 16fxx bulunmuyor
erkan amacım herkes bilgilerini paylaşsın ve yardımcı olsun son yazdıklarından dolayı biraz düşünmeni öneririm lütfen kırıcı olmayalım
sanada başarılar dilerim
Saygılarımla
Alıntı yapılan: "kalman"son yazdıklarından dolayı biraz düşünmeni öneririm
Ben yazdıklarım hakkında hem göndermeden önce hemde gönderdikten sonra çok düşündüm ayrıca burada kırılan benim onca emek sarfedip bunların bir işe yaramadığını görmek beni üzdü doğrusu.
Neyseki bu başlıkta hem ben hemde katkıda bulunan diğer arkadaşlar bilgilerimizi paylaşarak tecrübe sahibi olduk.
Ben yazdığım mesajdan memnunun bence siz önceki mesajları baştan sona anlayarak okumayı bir deneyin çünkü bu başlıkta ve sitenin daha pek çok yerinde para verseniz dahi elde edemeyeceğiniz tecrübeler var.
Bunları size kimse anlatmaz.
Ayrıca internette forumların bir numaralı kuralı 'kimse size bir şey borçlu değildir' kuralıdır. Yani kimse sizin sorununuzu çözmek için zamanını harcamak zorunda değildir. Halbuki ben ve diğer arkadaşlar bir sürü zamanımızı harcadık. Buna biraz saygı gösterseniz yeterli.
Alıntı yapılan: "kalman"Petek,
Benim anlatmak istediğim olay şöyle diyelim int_rb i açtınız ve aynı zamandada int_ex i açtınız ve interrupt geldiğinde sizce ne yapar önce İNTcon Registerde duruma bakıp hangi kaynaktan geldiğine bakar ve o kaynağın ISR ine atlama yapılır diye biliyorum pekala ikisi aynı anda gelse sizce hangisi öncelikli olur???
bildiğim kadarıyla her interrupta 04h ya atlama yapılıyor ve interrupt
önceliği pıc 16fxx bulunmuyor
erkan amacım herkes bilgilerini paylaşsın ve yardımcı olsun son yazdıklarından dolayı biraz düşünmeni öneririm lütfen kırıcı olmayalım
sanada başarılar dilerim
Saygılarımla
Birincisi, iki interruptın aynı anda gelme olasılığı milyonda birdir (4 MHz kristal için). İkincisi Piclerde vektörel interrupt olmadığı için interrupt durumunda tek bir adrese gider 0x04.
nterrupt önceliğini CCS ayarlıyor. Detayına bakmadım ama muhtemelen siz ilk hangi interrupt rutinini tanımlamış iseniz öncelikle ona bakacaktır. Onu bitirdiğinde diğerlerine bakıyor mu bilemiyorum ama bakmasa da interruptan çıktıktan sonra diğerinin flagi (tabi int enable edilmişse) set edilmiş ise tekrar interrupta döner ve set edilen flagin hangisi olduğuna bakar. Dolayısıyle hem int_rb ve hem de int_ext aynı anda kullanılabilir. Bunda herhangi bir engel yok. İnterruptan çıkarken sadece hangisi için gelmiş ise onun flagini resetleyerek çıktığı için diğer flaglar set edilmiş ise interrupt onlar için tekrar harekete geçirilir.