Pic16f877 Rotary Encoder problemi...

Başlatan samil134, 12 Kasım 2008, 22:16:51

samil134

merhabalar...

picbasicte pic16f877 ile rotary encoder controllü bir devre yapmak istiyorum...

bu devrede rotary encoderi saat yönünde çevirdiğimde, sadece portd.4, tersine çevirdiğimde ise sadece portd.5'ten çıkış okunsun  (bu bitlerin biri '1' iken diğeri '0' olsun) ve aynı zamanda da lcd ekrandan okuyabilmek istiyorum.

internetten araştırdığım kadarıyla, bi kod hazırladım.

elimde 2 adet rotary encoder mevcut. biri ALPS'in (korg pa80'den bozulduğu için sökmüştüm) diğeri ise, piyasa bulunan satandart pulse encoder...


1. problemim,

LCD'de Alps'in rotarysi ile okduğum bilgiyi, piyasan aldığım rotary ile okuyamıyorum. (sabit kalıyor ya da 1 ileri giderse hemen ardından 1geri sayıyor)

2. problemim ise,


saat yönünde çevirdiğimde, sadece portd.4, tersine çevirdiğimde ise sadece portd.5'ten çıkış okunsun işlemini iki rotary ile de gerçekleştiremiyorum....

lütfen yardım :(

Alıntı YapTRISA=0
TRISB=0
TRISC=0
TRISD=%00000000
PortC=%00000011
PortA=%00000000
'-------------------------------------------------------------------------------
@ DEVICE pic16F877
@ DEVICE pic16F877, WDT_on
@ DEVICE pic16F877, PWRT_ON
@ DEVICE pic16F877, PROTECT_OFF
@ DEVICE pic16F877, XT_OSC
'-------------------------------------------------------------------------------
DEFINE LCD_DREG      PORTB   
DEFINE LCD_DBIT      0      
DEFINE LCD_EREG      PORTB   
DEFINE LCD_EBIT      5      
define LCD RWREG                    PORTB  
define LCD_RWBIT                    7      
DEFINE LCD_RSREG                  PORTB   
DEFINE LCD_RSBIT                   4      
DEFINE LCD_BITS      4   
DEFINE LCD_LINES                   2   
'-------------------------------------------------------------------------------


kod:
eski_deger      VAR BYTE
yeni_deger       VAR BYTE
direction_bit    VAR BIT
enc_counter    VAR WORD
adval      VAR WORD         
potval      VAR WORD
servo_val      VAR WORD
difference      VAR WORD
   
TRISd=%00000011
enc_counter=120      
HPwm 0,100,20000   
   
   

   yeni_deger= PORTd & %00000011
basla:
   eski_deger = yeni_deger
   
   
tekrarla:
   yeni_deger = PORTd & %00000011
   'LCDOut $fe,1,"elde yok"
   IF yeni_deger = eski_deger Then tekrarla

   direction_bit = eski_deger.bit0 ^ yeni_deger.bit1
   portd.4=0
   portd.5=0
   IF direction_bit = 1 Then  
   
      LCDOut $fe,1,"saatYonu"
      enc_counter = enc_counter + 1
      LCDOut $fe,$c0,DEC enc_counter
     
portd.4=1:pause 50:portd.4=0    
   
Else
      LCDOut $fe,1,"tersi"
      enc_counter = enc_counter - 1
      LCDOut $fe,$c0,DEC enc_counter   
       
portd.5=1:pause 50:portd.5=0

   EndIF
      GoTo basla

mytap

16F serisi ile biraz zor okursun. Birde encoderin devir hızı yüksekse bu iş 16F serisi 4 cycle da bir işlem yapan mcular için imkansız. Birkaç yol var okumak için sağlıklı olması için donanım kesmesi kullanman gerek. Diğer yandan kodunda 50ms gibi bi zaman koymuşsun burda işlemci zaten bekliyor bu zaman içinde belkide encoderin açısı değilmiş olacak. Diğer yandan LCD ye bişeyler yazarkende beklemede kalacak genel pulslar yine kaçtı. uzun uzadıya bi program yazamam ama fikir açısından şöyle yapabilirsin

Encoderin A ve B uçlarını kullanacaksın
Herhangi birini referans alıp işlemcinin kesme pinine gireceksin, diğerininde herhangi bir pine gireceksin

Program akışı şöyle olacak;
......kesmeleri kur!
basla:
.
lcd ye verileri gönder
.
diğer işlemleri yap
.
goto basla

Kesme_Rutini:
registerleri kaydet
bu rutine hergeldiğinde Encoder_A=1 dir bu tamam
şimdi diğer ucun bağlı olduğu pini bul ve konumunu tespit et
karşılaştırma yaparak encoderin konumunu bul

bu rutinde oldukça kısa işlem yapıp hemen terketmek gerek
flagları temizle
return
registerleri tekrar yükle
-------------------------------------------------------- hayırlı günler, iyi çalışmalar..  --------------------------------------------------------

samil134

@mytap

yardımlarınız için çok teşekkür ediyorum. bişeyler canlandı kafamda sayenizde :)

