avatar_Mucit23

Timer ile ileri geri Encoder sayımı?

Başlatan Mucit23, 04 Kasım 2013, 19:55:36

Mucit23

Merhaba Arkadaşlar. Ufak bir sorunum var.

İncremental Encoderler'i bilirsiniz.
http://www.robotshop.com/ca/en/cytron-incremental-rotary-encoder.html

Bu encoderleri kullanarak bir motorun mil açısını ölçmem gerekiyor. Encoder tur başına 3600 pals veriyor.
Normalde motor tek yöne dönse sıkıntı yok ama bende motor diyelim 90derece sağa dönmüşken durup geri dönebilir.  Bu durumda diyelim 90 derecede 900 pals gelmişse geri dönmeye başladığında timerdeki sayacında geri saymaya başlaması lazım.
Piclerde donanımsal olarak yapmam mümkün değil çünkü timer tek yönlü sayıyor. Benim bu işi yazılımsal olarak çözmem lazım fakat tüm sayım işleminide yazılımsal olarak yapamam öyle olursa pals kaçırırım.

Encoderin hangi yöne döndüğünü takip edebiliyorum. Ayrıca encoderin A sinyalini timer1'in harici saat girişine bağlamışım.

Yine timer1 donanımını kullanarak bu işi nasıl yapabilirim. Ete Hocam fikriniz varmı?
Bir ulusu yok etmenin En iyi yolu o ulusun dilini yok etmektir.

www.arectron.com/

ete

Encoder çıkışını timer0 veya Timer1 sayacının harici girişine bağladın anlaşılan. Hangi yönde dönerse dönsün yalnızca bir yöne oda artırmaya yönelik sayma yapacaktır.
Tabiiki tercihin yanlış. Bu iş Timer sayacın harici girişi ile olmamalı. ELinde encoder A ve B çıkışları olduğuna göre ya 18F serisinde INT0 kesmesi ve INT1 kesmelerini kullanarak bu iş mükemmel yapılabilirdi.
Her neyse iş yapılmış bitmiş anlaşılan. Mevcut durumu nasıl kurtarırız ona bakalım.
Yön tayini yapabiliyorsan , Yon=1 iken (saat Yönü) sistem normal artırma yönünde saysın. Bunuda gösterirken
direk timer değerini alıp ekrana verebilirsin.
ANcak encoder tersine dönünce Yon=0 olacak ve bu durumda yon değiştiği anda ;
- Eskı=Timer
- Timer=0
- Encoder=ABS(eski-encoder) şeklinde atamalar yapıp doğru değeri saydırmış olacaksın.
Başka bir yol aklıma gelmedi maalesef.

Ete

Mucit23

#2
Hocam Aslında daha sistemi kurmadım ama timer1 ile yapacağım. RB0 kesmesi ile yapmak istemiyorum. Galiba sizde aynısını söylediniz ama benim aklıma gelen sistem şöyle. Yine anlatayım.

Encoderin A,B ve Z sinyalleri var. A sinyalinin timer Girişine bağlı olduğunu düşünelim.

Encoder Sağa dönüyorken Timer Sürekli arttırılsın. Her Z sinyali alındığında (yani mil tam tur döndüğünde) timer sıfırlansın. Dolayısıyla sağa dönüşte sürekli olarak encoder değeri elimizde olur.

Eğer Sola döndüğünü tespit edersek hemen timer değeri geçici bir değişkene kaydedilir ve timer sıfırlanır. Ardından Bir sonraki timer okumasında timer değeri artmışsa bir önceki geçici değerden çıkarılır. Bu elde edilen değeri tekrar geçisi değişkene kaydedip timeri sıfırlarız.  Bu şekilde Encoder kaç puls vermiş Sürekli elde olur.

Sadece timer değeri sıfırın altına inerse biraz iş karmaşıklaşıyor. Onuda çözebilirim sanırım


Bir ulusu yok etmenin En iyi yolu o ulusun dilini yok etmektir.

www.arectron.com/

İlyas KAYA

Sayın mucit ;

Timer ile yapdığınızda encoder 'ın palslerinde kaçırma yapmazmısınız ?
TIMER sayıma başladığı anda puls girişi olsa bu puls girişini kaçırmaz mı ?

Daha geçen gün bununla (2 palsli A ve B,Z) ilgili bir çalışmam oldu ve ben "RB CHANGE INTERRUPT"  (Portb.4-Portb.7) kullandım.
16f876 veya 16f877 'de RB change interrupt var.

