Gönderen Konu: Interrupt  (Okunma sayısı 14528 defa)

Çevrimdışı batı

  • Mezun olmuş OTOKON'cu
  • *
  • İleti: 126
Interrupt
« : Haziran 17, 2008, 10:26:29 ÖS »
Interrupt metoduyla hız ölçümü yapmam gerekiyor. Elinde interrupt ile ilgili döküman olan varsa ve gönderebilirse çok sevinirim.
Kendimi durduracak değilim...

Çevrimdışı Onur Varol

  • Mezun olmuş OTOKON'cu
  • *
  • İleti: 3029
Ynt: Interrupt
« Yanıtla #1 : Haziran 18, 2008, 12:14:51 ÖÖ »
mikrodenetleyicilerlemi yapılacak?

Çevrimdışı Özen Özkaya

  • Özen
  • Mezun olmuş OTOKON'cu
  • *
  • İleti: 826
  • sudo ./FuutonRasenShuriken
Ynt: Interrupt
« Yanıtla #2 : Haziran 18, 2008, 01:32:21 ÖÖ »
Interrupt moduyla ama hangi interruptla? dış kesmeyle mi zamanlayıcı kesmesiyle mi? SPI kesmesiyle mi? USART kesmesiyle mi? UART kesmesiyle mi? JTAG kesmesiyle mi? =) hız ölçümünü nasıl yapacağını hangi türden interrupt kullanmak istediğini yazarsan abi yardım edebileceğimizi düşünüyorum...
sudo ./FuutonRasenShuriken

Çevrimdışı batı

  • Mezun olmuş OTOKON'cu
  • *
  • İleti: 126
Ynt: Interrupt
« Yanıtla #3 : Haziran 18, 2008, 08:14:07 ÖS »
Donanım interruptı olması gerekir çünkü pic18f2550 nin A0 portuna bağlı (yada başka herhangi bir) cny den aldığım bigiye göre hız ölçümü yapacağım. (belli bir zaman aralığında kaç kere kesmeye uğradı(?)) Hangi kesmeyi kullanacağımı bilsem birşeyler bulurum da ben de bilmiyorum hangi kesmeyi kullanmam gerektiğini. Bi fikriniz var mı?
Kendimi durduracak değilim...

Çevrimdışı Ufuk Sevim

  • Mezun olmuş OTOKON'cu
  • *
  • İleti: 451
Ynt: Interrupt
« Yanıtla #4 : Haziran 19, 2008, 12:13:23 ÖÖ »
şimdi sen artırımlı enkoder tarzı bir sensörden veri almak istiyosun anlaşılan. pic ailesinde CCP (Capture/Compare/PWM) modülü vardır. Bu modülde sen Capture olanı kullanmak durumundasın. onu kullanırsan şöyle olur, yükselen ya da düşen kenarlar arasındaki süreyi kesme alt programında CCP ile ilgili bir kütük sana verir. eh buradaki frekansı (ya da süreyi) biliyorsan da hız bilgisine rahatlıkla geçersin. bu kesmeleri de sayarsan konum elde edersin.
++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.

Çevrimdışı batı

  • Mezun olmuş OTOKON'cu
  • *
  • İleti: 126
Ynt: Interrupt
« Yanıtla #5 : Haziran 19, 2008, 01:43:10 ÖÖ »
Bir örnek kod üzerinde açıklayabilir misin Ufuk abey, hal böyle olunca bayaa karışıyor. İnsan araştırma yapmayı bilmeyince de doğru bilgiye ulaşmak epey zaman alıyor.
Kendimi durduracak değilim...

Çevrimdışı Ufuk Sevim

  • Mezun olmuş OTOKON'cu
  • *
  • İleti: 451
Ynt: Interrupt
« Yanıtla #6 : Haziran 27, 2008, 11:45:39 ÖÖ »
daha önce yazdığım bir kodu düzenledim ve açıklamalarıyla birlikte buraya yazıyorum. ama onun dışındaki bilgiler için tabi ki datasheet'e danışman gerekecek.

