PWM Hesabı ve Kodlanması

keanatay

Üye
Katılım
3 Eki 2012
Mesajlar
10
Puanları
1
Dikkat: Sorun çözüldü. Cevapları dördüncü sorunun altında belirttim.
----------------------------------------------------------------------------------------------
PWM hesaplamalarında anlamadığım birkaç nokta var:


XT kristal osilatör f = 4mhz kullandığımızı varsayalım.
(Ccs C dilinde ve PIC C derleyicisinde çalışıyoruz)


PWM, timer2 ile çalıştığına göre kodumuz:
setup_timer2(T2_DIV_BY_Bölme Oranı,PR2,Postscale); olmalıdır.


setup_timer2(T2_DIV_BY_16,254,1); kullandığımızı varsayalım. Buradan,
Bölme oranı (prescale) = 16
PR2 = 254
Kesmeye geçme sayacı (Postscale) = 1 (ilk sorum burada: postscale timer2 kesmesi için kullanılıyor ancak benim programımda kesme olmayacak, bu durumda PWM'i kesmeye girmeden kullanabilir miyim ?)




PWM periyodu = (PR2+1 ) x 4 x Osilatör Periyodu x TMR2 Bölme Oranı (ikinci sorum: bu hesap 10bitliğe göre mi ayarlanmıştır ? 4 ile çarpılmasaydı 8bitlik hesap mı yapmış olurduk?)


Yani,
Tpwm = (PR2+1) x 4 x Tosc x (TMR2 prescale) buradan,
Tpwm = (254+1) x 4 x (1/4 000 000) x 16
= 4080 us


Bu şekilde çalışırken sinyalin 2040uS süresince iş-görev (duty) yaptığını görüyoruz.
Bu çalışma aralığını %50 oranına çekmek istersem yani 1020us yapmak istersek;


10 bitlik Duty değeri için:
Darbe Genişliği (pulse width) = Görev (duty) Değeri x Tosc x (TMR2 Bölme Oranı)


İstediğimiz darbe genişliğimiz = 1020us
= 1020/1 000 000


Yani,
1020/1 000 000 = Duty x (1/4 000 000) x 16 denkleminden Duty bilinmeyenini çekersek:
Duty = 255 çıkar.
Bu hesabı 10bitlik duty değerine göre yapmış olduk.


8bitlik duty değeri için formül:
Darbe Genişliği (pulse width) = Görev (duty) Değeri x Tosc x (TMR2 Bölme Oranı) x 4




Pwm değerini ya 8 bitlik yazım ile ya da 10 bitlik yazım ile değiştirebiliriz. (gerçi 8bitlik yazsak bile, PIC iki sıfır kaydırarak bu değeri 10bitliğe çeviriyor)
10 bitlik tanımlama için "gorev" adında geçiş değişkeni tanımlıyorum:


int16 gorev = 255
set_pwm_duty(gorev);


8 bitlik tanımlamada ise girdiğimiz sayı PIC iki sıfır kaydırarak bu değeri 10bit'e çevirdiği için 4 ile çarpılacak
Yani,
gorev = gorev/4 ise:


set_pwm_duty(63,75); olur.


Üçüncü sorum: Tpwm hesabı 10bitlik kullanıma göre uygulanıyorsa 8bitlik tanımlama(set_pwm_duty(63,75)) yapmamız yanlış olmaz mı ?


Şuradan:
http://www.acroname.com/robotics/info/concepts/pwm.html


görülebileceği gibi görev çevrimi (duty cycle):


Duty Cycle = Pulse Width/Tpwm olur.


Yukarıdaki formüllere göre gerekli sadeleştirmeler yapıldığında:
Duty Cycle = Duty/(PR2+1)x4 olur.


PR2 = 254 seçilmişti ve
Duty = 255 bulunmuştu. Buradan:


Duty Cycle = 255/(254+1)x4
= 1/4
= %25 olur.


Sinyalin çalışma süresinin toplam PWM periyoduna oranı 1/4 çıkıyor. Yani hesapların doğruluğunu sağlıyor.


Gelelim dördüncü soruya:


PWM ile motor sürmeye kalkarsak %100 (ideal varsayalım) hızla çalışan bir motoru pwm(gorev) veya pwm(63,75) ile %50 çalışır hale -daha doğru bir söylemle Rpm hızında dönen bir motorun Rpm/2 hızında dönmesini- sağlayabilir miyiz ?

----------------------------------------------------------------------------------------------

Sonunda cevaplarımı elde ettim. Buraya da son durumu güncelleyeyim:

1) Postscaler'in PWM üzerinde bir etkisi yok. Datasheet'lerden de kolaylıkla bulunabilir. Postscale timer2 kesmesi için kullanılan bir değer. PR2 değeri sınırına ulaşıp her sıfırlanışında 1 postscale değeri artıyor. Örneği PR2 değerini 50 girdik. Postscale değerini 3 girdik. Timer2 sıfırdan saymaya başlıyor. 50 olduğunda sıfırlanıyor ve postscale 1 değer artıyor. Bu işlem iki kez daha tekrarlanınca Postcale bizim belirlediğimiz 3 değerine ulaşıyor ve Timer2 kesmesi oluşuyor. Ben programda kesme kullanmayacağım için gireceğim değerin program üzerinde bir etkisi yok.
2) PR2 değeri 0xff şeklinde 16bitlik olarak dahi belirtilebiliyor. Dolayısıyla formül 8bitlik veya 10bitlik diyemeyiz. Datasheet'te de bu formül belirtilmiş. PR2'e ne değer girersek girelim 10bit üzerinden hesap yaptığımız için (örneğin 0xff = 255 deyip PR2=255 yazıyoruz) 10bitlik bir hesap yapıyoruz. Söylemeyi unutmuşum, 16F877A kullanıyorum. Datasheet'te bu PIC'in çözünürlüğü 10bit verilmiş zaten.
3) İşte en büyük problemim set_pwm_duty() fonksiyonunun nasıl çalıştığıyla ilgiliydi.