Hiçbir kaçırma yapmıyor.
Yada bir flip flop kullanarak da en hızlı çözüme ulaşabiliyorsunuz.



Bir önceki A nın durumunu yeni A ile xor layıp , çıkan sonucu da B ile xor lar isek sonuca bakıp karar verebiliyoruz.



Aşağı doğru sonuç 1 , yukarı doğru işlem yapıldığında sonuç 0 olacaktır.

Buna göre sayım yaparsanız encoder her pozisyon değiştiğinde yukarı veya aşağı sayım yapabileceksiniz.

HAZIR KONUSU AÇILMIŞKEN

2 puls encoderlar bu şekilde hem yön hemde sayım yapılabiliniyorken ben BLDC motorlardaki hall sensör'ü aynı mantık ile yahut farklı bir mantık ile basitce yapabileceğim bir formül çözemedim.

Pozisyona göre bir öncekine bakılarak yapılabiliyor ancak if lerden ibaret oluyor.
Her komut da beklemeye davetiye çıkarttığı için en kestirme yol sizce nasıldır ?

3 puls encoder'ı nasıl decode edebiliriz bilginiz var mı ?

Göz odur ki dağ ardını görsün,
Akıl odur ki başa geleceği bilsin.!

Mucit23

İlyas bey Sistemi yanlış anladınız galiba.

Ben Timer ile zaman tutmuyorum. Timer1 modülünü harici saat girişine ayarlıyorum. Sayım için clock darbelerini dışarıdan, encoderden gelen clock sinyalleri sağlıyor. Yani Clock darbeleri direk Timerin değerini arttırıyor. Bu durumda neden kaçırma olsun?

Sadece Timer 16Bitlik olduğu için timer değerini 65535'i aşmasına izin vermemek gerekiyor. Bu durumda zaten bende mümkün değil.

İsiste şöyle bir devre kurdum. Encoder Yön tayinini  Ete Hocanın 4013'lü flip flop devresi ile yapıyorum. Sıkıntı yok gibi


ücretsiz resim barındırma

İşi 16F ile Götüreceğim. Bakalım İsiste sağa dönüşte problem yok. Sola dönüşüde yapmadım. Onada bakacağım.

Sizin Sorunuza gelince,

Hal sensörleri normal rotary encoderler gibi çıkış sinyali vermesi gerekiyor.

Normalde STM32 serisi işlemcilerde Birçok Timer bulunuyor ve Bu timerler direk Encoder sayımı için Configre edilebiliyor.

Piclerde ise bu iş için hazır modüller olacaktı. Yani Encoder sayımı için kullanılıyor. Fakat encoder değeri ile direk pwm modülü arasında bağlantı kurulabiliyormu onu bende çözemedim.
Bir ulusu yok etmenin En iyi yolu o ulusun dilini yok etmektir.

www.arectron.com/

İlyas KAYA

#5
Teşekkür ederim sayın Mucit23.

Evet söylediğinizi şimdi daha iyi anladım. Aynen benimde bahsettiğim flip flop devresi bu.
Hatta bence yazılımdan daha iyi çalışıyor :)


Malesef benim PIC'i değiştirme şansım artık yok gibi. 16F876A ile yapmak zorundayım.

Az önce hallettim ama işte if lerden ibaret oluyor.

Örneğin ;
001 = 1
010=2
..
..

Yapıp bir öncekinden şuankini çıkarttım. Yani 2-1 =1 oldu.
Eğer sonuç 1 ise sağa -1 yani 254 ise sola dönüş gibi.

1400 devir ile dönerken bakalım ne kadar kaçırma yapacak.
Allah tan sıkışma kontrolü yapıp stop noktalarını buluyorum. Stop noktalarında sayımları sıfırlıyorum.

Siz de Z noktası var BLDC encoder'inde o da yok :)



Göz odur ki dağ ardını görsün,
Akıl odur ki başa geleceği bilsin.!

F®T

selamlar.Mucit23 bende 18f serisinde ete hocanın yardımı ile dediğin gibi bir uygulama yaptım.yapacağım dediğin gibi encoderden gelen puls ile timer saymak.bende o şekilde yaptım  8 khz lik frekansı rahat yakaladığım.yön olayı içinse diğer tmr kesmesini senin motor frekansından daha hızlı ayarlarsan kesme içindede yön kontrolüne göre artırma yada çıkarma yaparsın.misal encoderdan gelen sinyal frekansın 5 khz olsun max olarak. sen bunu zaten tmr ile sayıyon.bu kaçmaz sorun yok.diğer kesme süresini sayma hızından daha hızlıya ayarla.kesme içindede sürekli yöne göre artı yada eksi olayını yap.eğer artı yönde ise zaten artırırsın eksiye dönersede değeri bir değişkene atıp tmr dan saydığını bu sefer direk çıkartırsın.yön değişirse yine tmr değerini o anki değerle eşleştirir üstüne devam edersin.
"Hakk" şerleri hayr eyler Zannetme ki gayr eyler Ârif anı seyreyler Mevlâ görelim neyler Neylerse güzel eyler.

