Arduino PWM Kullanımı.

Arduinoda PWM kullanımını öğrenmeden önce PWM konusuna bir giriş yapmak istiyorum. Bir çok yerde örnekler ve anlatımlar var. Ben bu anlatımlardan farklı olarak sade ve pratiğe yönelik anlatmak istiyorum.
Öncelikle PWM nedir ve nerelerde kullanılır diye başlıyoruz. Fakat kullanım yerleri saymakla bitmeyeceği için genel anlamda şöyle bir tanım yapabiliriz. Belirli bir frekansta oluşturulan kare dalganın 1 periyot içerisinde 1 ve 0 ların başlangıç pozisyonunu değiştirerek, kare dalga sinyalinin HIGH seviyesi ve LOW seviyesinde kalma zamanını ayarlamış oluyoruz. Bu şekilde elde ettiğimiz sinyale PWM sinyali deriz.
Period( periyot ) = Bir sinyalin tekrar ettiği noktalarının arasıdır. T=1/frekans olarak hesaplanır. Birimi saniyedir.
Frekans=1/T (periyot)  olarak hesaplanır.  Resimdeki A (amplitude) gerilimi ifade eder.Birimi Hz. dir


Bu zamanı ayarlayarak biz ne yapmış oluyoruz derseniz, kullanıldığı yerdeki oluşan gerilimi azaltıp çoğaltırız. PWM ile kullanılan ledlerin yavaş yavaş yanıp söndüğünü görmüşsünüzdür. Bu hareketin sebebi 1 ve 0 zamanlarını ayarladığımız pwm sinyalinin oluşturduğu gerilimi ayarlamamızdır.
Mesela bir motorun hızını ayarlayacaksınız. Bunun için Potansiyometre kullanabilirsiniz. Bunun yerine pwm sinyali kullandığınızda mikroişlemci ile motor hızını ayarlarsınız.
Bu 1 ve 0 zamanlarına duty denir. 1 ve 0 zamanları eşitse %50 duty denir. aşağıdaki resimde duty oranlarının sinyalde nasıl değişiklik yaptığını görüyorsunuz. %0 ile %100 arasında ayarlanır.

Buraya kadar PWM nedir, cevaplamaya çalıştık. Her mikrokontrolcü ile yazılımsal olarak PWM elde edilebilir. Fakat donanımsal PWM her mikrokontrolcüde yoktur. Arduinoda 6 adet donanımsal PWM çıkışı vardır.  Altısınıda aynı anda kullanabilirsiniz. Bazen birbiriyle senkron olabilir bazen de farklı zamanlarda başlayıp farklı frekanslarda olabilirler. Sizin ayarlarınıza bağlı olarak bir çok konfigürasyon yapılabilir.
En sade örnek: Fakat bunun kullanılmasını tavsiye etmiyorum. 
void setup()
{

pinMode(13, OUTPUT);
}

void loop()
{
digitalWrite(13, HIGH);
delayMicroseconds(100); // yaklaşık 10% duty cycle = 1KHz
digitalWrite(13, LOW);
delayMicroseconds(1000  100);
}
Bunun gibi bir mantıkla kolaylıkla pwm üretilebilir. Bunun dezavantajı ise bu işlemin yanında başka program satırları da varsa, hele bir de delay  komutu varsa, pwm frekansı devamlı farklı olacaktır.

Bu durumu engellemek için zaman kesmesi kullanılır. Bu zaman kesmesi süresince arduino başka program satırlarını işletebilir. Zaman kesmesi, arka planda bulunan zaman sayacının son noktaya gelip sıfırlandığı anda oluşan bir kesmedir. Bu sayede kesme gelesiye kadar arduino bizim programımızı işletecek zaman bulur ve kesme geldiğinde bizim programımıza ara verip kesme programını çalıştırır. Sonrasında kaldığı yerden programımızı işletmeye devam eder.
Bununla ilgili bir örnek program, örnek programların arasında yer almaktadır. Videoda da çalışmasını görebilirsiniz.