Öyle bir fonksiyon oluşturmuş ki adamlar duty parametresine girilen değer 255'den büyükse derleyici bunu 10bit algılıyor, eğer 255 ve altında bir değer girilmişse derleyici bunu 8bit kabul ediyor.


set_timer2(T2_DIV_BY_1,249,1); belirledik diyelim.


255'den küçük bir değer girdiğimizde yani 8bitlik bir değer girdiğimizde


Duty Cycle = Duty/(PR2+1) olacaktır.


Örneğin set_pwm_duty(125) için Duty Cycle = 125/250 = 1/2 = %50 çıkar.




Ancak değer hem 255'den küçükse hem de bu değer 10bitlik olarak kullanılmak isteniyorsa:


1)10bitlik bir değer için int16 diye bir değişken ile bu değeri girebiliriz.
int16 gorev = 125;


Duty Cycle = Duty/(PR2+1)x4 demiştim. Buradaki Duty değeri girilen değerin 10bitlik olması gerekiyor. Bunu tanımlayabilmek için de int16 kullanıyoruz. Aslında çözünürlüğü 10bit'e çıkarmış olduk.


Duty Cycle = 125/1000 = %12.5 Bu kez PWM oranı %12.5 olur.


veya aşağıdaki iki şekilde de bu işlemi yapabiliriz.
2)set_pwm_duty(125L);
3)set_pwm_duty((long)125);


kaynak:
http://www.ccsinfo.com/forum/viewtopic.php?t=31674
http://www.ccsinfo.com/forum/viewtopic.php?t=28761
http://www.ccsinfo.com/forum/viewtopic.php?t=24403




4) Üçüncü sorumun cevabına göre bu cevap ta kendiliğinden beliriyor. set_pwm_duty() fonksiyonu kaç bitlik kullanılırsa motorun yüzde hesabı da ona göre çıkıyor.
 
Arkadaşım bu hesapları en son okulda yapıyorduk artık kullanmıyorum uzun zamandır.Bir motoru maximum hızda sürecek isem pwm olarak 8-bit lik ise 255 gönderiyorum %50 hızda sürecek isem 255/2,%25 hızda sürecek isem 255/4 gibi ayarlamalar yaparak bunu pwm üzerinden gönderiyorum.CCS te de bu şekilde arduino da da bu şekilde micro c de o keza.
Eğer 10 bit pwm kullanacak isen max hız için 1024 ,%50 için 512 ,%25 için 256 gibi değerler gönderirsin ayarlarsın.

Yukarıdaki hesabı hiç kullanmadım şu zamana kadar ki uygulamalarımda..
Belki bu hesaplamayı bilmiyorsun ilk pwm uygulamanı geliştiriyorsundur diye yardımcı olmaya çalıştım.Kolay gelsin....
 
