CCS-C Encoder okuma ve seri iletişim

pic_loader

Üye
Katılım
13 Eki 2009
Mesajlar
42
Puanları
1
Arkadaşlar merhaba.

Daha önce yardımlarınızı rica ettiğim çalışmada programlama dili olarak SALİH-46 hocamın tavsiyesiyle ccs kullanmaya çalışıyorum.

Şu an yapmak istediğim encoderin ürettiği pulse'leri sayıp seri iletişim ile bilgisayara göndermek.

Bunu başarırsam sonraki aşamada pwm sinyalleri üretmeye çalışacağım.

Acemice de olsa bu amaç için bir kod yazdım.

Encoder'in pulse üreten bacağı RB0 pinine, yön bilgisini alacağımız bacağı ise RB3 pinine bağlı diye farzediyorum(bu tercihlerim hatalıysa lütfen belirtin), diğer iki pin ise seri iletişim için.

Kod:
#include <16F628A.h>

#FUSES NOWDT                    //No Watch Dog Timer
#FUSES XT                       //Crystal osc <= 4mhz
#FUSES NOPUT                    //No Power Up Timer
#FUSES NOPROTECT                //Code not protected from reading
#FUSES NOBROWNOUT               //No brownout reset
#FUSES NOMCLR                   //Master Clear pin used for I/O
#FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOCPD                    //No EE protection

#use delay(clock=4000000)
#use rs232(baud=9600,parity=N,xmit=PIN_B2,rcv=PIN_B1,stop=1)

#use fast_io(b)
#priority ext, tbe

signed int16 palse_konum=0;


#int_ext
void harici_kesme () {
   
   if(input(pin_b3))
      palse_konum--;
   else 
      palse_konum++;
}

#int_tbe
void seriletisim_gonder(){

   puts(palse_konum);
   disable_interrupts(int_tbe);

}


void main(){
   
   setup_timer_1(T1_DISABLED);
   setup_timer_2(T2_DISABLED,0,1);
   setup_ccp1(CCP_OFF);
   
   set_tris_b(0b00001011); //RB0, RB1 ve RB3 giris, RB2 cikis
   output_b(0x00);
      
   
   ext_int_edge(H_TO_L);
   enable_interrupts(int_ext);
   enable_interrupts(global);

   while(1);
}

SALİH-46 hocamın önerisiyle Serdar Çiçek'in kitabını aldım, orada seri iletişim örneğinde int_tbe kesmesi hakkında kod örneği bulamadım.

Acaba burada kodu yanlış kullandım mı bilmiyorum :)

Bir diğer bilmediğim ext kesmesinde kitapta gördüğüm şu bilginin ne anlama geldiği.

ext_int_edge(H_TO_L); komutu ile dış kesmenin, giriş sinyalinin yüksek kenardan düşük kenara geçişi sonunda olması sağlanmıştır.

Şimdi doğrusu yüksek kenar düşük kenar nedir onu dahi hala anlayamadım, burada tam olarak ne söylendiğini bana anlatabilir misiniz?

Son olarakda burada yön bilgisi için şöyle bir bilgiye ihtiyacım var, encoder saat yönünde döndüğünde RB3 pinine bağlı bacak lojik "1" mi olur "0" mı?

Artırma yada eksiltmeyi buna göre yapmalıyım.

Yardımlarınız için şimdiden teşekkür ediyorum.
 
Arkadaşım önce yükselen kenar düşen kenar olayını açıklayım yükselen kenar demek bilginin 0 dan 1 e geçiş anı düşen kenar ise 1 den 0 da geçiş anıdır.
ext_int_edge(H_TO_L); bu komutla kesmenin 1 den 0 a geçiş anında oluşacağı söyleniyor.
İkincisi rs232 ile kod gönderirken kesme kullanmasanda olur genelde kesme alma işleminde kullanılır tam olarak emin olamasamda :))

Yön bilgisini ise encoderin datasheet'inden öğrenebilirsin yada eline ölçü aletini al ölç :))

Yalnız seninki encodermi takometremi encoderlerde daha fazla uç var diye biliyorumm.
Umarım açıklayıcı olmuştur iyi çalışmalar.
 
interrupt içerisinde disable_interrupts(int_tbe); yazmana gerek yok. silebilirsin.

kesmelere hiç girmeyin. Programınızı while (){...} döngüsü içerisinde bacak tarama ve seri bilgi gitti flagini tarama ile rahatlıkla yapabilirsiniz. İnanın kesmelerden daha hızlı çalışır bu yöntem. Kesmeye gittiğinizde sizin iradeniz dışında derleyicinin mcuya yaptırdığı o kadar çok iş var ki, aynı şekilde kesmeden geri dönüşte, listing den görünce bana hak vereceksiniz.