hemen başlıyorum...

ete

Aslında bayağı yaklaşmışsın işi çözmeye ama bazı eksiklerin var. Öncelikle encoderi PortD ye bağlamışsın (sanırım) ama TrisD de her hangi bir pini giriş olarak ayarlamamışsın. Giriş olarak ayarladığın C portunda ama encoder okuma kısmında D portunu kullanmışsın. Hatan buradan kaynaklanıyor. Yoksa kodun çok yanlış değil ancak lüzumsuz satırlar var.
Senin kod üzerinde tartışmaktansa yenisi üzerinde açıklama yaparak bilgi vermek istiyorum;
ENC:
ESKI= PORTD & %00000011
basla:
YENI = PORTD & %00000011
'LCDOut $fe,1,"elde yok"
IF YENI=ESKI THEN BASLA
'Burada encoder konum değiştirinceye kadar YENI ile ESKI birbirine eşit kalacaktır. O yüzden değişen konumu yakalamaya çalışacağız.

YON=ESKI.Bit0 ^ YENI.Bit1
IF YON=1 then 
   PORTD.4=1
ELSE
   PORTD.5=1
ENDIF
GOTO ENC 'yeniden yön tayini için

Alps in rotary encoder'i dediğine göre bir encoder pot okutmaya çalışıyorsun. Bu tip encoderler grey kodu verirler ama sonuçta sana okuma ve yön tayini için yeterli olacaktır.  Dikkat edeceğin husus yalnızca bir tıklama dönüşünde encoderin 00 01 11 10 kodlarını ürettiği olacaktır. Her tıkta yalnızca tek bilgi üretilmemektedir. Bu nedenle yanılıyor olabilirsin.
Yapacağın iş ne kadar hızlı cevap istiyor bilmiyorum ama tek encoder için 4 MHz'in yeterli olacağını sanıyorum. Ama iki adet okutacak isen en azından 10MHz veya 20 MHz osilatör kullanmanda yarar var.
Ben iki adet ALps encoder'i bir güç kaynağı volt ve amper ayarları için kullandım. Sorunsuz çalışıyorlar.
Bu arada Encoder Potların ufak bir hazırlığı olması gerek. Yanlış hatırlamıyorsam 3 adet çıkışı mevcut ve ACB şeklinde diziliyor. A ve B uçlarını birer direnç ile (10K) pullup yapman gerek. C ucunu da GND ye bağlayarak okumaya hazır hale getirebilirsin.
Bu durumda A ve B uçlarınıda pic'e gireceksin.
İkili encoderin aynı anda okunmasına örnek istersen aşağıdaki kodu incele. Anlayasın diye programınbaşında tanımlanacak bazı kritik değişkenleri baş tarafa yazdım. ;

YON_VA    VAR  OLD.4
YON_VB    VAR  NEW.5
YON_AA    VAR  OLD.6
YON_AB    VAR  NEW.7
YONA        VAR   Bit
YONV        VAR Bit

ENCODER:
	   degis=1:SURE=0
BIR:	    
        OLD = PORTB & %11110000
         
TEKRAR:
        gosub ekran_set'o anda okunmuş değerler ekrana veriliyor	
        NEW = PORTB & %11110000
	      IF NEW = OLD Then 
          SURE=SURE+1
          if SURE=50 then KAYIT'belirli bir süre encoder çevrilmez ise okumadan çıkıyoruz ve son değerleri kayıt edip programın diğer yerlerindeki işleri yapıyoruz.
          goto TEKRAR
        endif
        SURE=0
        IF (OLD & %00110000) = (NEW & %00110000) THEN AMPER
        YONV=YON_VA ^ YON_VB :DEGIS=0
        VOLT_SET=VOLT_SET+1-2*yonv 'yonv nin değerine bağlı olarak Volt=Volt+1 veya Volt=Volt-1 yapılıyor

             
AMPER:
       IF (OLD & %11000000) = (NEW & %11000000) THEN CIK
       YONA=YON_AA ^ YON_AB:DEGIS=0
       if (NEW & 192)=192 then akim_set=akim_set+(50-100*YONA)*(POZ+1)

CIK:           
       sure=0   
       OLD=NEW
       GOTO TEKRAR


Kolay Gelsin
Ete
Bilgi hazinedir paylaştıkça büyür.            http://etepic.com

samil134

allah senden razı olsun abicim...

hem daha iyi anladm, hem de kara kara düşünerek uykuya daldığımda rüyamda, 00 10 11 00... kâbuslarından kurtuldum...

çok teşekkür ediyorum...