*********************habulu.c******************************
/* Not: Hi-Tech PICC derleyicisinde derlenmiştir */
#include <pic.h>

unsigned int zaman; // her yerde geçmesini planladığımız global değişkenimiz

/* kesme alt programı...
16f serisinde bir tek kesme alt programı kullanabilirsin. bu şu demek: hangi tür kesme olursa olsun programın hep aynı alt programa dallanacaktır.
18f serisinde de eğer önceliklerle (priority) oynamadıysan hep aynı programa dallanır */
static void interrupt kesme () {
   if ( CCP1IF ) { // CCP kesmesi ise...
      zaman = CCPR1H*256+CCPR1L; // zamanı yakalıyoruz toplam 16 bit

/* Artık ne kadar süre ile 5V - ya da ayarlarına göre 0V - geldiğini biliyoruz. Bunu burada
ya da ana programda istediğin gibi kullanmak sana kalmış */

      TMR1H = 0; // zamanlayıcıyı sıfırlıyoruz ki bir sonraki kesmede yine doğru değer alalım
      TMR1L = 0;
      CCP1IF = 0; // kesme bayrağını temizliyoruz
   }
   if ( TMR1IF ) { // zamanlayıcı kesmesi ise...
/* bunun anlamı şu ki zamanlayıcı taşana kadar bir kesme gelmemiş,
yani senin uygulaman için aletin duruyor ya da çok yavaş dönüyor.
Not: pic16f877'de Yakalama (Capture) modülü Timer1 ile ilişkili. ama senin mikrokontrolöründe farklı
bir zamanlayıcı ile ilişkili olabilir*/
      TMR1H = 0;
      TMR1L = 0;
      TMR1IF = 0;
   }
}

main(){
   TRISC = 4; // RC2 bacağını giriş yapıyoruz, yani sensör buraya bağlanacak (pic 16f877'de tabi ki)
   CCP1CON = 0b00000100; // her düşen kenarda kesmeye gir -> datasheet : )
   T1CON = 0b00110001; // (Focs/4)/8; dahili saat; zamanlayıcıyı başlat -> datasheet : )
   CCP1IE = 1; // CCP kesmesine izin ver
   TMR1IE = 1; // zamanlayıcı kesmesine izin ver
   PEIE = 1; // dış kesmelere izin ver
   GIE = 1; // tüm kesmelere izin ver
   while(1); // kesmenin gelmesini bekle : )
/* tabi ki while döngüsünün içinde başka işlemler yapman kesmeleri engellemeyecek; hatta kesmenin
mantığı da budur zaten, sen başka işlemleri yaparken dışarıdaki uyaranlara anında tepki verebilmek */
}

**************************************************************

umarım açıklayıcı olmuştur kolay gelsin...
++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.

Çevrimdışı batı

  • Mezun olmuş OTOKON'cu
  • *
  • İleti: 126
Ynt: Interrupt
« Yanıtla #7 : Haziran 27, 2008, 02:06:04 ÖS »
Pekala şimdi anladığım kadarını bir dile döküp anlatmaya çalışacağım. Eğer düşündüklerimde hata varsa söylersiniz.

Programımızı çalıştırdık.

TRISC = 4

(1) Neden RC2 bacağını giriş yaptık? Çünkü CCP modülünden kullandığımız Capture tetikleyici olarak RC2 port girişini kullanıyor. PIC18f serisiyle çalışanlarda bu 13 numaralı bacak oluyor. Benim cahilliğim ise şurada. Daha önce bu işlerle uğraşmış olmadığım için TRISC = 4 değer ataması neden RC2 bacağını giriş yapıyor? Başka bir bacağı giriş yapmak isteseydim ne yapacaktım? (Oha dediğinizi duyar gibiyim :) )

CCP1CON = 0b00000100

(2) 18f2550 için de bit 3-0 mod seçimi için kullanılıyor ve 0100, her düşen kenarda kesmeye girilmesi için kullanılıyor. Sanırım burada bir problem yok.