İlyas KAYA

#7
BLDC encoder'i ile ölçümü şu şekilde yaptım. Verdiğim PWM ile ölçtüğüm değer şuan aynı.
Amacım devir ölçmek değil yük bindiğinde otomatik tork arttırmaktı ve şuan çalışıyor.

Belki fikirler verebilir diye kodlardan örnekler vereyim.


RB değişim kesmesi çalıştırıldığında (Encoderdan herhangi biri değiştiğinde);

REF=30 ' veya ayarlı bir değişken olabilir.

KESME:

HIZABAK=HIZABAK+1        'HIZA BAK DİYE BİR DEĞİŞKENE HER KESME de BİR EKLEDİM.


'encoder pozisyonuna göre yukarıdaki mesajımda yazdığım gibi her pozisyon için numara verip bir öncekinden çıkartarak yön tayini yaptım ve aynı zamanda mosfetleri sürdüm.

IF ENCA=1 AND ENCB=0 AND ENCC=0 THEN
ENC=1
PORTC=17
ENDIF

IF ENCA=1 AND ENCB=0 AND ENCC=1 THEN
ENC=2
PORTC=24
ENDIF

IF ENCA=0 AND ENCB=0 AND ENCC=1 THEN
ENC=3
PORTC=72
ENDIF

IF ENCA=0 AND ENCB=1 AND ENCC=1 THEN
ENC=4
PORTC=192
ENDIF

IF ENCA=0 AND ENCB=1 AND ENCC=0 THEN
ENC=5
PORTC=160
ENDIF

IF ENCA=1 AND ENCB=1 AND ENCC=0 THEN
ENC=6
PORTC=33
ENDIF


ENCYON=ENCESKI-ENC                    'bir önceki encoder numarasından şuankini çıkarttım.

ENCESKI=ENC                                   'mevcud encoder pozisyonunu başka bir değişkene atadım

IF ENCYON=1 or ENCYON=251 THEN COUNTER=COUNTER-1     'aşağı doğru inildiğinde sonuç 1 ve 1-6 251 çıkıyor. Buna göre sayımı eksiltiyorum.

IF ENCYON>=255 OR ENCYON=5 THEN COUNTER=COUNTER+1 'yukarı doğru çıkıldığında kendinden  1 fazla olan çıktığı için 255 değerini veya  6-1 olduğu konumda da 5 değerini aldığında sayımı arttırıyorum.



RESUME




ANADONGU:

HIZSURESI=HIZSURESI+1             'ana döngüde  bir değişkeni daha arttırtırdım.


IF HIZSURESI>=2 Then                     ' Anadöngümde shiftout ve tüm beklemeler 100 ms. hız süresi bende yaklaşık 200ms de bir ölçüyor

HIZSURESI=0

ESASHIZ=HIZABAK                            ' esashızımız kesmedeki değişkene eşitleniyor (ben dislpayden takip edip eşitlemek için HIZABAK 'a 4 işlem uyguladım. PWM =50 iken  200ms 'de ölçtüğüm değer 36 idi. Buna göre % hesabı yapıp hatayı hızabak'a ekledim

HIZABAK=0                                       ' kesmedeki değişken sıfırlanıyor

HATA=REF-ESASHIZ                         ' ölçtüğümüz hız ile PWM referans değeri arasındaki farkı buluyorum
IF ESASHIZ>REF THEN HATA=0       ' eğer motor hızı referans hızdan yüksek ise hatayı sıfırlıyorum.Aksi halde işlem sonucu - yani 255 den aşağı doğru olur ve motor biranda fırlar.
ENDIF


hpwm 1,ref+hata,14000           ' PWM sürüşü


goto anadongu
Göz odur ki dağ ardını görsün,
Akıl odur ki başa geleceği bilsin.!

Mucit23

6 Adet PWM kanalı olması gerek.

Tek PWM ile nasıl çözdünüz? Portu bir Bufferdenmi geçirdiniz?
Bir ulusu yok etmenin En iyi yolu o ulusun dilini yok etmektir.

