avatar_Mucit23

İki Timer ile servo sürme

Başlatan Mucit23, 24 Nisan 2014, 10:51:23

Mucit23

Dün akşam bu konuda bir çalışma yaptım. Maksat sadece timerler ile servo için gerekli olan 20ms periyotlu, 1-2ms duty değerine sahip sinyali oluşturabilmek.

Pic12F683 kullandım. Genel kullanım için Timer0 ve Timer1 olmak üzere iki adet timeri var. Bu timerleri kullanılarak kesme oluşturuyoruz.

Timer1 sinyalin negatifte kalma süresini ayarlıyor(18-19ms), Timer0 ise sinyalin pozitifte kalma süresini ayarlıyor.(1-2ms). Bu ayarlama işlemlerini Timer Preload değerleriyle oynayarak hesaplıyoruz.

Sistem ilk enerjilendiğinde Timer0 Aktif değildir. Sadece Timer1 aktiftir. İlk kez timer1 kesmesi oluşur. Ardından kesme rutinleri içerisinde Timer0 ve Timer1 açılıp kapatılarak kesme oluşumu kontrol altında tutulur.

Yazılımın mantığı çok basit aslında
'****************************************************************
'*  Name    : Timer_Servo.BAS                                   *
'*  Author  : [select VIEW...EDITOR OPTIONS]                    *
'*  Notice  : Copyright (c) 2014 [select VIEW...EDITOR OPTIONS] *
'*          : All Rights Reserved                               *
'*  Date    : 22.04.2014                                        *
'*  Version : 1.0                                               *
'*  Notes   :                                                   *
'*          :                                                   *
'****************************************************************
DEFINE OSC 4

@ __config _INTRC_OSC_NOCLKOUT & _WDT_OFF & _MCLRE_OFF & _CP_OFF

DEFINE ADC_BITS 10
DEFINE ADC_CLOCK 1
DEFINE ADC_SAMPLEUS 30

ADC_VALUE    VAR WORD
TIM0_PRELOAD VAR WORD
TIM1_PRELOAD var word
TIM0_OFSET   CON 28
TIM1_OFSET   CON 46904

OSCCON=%01100001
TRISIO=%00000111
GPIO=0
CMCON0 = 7
ADCON0=%10000001
ANSEL=%00010001
INTCON=%11000000       ;Enable Global and peripheral interrupts
OPTION_REG=%00000010   ;Timer0 Prescaller Value 1/8
PIE1=%00000001   
T1CON=%00000001
WPU=0

ON INTERRUPT GOTO KESME

TIM0_PRELOAD=TIM0_OFSET    ;Timer0 Preload Value
TIM1_PRELOAD=TIM1_OFSET    ;Timer1 Preload değeri
TMR1L=TIM1_PRELOAD.LOWBYTE
TMR1H=TIM1_PRELOAD.HIGHBYTE

BASLA:
  ADCIN 0,ADC_VALUE

  TIM0_PRELOAD=(((1024-ADC_VALUE)*/125)/4)+TIM0_OFSET
  TIM1_PRELOAD=((ADC_VALUE+1)*/250)+TIM1_OFSET
GOTO BASLA

DISABLE
KESME:
  IF PIR1.0=1 THEN   ;Timer1 interrupt
    INTCON.6=0       ;Disable Timer1
    GPIO.5=1         ;PWM = 1
    TMR0=TIM0_PRELOAD;Set Timer0 Preload Value
    INTCON.2=0       ;Clear Timer0 interrupt Flag
    INTCON.5=1       ;Enable timer0
    PIR1.0=0         ;Clear Timer1 interrupt Flag
  ENDIF
 
  IF INTCON.2=1 THEN ;Timer0 interrupt
    INTCON.5=0       ;Disable Timer0
    GPIO.5=0         ;PWM = 0
    TMR1L=TIM1_PRELOAD.LOWBYTE ;Set Timer1 Preload LSB Value (LowByte)
    TMR1H=TIM1_PRELOAD.HIGHBYTE;Set Timer1 Preload MSB Value (HighByte)
    PIR1.0=0         ;Clear Timer1 interrupt Flag
    INTCON.6=1       ;Enable Timer1
    INTCON.2=0       ;Clear Timer0 interrupt Flag
  ENDIF
RESUME
ENABLE
END


Okunan ADC değerine göre Timer Preload değerlerini bulmak için aşağıdaki hesaplamaları yaptım.

  TIM0_PRELOAD=(((1024-ADC_VALUE)*/125)/4)+TIM0_OFSET
  TIM1_PRELOAD=((ADC_VALUE+1)*/250)+TIM1_OFSET

Burada dikkat edilmesi gereken konu sabit periyot için timerlerin kesme oluşturma sürelerinin birbiriyle ters orantılı olması. Yani Timer0 artışta iken Timer1 azalması gerekiyor

Timer0 1ms ile kesme oluşturuyorsa, Timer1 19ms ile kesme oluşturması gerekiyor
Timer0 1,5ms ise Timer1 18,5ms
Timer0 2ms ise Timer1 18ms ile kesme oluşturması lazım. Arada ters bir orantı var.

Sistem gerçekte çalışıyor fakat kod gecikmeleri çok etkili oluyor ve sürelerin hesaplananın dışında olmasına sebeb açıyor.

Hesaplama için pic Multicalc kullandım.
Örneğin

Timer0 1/8 bölücü oranıyla 1ms için(999uS) Preload değeri 132, 2ms(1999uS) için preload değeri  7 olması gerekiyor.

Timer1 ise 1/1 bölücü oranı kullanıyor. 19ms(18999uS) için preload değeri 46544, 18ms(17999uS) için preload değeri 47544 olması gerekiyor.

Timer0 için 132-7'den aradaki Fark'ın 125 olduğunu görürsünüz. O halde biz ADC'den okuduğumuz değeri 0-125 arasına oranlayıp sonuca 7 eklersek direkmen Timer0 preload değerini hesaplamış oluruz.

Aynı durum Timer1 içinde geçerli. 47544-46544 den aradaki farkın 1000 olduğunu görebiliyoruz. O halde ADC den okunan değeri 0-1000 arasına oranlayıp sonuca 46544 eklememiz gerekiyor.

Bu şekilde Timer Preload değerlerini hesaplamış oluyoruz. Hesaplıyoruzda fakat hesaplarımız gerçektekini tutmuyor çünkü komut gecikmeleri timeri etkiliyor.

Hesaplama rutinlerinin en sonunda TIM0_OFSET ve TIM1_OFSET diye iki değerin sonuca eklendiğini görürsünüz. Bu değerler kod gecikmeleri için. Bunları ben deneme yanılma ile buldum. (ince hesaplar ince ayarlar gerektiriyor  ::))

Sonuç olarak gerçekteki osiloskop görüntüleri bu şekilde.

ADC değeri 0 iken(+Widh 1ms, -Widh 19ms)

ADC Değeri 1023 iken (+Width 2ms, -Width 18ms)


Timer kullanımına dair farklı fikirler verebilir.

İyi çalışmalar.
Bir ulusu yok etmenin En iyi yolu o ulusun dilini yok etmektir.

www.arectron.com/

Powered by EzPortal