Her seri bilgi gittiğinde peşinden aynı bilgiyi göndermek yerine, encoder bağlı bacaklardaki durum değişince bilgiyi göndermek daha mantıklı.
 
Merhaba
Hocam öncelikle bence siz o seri iletişim kesmesini iptal edin yani orayı kaldırın şimdilik zaten o şekildede bir kesme bildirimi yok ccs c de (#int_rda: seri iletişim kesmesi) yani siz bu programı ccs c de derlediyseniz hata verdiğini görmüş olmanız lazım şimdi sen rb0 pinine encoder'ın puls sinyalini verdin yön sinyalini ise rb4 (giriş olarak ayarla) pinine ver nedeni ise sen pwm çıkışını rb3'ten alacaksın o nedenle rb3 şimdilik boş kalsın ve hiç timer kullanma yani tek yapacağın şey encoder'ın puls ucundan gelen sinyalin düşen kenarında (H_TO_L) kesme oluşturacaksın kesme alt programında rb4 pinini kontrol edip ona göre puls sayısını artır veya azalt ve bence yine kesme içinde seri olarak yollayacağın verileri gönder.
Proğramında ise bu blokları kaldır
***********
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DISABLED,0,1);
setup_ccp1(CCP_OFF);
*************
#int_tbe
void seriletisim_gonder(){

puts(palse_konum);
disable_interrupts(int_tbe);

}
**************************
 
Arkadaşım önce yükselen kenar düşen kenar olayını açıklayım yükselen kenar demek bilginin 0 dan 1 e geçiş anı düşen kenar ise 1 den 0 da geçiş anıdır.
ext_int_edge(H_TO_L); bu komutla kesmenin 1 den 0 a geçiş anında oluşacağı söyleniyor.

Hocam bilgi için teşekkürler, ancak böyle ise yani yükselen kenar 0 dan 1'e geçiş ise kitapta söylenen ext_int_edge(H_TO_L); bunu sağladığına göre bana da bu lazım çünkü encoder pulse ürettiğinde ben kesme oluşmasını istiyorum buda lojik "1" olacak.

İkincisi rs232 ile kod gönderirken kesme kullanmasanda olur genelde kesme alma işleminde kullanılır tam olarak emin olamasamda :))

Yön bilgisini ise encoderin datasheet'inden öğrenebilirsin yada eline ölçü aletini al ölç :))

Anlıyorum teşekkür ederim.

interrupt içerisinde disable_interrupts(int_tbe); yazmana gerek yok. silebilirsin.

kesmelere hiç girmeyin. Programınızı while (){...} döngüsü içerisinde bacak tarama ve seri bilgi gitti flagini tarama ile rahatlıkla yapabilirsiniz. İnanın kesmelerden daha hızlı çalışır bu yöntem. Kesmeye gittiğinizde sizin iradeniz dışında derleyicinin mcuya yaptırdığı o kadar çok iş var ki, aynı şekilde kesmeden geri dönüşte, listing den görünce bana hak vereceksiniz.

Her seri bilgi gittiğinde peşinden aynı bilgiyi göndermek yerine, encoder bağlı bacaklardaki durum değişince bilgiyi göndermek daha mantıklı.

ze_tr hocam küçük bir bilgi gönderme örneği bana gösterebilir misiniz?

Birde asenkron iletişim düşünüyorum bu iş için, bu doğru bir tercih mi?

Merhaba
Hocam öncelikle bence siz o seri iletişim kesmesini iptal edin yani orayı kaldırın şimdilik zaten o şekildede bir kesme bildirimi yok ccs c de (#int_rda: seri iletişim kesmesi) yani siz bu programı ccs c de derlediyseniz hata verdiğini görmüş olmanız lazım

Ve SALIH-46 hocam :)

Hocam önce bana ayırdığın zaman için sana çok teşekkür ediyorum.

Sonra bu kodu derledim hocam ve bir error almadım ama madem hepiniz bilgi göndermek için kesme kullanma diyorsunuz kullanmayalım.

Bana basit bir örnek gösterebilir misiniz bilgi göndermeyle ilgili.

Birde aynı kesme kullanmama önerisi bilgisayardan pic'e bilgi gönderirkende geçerli mi?

Bu işide kesmesiz mi yapmalıyım sizce?