Arkadaşım bu hesapları en son okulda yapıyorduk artık kullanmıyorum uzun zamandır.Bir motoru maximum hızda sürecek isem pwm olarak 8-bit lik ise 255 gönderiyorum %50 hızda sürecek isem 255/2,%25 hızda sürecek isem 255/4 gibi ayarlamalar yaparak bunu pwm üzerinden gönderiyorum.CCS te de bu şekilde arduino da da bu şekilde micro c de o keza.
Eğer 10 bit pwm kullanacak isen max hız için 1024 ,%50 için 512 ,%25 için 256 gibi değerler gönderirsin ayarlarsın.

Yukarıdaki hesabı hiç kullanmadım şu zamana kadar ki uygulamalarımda..
Belki bu hesaplamayı bilmiyorsun ilk pwm uygulamanı geliştiriyorsundur diye yardımcı olmaya çalıştım.Kolay gelsin....

Tpwm > Tduty olması için bu hesapları yapıyorum. Asıl takıldığım nokta bu 255 gönderme kısmını nasıl gerçekleştireceğim ? Örneğin set_pwm_duty(192) yazdığımda bu 192 sayısı 8bitlik mi yoksa 10bitlik mi oluyor?

Eğer 8bitlikse duty içerisinde doğrudan 255 üzerinde bir sayı giremem. Bu karışıklıklardan dolayı hatalı sürüş yapmamak için araştırıyorum.
 
Şöyle açıklamaya çalışayım arkadaşım.Yukarıdaki hesapların hiçbirine gerek yok uygulamalarda.Sen işlemcinin datasheet ine baktığın zaman PWM in kaç bitlik olduğunu oradan öğrenirsin.

set_pwm_duty(192); yazdığında eğer 8 bit lik ise 5*(192/255)=3,76 voltluk enerji çıkışı verirsin.Buda %75,29 oranında
lojik 1 , %24,71 oranında lojik 0 demek.1 cycle için..

Eğer pwm 10 bitlik ise 5*(192/1024)=0,93 voltluk enerji çıkışı verirsin.Buda %18,75 oranında
lojik 1 , %81,25 oranında lojik 0 demek.1 cycle için..
 
Şöyle açıklamaya çalışayım arkadaşım.Yukarıdaki hesapların hiçbirine gerek yok uygulamalarda.Sen işlemcinin datasheet ine baktığın zaman PWM in kaç bitlik olduğunu oradan öğrenirsin.

set_pwm_duty(192); yazdığında eğer 8 bit lik ise 5*(192/255)=3,76 voltluk enerji çıkışı verirsin.Buda %75,29 oranında
lojik 1 , %24,71 oranında lojik 0 demek.1 cycle için..

Eğer pwm 10 bitlik ise 5*(192/1024)=0,93 voltluk enerji çıkışı verirsin.Buda %18,75 oranında
lojik 1 , %81,25 oranında lojik 0 demek.1 cycle için..


Kardeş Datasheet'te 10 bitlik çözünürlük yazıyor. Ancak kullanacağım kristal frekansına ve timer2 fonksiyonunda gireceğim PR2 değerine göre PWM'nin periyodunu hesaplanması ve vereceğim duty değerine göre yapılan yeni hesabın önceki hesaplanan PWM periyodunu geçmemesi gerekir.

Özetle 5V bir kare dalga düşünelim. 5 ms boyunca 5V duruyor, bir sonraki 5ms boyunca 0V olarak duruyor. Bu durumda periyot 10ms olur.

PWM ile bu 5V'da kalma sürecini yani duty_cyle değerini değiştireceğim. Örneğin 7ms boyunca 5V kalmasını 3ms boyunca 0V kalmasını istiyorum. Öyleyse buna göre ayarlarım.

Fakat açıkça görüldüğü gibi 10ms olan bir periyotta 10ms'den daha yukarı bir süreçte 5V kalsın diyemem. Dolayısıyla bu hesapların kesinlikle yapılması gerekir.

Hesaplarda problemim yok.

En büyük problemim set_pwm_duty() fonksiyonunun nasıl çalıştığıyla ilgiliydi.

Öyle bir fonksiyon oluşturmuş ki adamlar duty parametresine girilen değer 255'den büyükse derleyici bunu 10bit algılıyor, eğer 255 ve altında bir değer girilmişse derleyici bunu 8bit kabul ediyor.

set_timer2(T2_DIV_BY_1,249,1); belirledik diyelim.

255'den küçük bir değer girdiğimizde yani 8bitlik bir değer girdiğimizde

Duty Cycle = Duty/(PR2+1) olacaktır.

Örneğin set_pwm_duty(125) için Duty Cycle = 125/250 = 1/2 = %50 çıkar.


Ancak değer hem 255'den küçükse hem de bu değer 10bitlik olarak kullanılmak isteniyorsa:

