Pulse Width Modulation etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster
Pulse Width Modulation etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster

16 Aralık 2015 Çarşamba

PIC18F452 CCS C - Yazılımsal PWM ile Servo Motor Sürme

Bu yazımda daha önce Arduino kullanarak sürdüğümüz servo motoru aynı şekilde PIC ile yapmaya çalışacağız. Bildiğiniz gibi Arduino, kütüphaneleri sayesinde  işimizi çok kolaylaştırmakta fakat aynı durumu PIC için söyleyemeyeceğim. Kütüphane kullanmadan yazılımsal PWM ile servoyu CCS C kullanarak kontrol etmeye çalışacağız.

Öncelikle servo motorlar hakkında detaylı bilgi için Arduino ile yaptığımız uygulamanın yazısını okumanız yeterli olacaktır.Bağlantı linki;

http://arduinotik.blogspot.com.tr/2014/05/arduino-pwm-ile-servo-motor-surme.html




 
Yazılımsal PWM oluşturma mantığımız soldaki gifte görüldüğü gibi olacak. Toplamda 20 ms'lik bir sinyal üretip 0 Derece için 1ms, 180 Derece için 2 ms lik bir duty cycle oluşturacağız. En azından teorik olarak. Çünkü kullandığım servo motor (SG90), 550us-2550 us'lik duty cycle ile çalışmakta. Tabii ki sinyal genişliğimiz yine 20ms olacak.





Yazılım kodlarını atmadan önce yaptığım işlemlerden kısaca bahsetmek istiyorum. Öncelikle servo motor için aç-kapa mantığı ile (led yakıp söndürme ile aynı) bir fonksiyon oluşturdum. Bu açma-kapama süreleri arasında kullandığım gecikme zamanlarını da potansiyometreden okuduğum adc değerleri ile belirledim. Yani servo motor potansiyometreden okundan adc değerine göre açıyı belirleyip konum alacak.

Neden donanımsal PWM kullanmadım ? Çünkü PIC ile 50 Hz'lik donanımsal PWM sinyali oluşturamıyorum. Bu yüzden yazılımsal PWM'i tercih ettim.




#include <main.h>
#include <flexy_lcd.c>
#use fast_io(a)
#use fast_io(d)

unsigned long int i=0,aci=0;

void servo(unsigned long int b,c)
{
output_high(pin_d7);
delay_us(550+b); // PWM Dolu Kısım
output_low(pin_d7);
delay_us(19450-b); //PWM Dolu Kısmı 20 ms'e tamamlayacak kısım
printf(lcd_putc,"\fAci = %u Derece",c);
continue;
}

void main()
{ set_tris_a(0x01);
set_tris_d(0x00);
output_d(0x00);
setup_adc(adc_clock_div_16);
setup_adc_ports(AN0);
set_adc_channel(0);
lcd_init();
while(1)
{
i=read_adc();
aci=i*2/11.1;
i=i*2;
servo(i,aci);
}
}


LCD kütüphanenizi kendinize göre belirlemeyi unutmayın.

Potansiyometrenin orta ucunuz A0 pinine, Servo motorun PWM ucunu da D7 pinine bağladım.

Ayrıca Servo motoru toprak uçları aynı olmak şartıyla başka bir kaynaktan beslemenizde gerekiyor.

SG90 Tower Pro Servo Motoru  550us-2550us arasında çalışıyor. Yani her şekilde en az 550 mikrosaniyelik bir PWM sinyalimiz olacak ve açı eklemelerimiz bu sürenin üzerine olmalı. En fazla da 2550 mikrosaniye.

Kabaca bir hesapla 10 bitlik ADC kullanarak 1023 değerini elde ettiğimizde PWM sinyalimizin doluluğun 2550 mikro saniye olması gerekiyor. Yani,

550+ADC.X=2550  denkleminde ADC yerine 1023 koyarsak,

X= 1,955 çıkıyor. delay_us fonksiyonunu kullanırken içinin tam sayı olması için bu değeri 2'ye yuvarladım. Ondalıklı değerlerde sıkıntı çıkıyor çünkü.

LCD'de açıyı göstermek için de, servonun her 1 derecelik dönüşünün 11.1 us olduğunu hesapladım. Dolayısıyla 2 ile çarptığım değeri 11.1'e böldüğümde açı değeri çıkıyor.

(2550-550) / 180 = 11.1 us

void servo fonksiyonu ile de  minimum 550us'lik lojik-1 ve bunu 20000us (20ms) ye tamamlayacak lojik-0  (20000-550=19450 us) değelerinden; lojik-1'e  2 ile çarptığımız ADC değerini ekler, lojik-0'dan da bu değeri çıkarırsak servomuzu sürebiliriz. 
PWM sinyalimizin frekansının  her zaman 50Hz, periyodunun da 20ms olduğuna dikkat ediniz.

Bu arada kullanmış olduğum






header dosyasının kodları da aşağıda ve siz direkt yazılımın başına ekleyebilirsiniz dilerseniz. Ya da benim kullandığım gibi ana programın olduğu klasöre atıp include edebilirsiniz.



#include <18F452.h>
#device adc=10