T1CON = 0b00110001

(3) Neden Timer1 kullanıyorum? Cevabını Ufuk vermiş aslında. Capture ve Compare modülü Timer1 ile ilişkili (pic16f877'de). pic18f2550'da (benim kullanacak olduğum da) ise Capture'ı Timer1 veya Timer3 ile kullanabiliyorum. Şimdi T1CON kütüğünü inceleyelim. --> 0b00110001

"(Fosc/4)/8; dahili saat; zamanlayıcıyı başlat" gibi bir açıklaması var. 0. bit zamanlayıcıyı başlatıyor. 1. bit dahili(ne demek? neden?) yapıyor. 4. ve 5. bitler ise 1:8 ölçekli olmasını sağlıyor. Pekala burada 1.bitin ve 4 ile 5. bitlerin açıklamasına ihtiyacım var. Neden 1:8 ölçeğini kullanıyoruz ve neden dahili saati kullanıyoruz ve wth is fosc?

CCP1IE = 1; // CCP kesmesine izin ver
TMR1IE = 1; // zamanlayıcı kesmesine izin ver
PEIE = 1; // dış kesmelere izin ver
GIE = 1; // tüm kesmelere izin ver


(4) Zamanlayıcı kesmesi,bir taşma olduğu zaman üretiliyor. Peki zamanlayıcımız ne zaman taşıyor?

Programımız bu kadar. Sonrasında while döngüsü içine giriyor. Peki şimdi bir kesmeye uğradığımız zaman neler olacak ona bir bakalım.
Öncelikle CCP1CON'un kütüğünü her düşen kenarda kesmeye girmesi üzerine ayarladık. Sanırım bu sensörün özelliğiyle ilgili. O yüzden bu kısımda ne yapmak istediğimi tekrar anlatayım. Elimde siyah veya beyazı algılayan bir CNY70 var. Işığı yansıtmadığı zaman (siyah yüzey) 1 (5V), yansıttığı zaman da 0 (0V) veriyor. Bu cny'yi örneğin üzerine siyah bir bant yapıştırılmış olan beyaz bir tekerleği görecek şekilde bağlıyoruz. tekerlek dönmeye başladığında CNY sabit kaldığı için, tekerleğin her dönüşünde sensör bir defa siyah bant üzerinden geçecek ve buna bağlı olarak bir kare dalga üretecek. Bu sebeple yükselen kenarda kesmeye uğraması daha mantıklı gözüküyor. (Aslında fark edeceğini pek sanmam çünkü her çıkışın bir inişi vardır :D ) Şu an için düşen kenarı kullanalım. Çok kısa bir süre için CNY siyah bant üzerindeyken 5V üretti ve siyah banttan çıktığı anda 0V'a döndü. Düşen kenar şu an gerçekleşmiş olmalı, öyle değil mi? Öyle olduğunu varsayarak, kesmeye uğradığımızı ve kesme() fonk'una gittiğimizi varsayıyorum.

if ( CCP1IF )
{
      zaman = CCPR1H*256+CCPR1L;
      TMR1H = 0;
      TMR1L = 0;
      CCP1IF = 0;
}


zaman'ın hesaplanışını gerçekten anlayamadım. CCPR1L Yakalama Kütüğünün düşük byte'ı, CCPR1H ise yakalama kütüğünün yüksek bayt'ı olmalı. Bu neyi ifade ediyor? Neden yüksek baytı 256 ile çarpıp düşük olanı ekliyoruz. Eminim mantıklı bir açıklaması vardır :D TMR1H ve TMR1L'i neden 0'lıyoruz? Madem zamanı hesaplamak için CCPR1H ve CCPR1L'miz var o zaman, zamanlayıcı kesmesini neden kullanıyoruz? Yoksa CCPR1H ve CCPR1L'in hesaplanabilmesi için Timer kesmesine mi ihtiyacımız var?

Birde şunu sormak istiyorum. Yukarda söylediğim gibi, Şu an siyah çizgiden çıkmak üzereydik, bu yüzden 5V dan 0V'a bir düşüş yaşadık. Bu sırada da kesmeyi ürettik. Hesapladığımız şey bir önceki kesmeyle şimdiki kesme arasında geçen zaman farkı mı? O zaman tam olarak bir dönüşü ne kadar zamanda yaptığını hesaplamış olmaz mıyım?

Şimdilik sorularım bu kadar. Ufuk bu kod çok güzel oldu bu arada, kafamdaki pek çok soruya cevap bulmaya başladım. Senin de yardımlarınla umarım kesme yöntemiyle hız ölçümü yapacağım :)
Kendimi durduracak değilim...