şimdi sen rb0 pinine encoder'ın puls sinyalini verdin yön sinyalini ise rb4 (giriş olarak ayarla) pinine ver nedeni ise sen pwm çıkışını rb3'ten alacaksın o nedenle rb3 şimdilik boş kalsın ve hiç timer kullanma yani tek yapacağın şey encoder'ın puls ucundan gelen sinyalin düşen kenarında (H_TO_L) kesme oluşturacaksın kesme alt programında rb4 pinini kontrol edip ona göre puls sayısını artır veya azalt ve bence yine kesme içinde seri olarak yollayacağın verileri gönder.
Proğramında ise bu blokları kaldır
***********
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DISABLED,0,1);
setup_ccp1(CCP_OFF);
*************
#int_tbe
void seriletisim_gonder(){

puts(palse_konum);
disable_interrupts(int_tbe);

}
**************************

Tamam hocam rb3 ccp1'miş 628a'da doğru :)

Kitapta 877 pici varya karıştırdık.
 
#use rs232 .... ile portu açtıktan sonra

göndereceğin bilgi 1 bayt ise, bilgiyi ham bilgi olarak göndermek için:

putc(deger);

2 bayt ise

putc(*(&deger));
putc(*(&deger+1));

veya deger ile aynı alanı paylaşan iki adet 1 baytlık değişken tanımlayıp tane tane gönderebilirsiniz (union tanımına bakın).

Göndereceğiniz değer ekranda sizin anlayabileceğiniz şekilde görünsün istiyorsanız sayıyı formatlayacaksınız.

printf("%3d", deger);
 
#use rs232 .... ile portu açtıktan sonra

göndereceğin bilgi 1 bayt ise, bilgiyi ham bilgi olarak göndermek için:

putc(deger);

2 bayt ise

putc(*(&deger));
putc(*(&deger+1));

veya deger ile aynı alanı paylaşan iki adet 1 baytlık değişken tanımlayıp tane tane gönderebilirsiniz (union tanımına bakın).

Göndereceğiniz değer ekranda sizin anlayabileceğiniz şekilde görünsün istiyorsanız sayıyı formatlayacaksınız.

printf("%3d", deger);

ze_tr hocam, şimdi ben bilmiyordum printf ile direkt konsola bilgi gönderebiliyor muşuz(salih hocam sağolsun :)) şimdi int16 değerindeki palse_konum değişkenini şu şekilde hyper terminal programına göndermek istiyorum harici kesme içinde.

Mesela değer 400 diyelim, bu çekilde bir gönderim sonucu

Kod:
printf("Pulse: %ld\n\r", palse_konum);

ekranda "Pulse: 400"

yazdırılmaz mı?
 
Evet arkadaşlar şimdi yine acemicede olsa istediğimi yapacağını sandığım kodu yazmış bulunmaktayım, şu an için bildiğim kadarıyla tek sıkıntım mesela hyper terminalden gelecek veriyi sayısal değişkene böyle atabiliyor muyus(derlemede bir hata vermedi)

Kod:
gets(git); // String ifadeyi al git degiskenine aktar

o noktada.


Kod:
#include <16F628A.h>

#FUSES NOWDT                    //No Watch Dog Timer
#FUSES XT                       //Crystal osc <= 4mhz
#FUSES NOPUT                    //No Power Up Timer
#FUSES NOPROTECT                //Code not protected from reading
#FUSES NOBROWNOUT               //No brownout reset
#FUSES NOMCLR                   //Master Clear pin used for I/O
#FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOCPD                    //No EE protection

#use delay(clock=4000000)
#use rs232(baud=9600,parity=N,xmit=PIN_B2,rcv=PIN_B1,stop=1)   // RS232 protokolünün 9600 bit/sn baud hizinda olacagini ve
                                                               // TX,RX uçlarynyn hangi pinler olacagini tanimliyor
                                                               // parity bitinin olmadigini, stop bitinin 1 bit olacagi belirtiliyor

#use fast_io(b)
#priority ext, rda

signed int16 palse_konum=0;
signed int16 git=0;

#int_ext
void harici_kesme () {
   
   if(input(pin_b4))
      palse_konum--;
   else 
      palse_konum++;
      printf("Pulse: %ld\n\r", palse_konum); 
}

#int_rda   // RX ucuna veri gelince meydane gelen kesme
void serihaberlesme_kesmesi (){
   disable_interrupts(int_rda); // int_rda kesmesini pasif yap
   gets(git); // String ifadeyi al git degiskenine aktar
}


void main(){
   
   int8 i=0;
   
   set_tris_b(0b00010011); //RB0 harici kesme giris
                           //RB1 RX giris 
                           //RB2 TX cikis
                           //RB3 CCP1 cikis
                           //RB4 Encoder yon bilgisi giris
                           
   output_b(0x00);
   
   setup_ccp1(CCP_PWM);  // CCP1 birimi PWM cikis icin ayarlandi
   setup_timer_2(T2_DIV_BY_16,250,1); // Timer2 ayarlari yapiliyor
   
   ext_int_edge(H_TO_L);
   enable_interrupts(int_ext);
   enable_interrupts(global);
   
   while(1){
   
      if(git>0){ //bir deger girilmis ise 
         
         if(paalse_konum<git && i<250)
            ++i;
         else if (palse_konum>git && i>1)
            --i;
         
         set_pwm1_duty(i);
   
      }
   }
   
}