1)10bitlik bir değer için int16 diye bir değişken ile bu değeri girebiliriz.
int16 gorev = 125;

Duty Cycle = Duty/(PR2+1)x4 demiştim. Buradaki Duty değeri girilen değerin 10bitlik olması gerekiyor. Bunu tanımlayabilmek için de int16 kullanıyoruz. Aslında çözünürlüğü 10bit'e çıkarmış olduk.

Duty Cycle = 125/1000 = %12.5 Bu kez PWM oranı %12.5 olur.

veya aşağıdaki iki şekilde de bu işlemi yapabiliriz.
2)set_pwm_duty(125L);
3)set_pwm_duty((long)125);

kaynak:
CCS :: View topic - PWM Modulator Duty Cycle Problem
CCS :: View topic - Strange set_pwm_duty(value) function
CCS :: View topic - How to change PWM resolution from 10bits to 8bits ?
 
Sonunda cevaplarımı elde ettim. Buraya da son durumu güncelleyeyim:

1) Postscaler'in PWM üzerinde bir etkisi yok. Datasheet'lerden de kolaylıkla bulunabilir. Postscale timer2 kesmesi için kullanılan bir değer. PR2 değeri sınırına ulaşıp her sıfırlanışında 1 postscale değeri artıyor. Örneği PR2 değerini 50 girdik. Postscale değerini 3 girdik. Timer2 sıfırdan saymaya başlıyor. 50 olduğunda sıfırlanıyor ve postscale 1 değer artıyor. Bu işlem iki kez daha tekrarlanınca Postcale bizim belirlediğimiz 3 değerine ulaşıyor ve Timer2 kesmesi oluşuyor. Ben programda kesme kullanmayacağım için gireceğim değerin program üzerinde bir etkisi yok.
2) PR2 değeri 0xff şeklinde 16bitlik olarak dahi belirtilebiliyor. Dolayısıyla formül 8bitlik veya 10bitlik diyemeyiz. Datasheet'te de bu formül belirtilmiş. PR2'e ne değer girersek girelim 10bit üzerinden hesap yaptığımız için (örneğin 0xff = 255 deyip PR2=255 yazıyoruz) 10bitlik bir hesap yapıyoruz. Söylemeyi unutmuşum, 16F877A kullanıyorum. Datasheet'te bu PIC'in çözünürlüğü 10bit verilmiş zaten.
3) İşte en büyük problemim set_pwm_duty() fonksiyonunun nasıl çalıştığıyla ilgiliydi.


Öyle bir fonksiyon oluşturmuş ki adamlar duty parametresine girilen değer 255'den büyükse derleyici bunu 10bit algılıyor, eğer 255 ve altında bir değer girilmişse derleyici bunu 8bit kabul ediyor.


set_timer2(T2_DIV_BY_1,249,1); belirledik diyelim.


255'den küçük bir değer girdiğimizde yani 8bitlik bir değer girdiğimizde


Duty Cycle = Duty/(PR2+1) olacaktır.


Örneğin set_pwm_duty(125) için Duty Cycle = 125/250 = 1/2 = %50 çıkar.




Ancak değer hem 255'den küçükse hem de bu değer 10bitlik olarak kullanılmak isteniyorsa:


1)10bitlik bir değer için int16 diye bir değişken ile bu değeri girebiliriz.
int16 gorev = 125;


Duty Cycle = Duty/(PR2+1)x4 demiştim. Buradaki Duty değeri girilen değerin 10bitlik olması gerekiyor. Bunu tanımlayabilmek için de int16 kullanıyoruz. Aslında çözünürlüğü 10bit'e çıkarmış olduk.


Duty Cycle = 125/1000 = %12.5 Bu kez PWM oranı %12.5 olur.


veya aşağıdaki iki şekilde de bu işlemi yapabiliriz.
2)set_pwm_duty(125L);
3)set_pwm_duty((long)125);


kaynak:
CCS :: View topic - PWM Modulator Duty Cycle Problem
CCS :: View topic - Strange set_pwm_duty(value) function
CCS :: View topic - How to change PWM resolution from 10bits to 8bits ?




4) Üçüncü sorumun cevabına göre bu cevap ta kendiliğinden beliriyor. set_pwm_duty() fonksiyonu kaç bitlik kullanılırsa motorun yüzde hesabı da ona göre çıkıyor.
 
sorun çözüldü ise problem yok demektir.İyi çalışmalar.:)
 

Forum istatistikleri

Konular
128,149
Mesajlar
915,474
Kullanıcılar
449,891
Son üye
Ercan29

Yeni konular

Geri
Üst