Çevrimdışı Ufuk Sevim

  • Mezun olmuş OTOKON'cu
  • *
  • İleti: 451
Ynt: Interrupt
« Yanıtla #8 : Haziran 27, 2008, 04:24:51 ÖS »
şimdi, tek tek açıklamaya çalışalım:

TRISC = 4

burada TRISC kütüğünde 1 olarak ayarladığın bitler, o bacağı giriş, 0 olarak ayarladığın bitler ise çıkış olarak tanımlıyor. yani aslında ikilik tabanda yazsaydık...

TRISC = 0b00000100;

sağdan başlayarak 0. biti çıkış, 1. biti çıkış, 2. biti giriş ve diğer bitleri çıkış olarak ayarlamışız. sen istediğin bacak değerlerini 1 ya da 0 yaparak giriş ya da çıkış olacağına karar verebilirsin.

CCP1CON = 0b00000100

Alıntı
0100, her düşen kenarda kesmeye girilmesi için kullanılıyor.

evet, dediğin gibi. diğer seçeneklerin ise; her yükselen kenarda, her 4. yükselen kenarda ve her 16. yükselen kenarda olarak belirlenmiş

Alıntı
"(Fosc/4)/8; dahili saat; zamanlayıcıyı başlat" gibi bir açıklaması var. 0. bit zamanlayıcıyı başlatıyor. 1. bit dahili(ne demek? neden?) yapıyor. 4. ve 5. bitler ise 1:8 ölçekli olmasını sağlıyor. Pekala burada 1.bitin ve 4 ile 5. bitlerin açıklamasına ihtiyacım var. Neden 1:8 ölçeğini kullanıyoruz ve neden dahili saati kullanıyoruz ve wth is fosc?

şimdi burada biraz duralım. aslında burada "dahili" demek belki biraz yanlış olmuş. bunun yerine "mevcut" demek daha doğru olabilirmiş. bu şu demek. senin pic'i çalıştırmak için halihazırda taktığın kristal aynı zamanda timer1 için de kullanılacak. ayrıca sen istersen T1OSI - T1OSO bacaklarına osilatör bağlayarak ya da T1CKI bacağına verdiğin kare dalgayla da zamanlayıcının artmasını sağlayabilirsin. fosc, bağladığın kristalin frekansıdır. normalde dışarıdan bir saat bağlamadığında zamanlayıcı bu frekansın 1/4 'ünde çalışır. 1/8 ölçeği ise zamanlayıcının bu asıl frekansı da kaça böleceğini ayarlar. örneğin 4MHz bir kristal kullanıyorsan ve 1/8 şeklinde ölçekleme yaptıysan saatin 125 kHz'de çalışacak demektir. bu da zamanlayıcının 1 saniyede 125000 'e kadar sayması demek (ancak pic16f ve pic18f serilerinde timer1 16 bitlik olduğundan 65535 (2^16 - 1) sayısını geçtiğinde zamanlayıcı taşacak ve sıfırlanacaktır) bu ölçeği tamamen sallıyoruz : ) tabi ki senin ölçmek istediğin hız ve hassaslık derecesi de bu ölçeği seçmek için etkenler.

