2011年5月31日 星期二

惱人的pwm duty cycle setting for PIC


PIC在使用hardware的pwm module(CCP1)時, 需要設定PWM的頻率如下
                           

這個部份大家應該都沒有問題, 通常比較有問題的是pwm的duty cycle, 先看下面的pwm duty的公式                       


如果按照我們既有的觀念去算, 假設我的Tosc=0.05uS(20M OSC), TMR2 prescale value=1, PR2=49則PWM frequency=100KHz, 如果我要得到50%的duty cycle, 則計算如下

               (CCPRxL:CCPxCON<5:4>)=PWM Duty Cycle/(Tosc*TMR2 Prescale Value)

                                                      =(50/100)/(0.05u*1)=10000000

疑? 真奇怪, 我完全按照公式去算啊, 為啥不對, CCPRxL:CCPxCON<5:4>總共是10個bit, 所以可設定範圍為0~1023, 那為什麼會得到10000000

花了二個小時去找為什麼, 最後終於發現為什麼了, 老外的思考和咱們就是有差, 原因是出在pic spec上寫的pwm duty cycle的解讀不同, 看下面

                          spec上寫的pwm duty cycle  => 指的是PWM pulse width
                          我的認知 pwm duty cycle => 指的是百分比的工作週期

所以按照我所認知的duty cycle應該要代入下面的公式
                         

我們按照上面的條件再算一次

                   (CCPRxL:CCPxCON<5:4>)=PWM Duty Cycle Ratio* 4(PR2+1)

                                                          =(50/100)*4(49+1)=100

請注意, 另一個陷阱來了, 這個是10bit的100喔, 而不是8bit的100, 差別如下

                 10 bit的100以2進制來看為0110010000 => 換成十進制為400

                  8 bit的100以2進制來看為01100100 => 換成十進制為100

真的是差很大, 所以正確的做法有二種
1. 宣告duty為int16的變數 , 如 int16 duty;
2. 直接給duty的數值, 如 set_pwm1_duty(100L); => 100L會通知compiler以long來做運算
我是建議用第一種方法, 因為很多人都應該會忘了在數值後面加個"L"

最後, 我們再驗證一次equation 15-2

                           (CCPRxL:CCPxCON<5:4>)=PWM Pulse width/(Tosc*TMR2 Prescale Value)



                                                                  =((1/100000)*(50/100))/(0.05u*1)

                                                                   =5u/0.05u

                                                                   =100

果然這樣就對了, 希望大家不要和我一樣多花了2~3個小時在這種地方, 很不值得, 所以寫出來和大家分享!!

2 則留言:

歡迎大家來討論交流一下~~~