Donanımsal PWM : Bu tip pwm kullandığınızda Arduino programınız başka iş yapsa da arka planda bu PWM sinyalini kendisi üretir. Tabii ki sizin verdiğiniz ayarlarla bu üretilir.
Gelelim PWM  için Arduinoda kullanılan komuta. [ analogWrite(3, 125); ] komutu kullanılır.
Bu komutta 3 hangi pwm pini olduğunu gösterir. 125 ise duty miktarını gösterir.
Burada şunu vurgulamakta fayda var. Timer1 dediğimiz zaman sayacı, 16 bitlik bir sayaçtır. Normalde sayaç 65536 ya kadar sayar. Fakat PWM dediğimizde en fazla 10 bit ayarı var. yani 1024e kadar sayar. %50 duty dediğinizde bunun yarısı, analog write komutunda 125 yazılan yere yazılır. Şayet Timer0 veya Timer 2 kullanılacaksa, bunlar 8 bitlik zaman sayıcısıdır. Bunlarda 255 e kadar sayar. Bundan dolayı %50 duty dediğimizde 128 sayısını veririz.
Şunu da unutmamak gerekir. Analogwrite komutunu kullanacaksanız sadece atmega entegresinin PWM çıkış pimlerinde kullanabilirsiniz. Ayrıca bu komutu kullanmak için PWM kütüphanesine ihtiyacınız olmayacaktır.  Bu tip bir çalışma ise örnek programlar arasındadır.

Arduino mega da daha fazla timer bulunmaktadır. Bunlar atmega328 entegresini kullanan arduino kartları için geçerlidir.

Burada şu soru akla geliyor. Hangi pwm çıkışı hangi ismi alır ve hangi zaman sayıcısıyla tetiklenir.
Buraya kadar basit olarak Anlog write komutuyla yapabileceğimizi gördük. Bu şekilde bir çalışmayı seçtiyseniz OC0A ve OC0B pimlerinden 1Khz lik PWM alabilirsiniz. Diğer pimlerden ise 500hz lik bir sinyal alabilirsiniz.
Bu frekansı ayarlamak istesem ayarlayamaz mıyım, diyorsunuz. Tabii ki ayarlayabilirsiniz. Ekteki örnek programlardan biri, bunu göstermektedir. Program ile 1-255 hz arasında bir seçim yapabilirsiniz.
Tabii ki bu ayarı yaparken örnek programda sadece timer1 kullanıldı. sizler ise timer0 ve timer2 yi de kullanabilirsiniz. Örnek programda frekans değiştirmek için PWM.H kütüphanesi kullanılmaktadır.
Problem sadece TIMER0 da olacaktır. Çünkü bu zaman sayacını Delay, millis gibi zaman fonksiyonları da kullandığından, bu frekansı değiştirmek için zaman sayacını değiştirirseniz bu zaman komutları etkilenebilir.  Diğer zaman sayaçlarını rahatlıkla kullanabilirsiniz.

Buraya kadar ise kolay pwm komutu gördük. Fakat donanımsal bir PWM oluşturmanın biraz daha ayrıntılı yönü var. Mesela frekansı değiştirmek ya da 2 çıkıştan birini invert etmek ve bir çok parametre. Bunları öğrendiğinizde ise kolaylıkla istediğiniz özellikte PWM sinyalini üretebilirsiniz. Sonuçta elinizde Analog write komutu var. Bununla sadece pim seçimi ve duty ayarı yapabiliyorsunuz. İstediğiniz frekanslara çıkmanız ya da inmeniz gerektiğinde bunları yapmak için standart başka komut yok. Hazır kütüphaneler var ama onlarda tam çözüm olmayabiliyor. Yine de kütüphane, yeteneği kadar yardımcı olacaktır.
Bunun yerine artık biraz derine gideyim, tüm kontrol bende olsun diyebilirsiniz.
Zaman sayaçlarını ayarlayarak, bazı yazmaç ( register) ları ayarlayarak çok çeşitli uygulamalar yapabilirsiniz. Mesela 10 bit lik bir pwm üretmek ya da saat frekansını bölerek istediğimiz frekansa yakın frekanslar elde etmek bunlardan bazılarıdır.
Bunlar için aşağıda bazı tablolar göreceksiniz Bu tabloların mantığını anladığınızda sizler ayarlamaları kolaylıkla yapabileceksiniz.

Uygulamanız gereken satır örneği budur. Tabii ki ayarlar gerektiğinde artabilir.
TCNT1=0;
TCCR1A=0b11110001; //TCCR1A= COM1A1 COM1A0 COM1B1 COM1B0 – – WGM11 WGM10
TCCR1B=0b00001001; // TCCR1B= ICNC1 ICES1 – WGM13 WGM12 CS12 CS11 CS10
OCR1A = 128;
OCR1B =180;

Yukarıdaki satırlarda 2 adet register içeriği değiştirildiğinde OCR1A ve OCR1B duty miktarları yazıldığında PWM sinyaliniz hazır oluyor. Tabii ki, hangi pimden çıkacaksa yukarıdaki tablodan görebilirsiniz.