Alıntı
(4) Zamanlayıcı kesmesi,bir taşma olduğu zaman üretiliyor. Peki zamanlayıcımız ne zaman taşıyor?

işte yukarıda da bahsettiğim gibi zamanlayıcı 0xFFFF değerini geçtiği anda sıfırlanıyor ve bir kesmeye giriyor. (tabi ki zamanlayıcı 16 bitlikse. örneğin timer0 8 bitlik olduğundan 0xFF değerini geçtiğinde kesmeye giriyor)

öncelikle kesmeye nasıl girdiğimiz ile ilgili açıklamaların tamamen doğru. her düşen kenarda kesmeye giriyoruz bu uygulamada. benim daha önce yazdıklarım yanlış : )

Alıntı
Artık ne kadar süre ile 5V - ya da ayarlarına göre 0V - geldiğini biliyoruz.

benim uygulamam biraz daha farklı olduğundan sanki aynısıymış gibi yazmışım. ayrıca düşen ya da yükselen kenar olması da fark etmez.

ekte gönderdiğim resme bakarsan daha rahat anlayacaksın. ben yine de anlatmaya çalışayım. şimdi zaman hesaplaması tamamen işlemcilerimizin 8 bitlik olmasından o şekilde : ) işlemcimiz 8 bitten büyük verileri işleyemediğinden veriler iki ayrı kütükte tutuyor. bu da yüksek anlamlı bitin aslında bir nevi "basamak değeri" olmasını sağlıyor.

peki madem CCP1 kütüğümüz var, neden TMR1 kütüğünü de kullanıyoruz? aslında uygulamaya göre dışarıdan bir kesme alıp TMR1 kütüğünü kesme sırasında okuyarak da aynı işi gerçekleştirebiliriz. yalnız şu var ki biz o kesmeye girip değeri yakalayana kadar bizim zamanlayıcımız hala artıyor olacak, çünkü o anda artma işlemi programdan bağımsız ve donanımsal olarak yürütülüyor. işte daha hassas uygulamalarda bu modül kesme geldiği anda donanımsal olarak o andaki TMR1 değerini başka bir kütüğe atıyor ve herhangi bir yanlışlığın olmasını engelliyor.

TMR1'i de şu sebepten 0'lıyoruz: diyelim ki Timer1 35000'e sayana kadar kesme geliyor. bu kütüğü sıfırlamadığımız durumda yine 35000 süre sonra bir kesme geldiğinde kütük taşacak ve okuyacağımız değer 5000 gibi bir şey olacak. bu durumda hızlanmamış olduğumuz halde sanki aniden 7 kat hızlanmışız gibi bir değer elde edeceğiz.

peki neden TMR1 kesmesine giriyoruz. diyelim ki tekerlek durdu. bu durumda bir daha kesmeye giremeyeceğiz ancak zamanllayıcımız saymaya devam edecek ve belli bir zaman sonra taşacak. biz bu taşmayı yakalayamazsak en son hızda devam ettiğimizi sanarız. ayrıca timer1 kesmesinin içinde zamanlayıcıyı sıfırlamaya gerek yok zaten kendisi 0'lanıyor : ) orada yalnızca tekerleğin durduğunu - ya da aşırı yavaşladığını - kullanıcıya göstermek gibi işlemler yapılabilir.

hız hesaplamasında ise örneğin 25000 gibi bir zaman değeri okuduysan yukarıdaki durumda 25000/125000 = 0.2 s ' de bir tekerlek aynı konuma geliyor. bu durumda (tekerlek çevresi) / 0.2 = (çizgisel hız) : ) ben tamamen attım tabi ki. hangi hızlara ulaşacağını bilmiyorum, tüm hesaplarını, kaçıncı yükselen kenarı seçmen gerektiğini, timer1 frekansını ne kadar ölçekleyeceğini, hatta fazladan bir sayaç koyarak - yazılımsal olarak - daha da hassas ölçümler yapmanın gerekliliği tamamen sana kalmış.

kolay gelsin.
++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.