www.arectron.com/

İlyas KAYA

Sayın Mucit23; Hayır tek kanal ile çözdüm.

74HC08 'in 1'er girişlerini ortaklayıp PWM kanalına bağladım.
Kalan girişleri PIC ile kontrol ettim :)
74hc08'in gerilimini zener ile 7,2volt tuttum.

Göz odur ki dağ ardını görsün,
Akıl odur ki başa geleceği bilsin.!

Mucit23

Örnek bir program yazdım..

#include <16F628A.h>
#include "stdlib.h"
#FUSES NOWDT                    //No Watch Dog Timer
#FUSES INTRC_IO                 //Internal RC Osc, no CLKOUT
#FUSES NOBROWNOUT               //No brownout reset
#FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOMCLR

#use delay(int=4000000)

#use fast_io(a)
#use fast_io(b)

#include <lcd_driver.c>

#define yon pin_b5
#define zero pin_b4
#define encoder_res 3600

signed   int16 time_count=0;
unsigned int16 counter=0;
unsigned int16 enc_round_val=0;
float angle=0;

float calc_ange  (int16 counter);

void main()
{
   set_tris_a(0x00);
   set_tris_b(0x70);
   output_a(0x00);
   output_b(0x00);
   
   setup_ccp1(CCP_OFF);
   setup_timer_1(T1_EXTERNAL | T1_DIV_BY_1);
   set_timer1(0);
   
   lcd_init();
   printf(lcd_putc,"\f");
   
   while(TRUE)
   {
      if(input(yon))
      {
        counter+=get_timer1();
        set_timer1(0);
        time_count=counter;
        if(counter>=encoder_res)
        {
          counter=0;
          enc_round_val++;
          if(enc_round_val>9999)enc_round_val=0;
        }
       
        angle=calc_ange(counter);
       
        lcd_gotoxy(1,1);
        if(angle>99.9){
          printf(lcd_putc,"Aci Degeri=%3.1f",angle);
        }else if(angle>9,9){
          printf(lcd_putc,"Aci Degeri=%3.1f  ",angle);
        }else if(angle<10.0){
          printf(lcd_putc,"Aci Degeri=%3.1f   ",angle);
        }
        lcd_gotoxy(1,2);
        printf(lcd_putc,"Tur=%04ld",enc_round_val);
      }
      else
      {
           time_count-=get_timer1();
           set_timer1(0);
           
           if(time_count<0)
           {
             time_count=encoder_res-abs(time_count);       //Sayı negatif olmuşsa
             enc_round_val--;
             if(enc_round_val>9999)enc_round_val=9999;
           }
           counter=time_count;
           angle=calc_ange(counter);
         
        lcd_gotoxy(1,1);
        if(angle>99.9){
          printf(lcd_putc,"Aci Degeri=%3.1f",angle);
        }else if(angle>9,9){
          printf(lcd_putc,"Aci Degeri=%3.1f  ",angle);
        }else if(angle<10.0){
          printf(lcd_putc,"Aci Degeri=%3.1f   ",angle);
        }
       
        lcd_gotoxy(1,2);
        printf(lcd_putc,"Tur=%04ld",enc_round_val);
      }
   }
}



float calc_ange(int16 counter){
return (float)(counter*360.0)/encoder_res;
}


Encoderin Kaç Derece döndüğü ve kaç tur döndüğünü yazdırıyorum. Encoder sola dönünce değerler azalıyor.  Kullandığım encoder tur başına 3600 pals veriyor.
Bir ulusu yok etmenin En iyi yolu o ulusun dilini yok etmektir.

www.arectron.com/

Mucit23

Bir sorum olacak
Teyp lerde kullanılan pot tipi encoderler bir turda örneğin A pininden kaç pals verir?
Bir ulusu yok etmenin En iyi yolu o ulusun dilini yok etmektir.

www.arectron.com/

ete

Standart bir değer varmıdır pek bilemiyorum. Dönüş hareketi tık-tık lar şeklindedir. Her tık için A ve B çıkış olarak ,%00 - %01 - %11 ve %10 şeklinde bir sinyali çıkışı vardır.  Bu durumda yalnız A olarak bakarsak 0-1-1-0 şeklinde bir çıkış görürsinki bu yalnızca 1 puls demektir. O halde tur başına tıkları sayarsan her tık 1 puls olarak kabul edilerek kaç tık var ise tur başına o kadar puls alırsın demek olur.

Ete

Powered by EzPortal