Arkadaşlar burada mantıkta, tercih edilen (mesela timer2'de) setup ayarlarında vs bir hata var mı?

Birde ben mesela 4 mhz osilatör ile çalışan bir pikte set_pwm1_duty(i); deyip saykılı artırdığımda her bir adımda çıkışta ne kadar volt alınacağını yaklaşık olarak nasıl hesaplayabilirim.

Üretilecek frekanstan volt hesabını yapabiliyor muyuz?
 
Arkadaşlar, java'dan varolan alışkanlıkla şöyle bir casting yapayım dedim kod derlendi.

Kod:
(signed int16)gets(git);

Olay bu mudur :)

gets ile git değişkenine atılan veri böylece işaretli int16 tipinde mi olmuş oldu?




ps: şimdi farkettim, sonsuz döngü içinde enable_interrupts(int_rda); demeyi unutmuşum.
 
Son düzenleme:
Kod üzerinde biraz daha çalışınca bir mantık hatamı keşfettim.

pulse_konum ile git'i eşitmi değil mi diye kontrol ediyorum ama kol yükseliyor yada alçalıyor mu diye hiç bakmamışım.

Bunun için harici kesme içinde önceki konumu bir değişkene alıp sonsuz döngüde bunuda sınadım.

Birde i değişkeni değişmemişse boşuna set_pwm1_duty(i); ataması yapmamak için bu satırı if bloğu içine aldım.

Kodun son hali:

Kod:
#include <16F628A.h>

#FUSES NOWDT                    //No Watch Dog Timer
#FUSES XT                       //Crystal osc <= 4mhz
#FUSES NOPUT                    //No Power Up Timer
#FUSES NOPROTECT                //Code not protected from reading
#FUSES NOBROWNOUT               //No brownout reset
#FUSES NOMCLR                   //Master Clear pin used for I/O
#FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOCPD                    //No EE protection

#use delay(clock=4000000)
#use rs232(baud=9600,parity=N,xmit=PIN_B2,rcv=PIN_B1,stop=1)   // RS232 protokolünün 9600 bit/sn baud hizinda olacagini ve
                                                               // TX,RX uçlarynyn hangi pinler olacagini tanimliyor
                                                               // parity bitinin olmadigini, stop bitinin 1 bit olacagi belirtiliyor

#use fast_io(b)
#priority ext, rda

signed int16 palse_konum=0;
signed int16 onceki_konum=0;
signed int16 git=0;

#int_ext
void harici_kesme () {
   
   onceki_konum=palse_konum; //Kolun bu kesmeden onceki pozisyonu
   
   if(input(pin_b4))
      palse_konum--;
   else 
      palse_konum++;
      
      printf("Pulse: %Ld\n\r", palse_konum); 
}

#int_rda   // RX ucuna veri gelince meydane gelen kesme
void serihaberlesme_kesmesi (){
   disable_interrupts(int_rda); // int_rda kesmesini pasif yap
   (signed int16)gets(git); // String ifadeyi al git degiskenine aktar
}


void main(){
   
   int8 i=0;
 
   set_tris_b(0b00010011); //RB0 harici kesme giris
                           //RB1 RX giris 
                           //RB2 TX cikis
                           //RB3 CCP1 cikis
                           //RB4 Encoder yon bilgisi giris
                           
   output_b(0x00);
   
   setup_ccp1(CCP_PWM);  // CCP1 birimi PWM cikis icin ayarlandi
   setup_timer_2(T2_DIV_BY_16,250,1); // Timer2 ayarlari yapiliyor
   
   ext_int_edge(H_TO_L);
   enable_interrupts(int_ext);
   enable_interrupts(global);
   
   while(1){
   
      enable_interrupts(int_rda);
      
      if(git>0){ //bir deger girilmis ise 
         
         if(palse_konum<git && palse_konum <=onceki_konum && i<250){
            ++i;
            set_pwm1_duty(i);
         }
         else if (palse_konum>git && palse_konum >=onceki_konum  && i>1){
            --i;
            set_pwm1_duty(i);}
   
      }
   }
   
}
 
Son düzenleme:

Forum istatistikleri

Konular
128,198
Mesajlar
915,766
Kullanıcılar
449,978
Son üye
food_eng_1952

Yeni konular

Geri
Üst