#FUSES NOWDT //No Watch Dog Timer
#FUSES HS //High speed Osc (> 4mhz for PCM/PCH) (>10mhz for PCD)
#FUSES NOPUT //No Power Up Timer
#FUSES NOPROTECT //Code not protected from reading
#FUSES NODEBUG //No Debug mode for ICD
#FUSES NOBROWNOUT //No brownout reset
#FUSES NOLVP //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOCPD //No EE protection
#FUSES NOWRT //Program memory not write protected
#FUSES RESERVED //Used to set the reserved FUSE bits

#use delay(clock=20000000)

Uygulamanın videosu;



29 Mayıs 2014 Perşembe

Arduino - PWM ile Servo Motor Sürme


PWM ile DC motor sürmüştük. Şimdi ise aynı yöntemle Servo motor süreceğiz.Fakat transistörlü anahtar kullanmayacağız.Çünkü servo motor kendi içerisinde PWM sinyalini algılayabilecek ekipmana sahip.





Servo Motor Nedir ?
Servo motor özellikle robotik uygulamalarda kullanılan bir motor çeşitidir. Servo motorlar da çıkış; mekaniksel konum, hız veya ivme gibi parametrelerin kontrol edildiği bir düzenektir. 
PWM sinyal ile DC motorun hızını kontrol ederek sürmüştük. Servo motor ise DC motor gibi sürekli dönen bir yapıya sahip değildir. 360 veya 180 derece dönebilen motorlardır ve mühim olan bu motorlarda hız değil açı değeridir. PWM ile servo motor kaç derece dönmesi gerektiğini algılar ve sinyalin istediği derece kadar döner. Uygulamamızda bunu daha iyi anlayacağız.


Towerpro SG90 Servo Motoru
Piyasada bulunan en ucuz servo motor Towerpro SG90 markalı motorudur. Motor 180 derece dönebilmekte ve ekipmanları da fena değil. Kablolarının bağlantıları da aşağıdaki resimde.
PWM yazan kabloyu Arduino'muzun 9 nolu pinine takacağız ve potansiyometre ile ölçtüğümüz analog değeri açıya dönüştürüp PWM ile motoru süreceğiz.

!!! Programı yazarken Servo'yu 170 derece döndürebildim. 180 derece döndürmek için map komutunu ya da açı değerini float olarak girmeme rağmen bu sorunu çözemedim.

Arduino Komutlarımız ;

#include  //Arduino'nun kendi Servo Kütüphanesi var

int potPin = 0;  
int servoPin = 9;
Servo servo;  // servo ismiyle servo motorumuzu tanıttık

void setup() 

  servo.attach(servoPin);  // Servo'nun sinyali alacağı Arduino Pinini belirledik


void loop() 

  int okunan = analogRead(potPin);     // 0'dan 1023'e, Pottan okunan değer
  int aci = okunan / 6;              // 0'dan 180 dereceye Açıya dönüştürülüyor.
  servo.write(aci);  



Bu uygulamayı PIC ile de yapmanızı şiddetle tavsiye ediyorum. Çünkü Servo.h kütüphanesi ile tüm uygulamayı basite indirgeyebiliyoruz. İşin arka planını görmek isteyenler mutlaka PIC ile de denemeliler. 

Uygulamamızın resmi ve videosu ;







22 Temmuz 2013 Pazartesi

Arduino - Analog Çıkışlara Hükmetmek (PWM & Ledler)

Daha önce dijital çıkışlara hakim olmuştuk. "1" ve "0" mantığı ile ledimizi yakmış ve söndürmüştük.Fakat hayatta ki ölçülebilen değerler sadece "1" ve "0" lardan oluşmuyor. Bu yazımda analog çıkışlarla ilgili çalışma yapacağız. Arduino UNO ve türevleri bu özelliği barındırmakta.




Bu özellik elbette ki tüm çıkış pinlerinde yok. Üzerinde ~ işareti bulunan pinleri kullanırsak analog özelliğini de kullanabiliriz.

Dijital çıkışlarda " digitalWrite(10, HIGH ), digitalWrite(10, LOW) " komutunu kullanıyorduk. Çıkışımız ya "1" ya da "0" oluyordu. Analog özelliğini kullanabilmemiz için ise aşağıdaki komuta ihtiyacımız olacak.

analogWrite( )

Öncelikle devremizi aşağıdaki gibi kuruyoruz.Tabi siz isterseniz üzerinde "~" işareti bulunan herhangi bir pini de kullabilirsiniz.

Kodlar ve açıklaması :


int led=9;
  
void setup()
{
  pinMode(led, OUTPUT);

}
void loop()
{
  int parlaklik;
  {
  for (parlaklik=0;parlaklik<=255;parlaklik+=5)
  {analogWrite(led,parlaklik);
  delay(100);
  }
  for(parlaklik=255;parlaklik>=0;parlaklik-=5)
  {
    analogWrite(led,parlaklik);
    delay(100);
  }
}
}


  • 9. pinimizi çıkış olarak ayarladık
  • Parlaklık ismiyle integer bir değer okuttuk.Bu değerimiz analog çıkış almamızı sağlayacak.
  • 8 bitlik dijital değeri analog değere çevirmiş olduk 2^8=256 formülünden analog çıkışımız 0-255 arasında değişecek.
  • Biz bu değeri 5'er 5'er 255'e kadar arttırdık ve sonra da 255'ten 5'er 5'er azalttık.
  • Böylece analog olarak ledimizin parlaklığını arttırmış ve azaltmış olduk.