Şimdi de bu registerleri ( yazmaç )ayarlamak için gereken tablolara bakalım.  3 Ayrı tablo ufak farklılıklarla benzerdir. Karıştırmayın. Mesela timer 0 zaman sayacı ve timer 2 zaman sayacını kullanan PWM de 7 mode vardır. timer1 zaman sayacında ise 15 mode vardır. 

 

 

 

 

 

 

Yukarıdaki tablolarda register ( yazmaç ) içerikleri mevcuttur. Program yazma şekli 2 çeşittir. 
Birincisi :
TCCR1A=0b11110001; //TCCR1A= COM1A1 COM1A0 COM1B1 COM1B0 – – WGM11 WGM10  şeklinde binary olarak kullanmak istediğimiz parametreler için 1 veririz istemediklerimize 0 veririz.
Ya da aşağıdaki şekilde bit işlemleriyle istediklerimizi yükleriz.
İkincisi : TCCR1B |= (1 << CS12) | (1 << CS10);  //  | işareti bit işlemini ifade eder. 
Bu şekilde de bit işlemi ile 1 yapmak istediklerimiz direkt olarak yazarız. Seçmek istemediklerimizi ise hiç yazmayız. Burada şuna dikkat edilmeli. Buradaki gibi CS12 gibi isimler register içindeki isimle aynı olmalı. CSS12 yazsanız, bu anlaşılmayacağı için hata verecektir. Bundan dolayı binary şeklinde yazmak kolay olacaktır. Fakat 2. şekilde yazılım ise, programın okunması açısından da kolay olacaktır. Hangi register bitleri kullanılmış, isme bakıp görebileceksiniz.

Verilen örnek programları inceleyip, parametreleri değiştirerek çıkan PWM sinyalini inceleyebilirsiniz. Bunu videoda olduğu gibi PROTEUS kullanarak çabuk bir şekilde test edebilirsiniz. Proteus programı yoksa eski versiyon ki ben bunu kullanıyorum. Bu linkte bulabilirsiniz. Kurup programlarınızı Arduino olmadan deneyebileceksiniz.

Bunun yanı sıra proteusta arduino uno resminin bulunduğu kütüphaneyi kullanabilirsiniz. Fakat bu tip özel kütüphanelerde bazı özellikler çalışmadığı için sorun yaşayabilirsiniz. Bundan dolayı Proteus programına ait atmega328 entegresini  kullandım.  Bu tip sonradan yapılan kütüphanenin problemleri için en alttaki  videoya bakabilirsiniz.

PWM tablolarının kaynak sitesi burasıdır.

Tüm programlar dokümanlar buradadır. 

ATMEGA328 entegresinin DATASHEET’i ( Teknik dokümanı )

PWM kütüphanesini buradan alabilirsiniz. 


Aşağıdaki video, sadece proteustaki sonradan yapılan kütüphanelerin sorunları olabileceğini gösterir. PWM kullanımı ile ilgisi yoktur. 

Lütfen bu konu hakkında eksiklik ya da yanlışlık olduğunu düşünüyorsanız yorum bırakmanızı rica ediyorum. Başka kişiler de bu hataları ya da eksiklikleri görebilsin.

 

 

 

 

 

 

 

 

 

7 Comments

  1. Arduino ile farklı frekanslarda çalışan servolari aynı anda nasıl kontrol edebilirim

  2. Merhaba ardunio UNO ile yaklaşık 30-40Khz civarında PWM üretip aynı zamanda frekansmetre gibi ölçmek mümkün mü acaba

    1. Bence bunu donanımsal PWM ile yapabilirsiniz. Donanımsal PWM programını9z tarafından 1 kere ayarlanır ve programa bir daha ihtiyacı olmaz. Bundan dolayı frekans ölçümünde programınızı yavaşlatmaz. 2 kutu devre olarak düşünün PWM donanımsal olursa 1. devre ve ayarlandıktan sonra kendi kendine çalışır. diğer devreyi de program ile devamlı kontrol edebilirsiniz.

  3. Ben herhangi bir PWM değerini üretiyorum. Fakat istediğim ürettiğim PWM in frekansını azaltıp cagaltmak. Bunu nasıl yapabilirim.

    1. PWM şayet analog write ile yapıldıysa onun parametrelerine bakın. ŞAyet donanımsal PWM ürettiyseniz o zaman bu yazıdaki registerlerin değerini değiştirerek buna ulaşabilirsiniz.

Şafak Ağustoslu için bir cevap yazın Cevabı iptal et

E-posta hesabınız yayımlanmayacak.