libsmps_control_dspic33e-elf庫函數的原代碼是以匯編的形式給出的,需要有一定的匯編程序的編程基礎,筆者以smps_pid_dspic_v2.s原代碼為例,闡述一下PID算法的實現原理。分2部分:1.計算參數,2.代碼分析。在附件中,有經過筆者修改的PID算法的代碼,可以下載學習。
1)先計算PID函數中各個參數值:
下圖為PID算法的結構框圖。
從上面的圖可知,PID函數求解的差分方程為:
而PID的標準式為:
由此可知:
為了正確計算PID的差分方程的解,還要按照要求設置工作寄存器
以平均電流型控制電流內環環路的PI差分方程為例:
所以:KA=3.2116 KB=-3.125 代入前面的公式,可得:
在累加器中要做小數的乘法運算,且小數是大于1的,為了方便累加器的小數計算,應該把大于1的小數都化成小于1的小數,具體做法就是從KA、KB和KC中選出一個絕對值最大的數,然后每項都除以這個數。還有一點,這個除數應該比最大值還要再大一點,否則會出現1,也是無法用dsp的小數格式表示。上式中3.2116最大,可以選擇3.2117做為除數,即
要注意,u[n-1]是上一次計算的結果,沒有進行postShift和postScalar,所以不需要再除3.2117。
要將Ka和Kb、Kc做為系數填入到數組controllerPIDCoefficients[3]中,這一過程是在數組初始化時完成的。
controllerPIDCoefficients[0]=Ka;
controllerPIDCoefficients[1]=Kb;
controllerPIDCoefficients[2]=Kc;
并且在初始化工作寄存器時,還要將w9寄存器做為指針,指向controllerPIDCoefficientABC[3]數組的地址。
進行完一次差分方程的計算后,結果還要乘回3.2117這個數,才是差分方程解的最終值。因為1<3.2117<4(2^2),是無法用Q15格式表示的,所以
w6寄存器中的值為:
還要將ACCA寄存器的結果向左移2位,所以w7寄存器的值應填-2,負號表示向左移,因為都是向左移位,w7寄存器的值總是負值。
w11和w12寄存器是限制PID計算結果最小最大值的。
w10寄存器要做為指針指向controllerPIDErrorHistory[3]數組的地址,用來保存當前誤差和前兩次誤差的結果。
w0是電流環路的參考值,也是PFC電壓外環的PID輸出值。
w1是ADC電感電流采樣。w2是指向占空比寄存器的指針。
因為ADC采樣是12位的,為了用滿15位,所以要左移3位,w13要填3
2)分析PID算法的代碼:
匯編程序以.text為程序的開頭,以.end為程序的結尾。
.global _SMPS_ControllerPIDUpdate_HW_Accel
先將函數聲明為全局函數,以供其它文件調用。然后是定義該函數,并編寫函數的內容,注意函數名前都有下劃線。
進入函數后,首先保存調用該函數前的CORCON寄存器,然后用w3、w14和w5三個寄存器將上次計算出的u[n-1]的值載入到ACCA累加器中,然后通過w4寄存器,設置本函數環境中需要用到的CORCON,主要是設置ACCA累加器的工作模式等參數。在這里,ACCA累加器被設置為普通飽和模式(1.31)且累加器ACCA是小數乘法運算。
接著計算誤差e[n],并存儲在w10指向的數組中。然后從w9和w10兩個寄存器中獲取兩個數組的地址,然后是計算差分方程解的過程。在用mac指令進行乘法運算時,乘法的源操作數只能是w4、w5、w6和w7這4個寄存器,用其它的寄存器都會報錯。另外,在mac指令預取操作時,x空間只能用w8和w9做指針;y空間只能用w10和w11做指針。也只有把兩個不同的數定義在不同的x和y空間,才能做到在一個mac指令中預取2個數,所以要把controllerPIDCoefficients[3]和controllerPIDErrorHistory[3]分別定義在x空間和y空間。因為ACCA寄存器是40位的,所以用3個16位寄存器w3、w14和w5來保存,為了下一次計算PID差分方程時做為u[n-1]使用。
接下來的
sac.r a, w4
其實就是將ACCAH的內容保存在w4寄存器中。w4內容就是PID差分方程的解,但是在做PID算法之前,我們將系數KA、KB和KC都除了3.2117,因此在這個地方,要重新乘回來才是正確結果。w6和w7寄存器的值保存的就是3.2117這個數的dsp小數格式。
mpy w4*w6, a
sftac a, w7
sac.r a, w4
mpy是純乘法指令,指明用ACCA累加器保存計算結果。如同前面文章中提到的,對于大于1的小數,先做乘法,再向左位移。然后再次將結果(ACCAH)保存在w4寄存器中。
接著做最大最小值的嵌位,最后把結果傳送給PID算法的輸出寄存器指針w2。對于本例來說就是PDC2。下面要把e[n]、e[n-1]和e[n-2]都保存起來,同時把w9和w10這兩個指針復位,供下次PID計算時指向正確的地址。
這里上面一段官方原代碼中,好像有點問題!此處不應該用w14寄存器,因為在前面的代碼中,用到了w14來保存u[n-1],下圖所示:
如果存儲e[n]、e[n-1]和e[n-2]過程中,再用w14寄存器,w14原來的值會被覆蓋!即u[n-1]的值會被覆蓋,則下次計算PID時會出現錯誤。所以是不對的,筆者把w14改為w8,經過測試可以實現PID功能。
在原代碼中,w8是指向結構體SMPS_Controller_Options_T的指針,這個結構體的成員triggerSelectFlag用來選擇觸發時間的計算方式,成員trigger是指向TRIG2寄存器的指針,成員period是指向PWM2周期寄存器的指針。在筆者的代碼中,完全舍棄了這個結構體,將計算觸發時間的代碼以C語言的方式,寫到本函數的外面。所以將下圖中的263行至297行,全部刪除。
然后提一下如何計算一下PWM2觸發ADC的時間,即計算TRIG2寄存器的值。對于平均電流型控制模式,我們只要在達到占空比一半的時間點時觸發ADC采樣,采到的值就一定是被測量的平均值,這可以說是數字電源對比模擬電源的一個優點,因為模擬電源采集平均值需要進行低通濾波,會有一定的延時,而數字電源幾乎是瞬時的。
TRIG2的計算方法:(其中Delay是指從PWM2發出波形到MOS管輸出PWM波形的延時時間)
再說明一下,在本函數中,并沒有進行觸發時間的計算,而是在函數的外面以C語言的方式編寫代碼,在下一節中會有具體說明。
總結:
PID差分方程的求解計算主要是應用累加器實現的,如何整定函數的參數,本文給出了詳細的步驟,并指出了原代碼中出現的錯誤,以及解決方法。里面涉及到了匯編代碼的編程,需要對匯編指令有比較深入的了解,其中的一些細節更是無法一一提及,還需讀者閱讀相關的資料。推薦閱讀《16位MCU和DSP程序員參考手冊》(DS70157F_CN)。
在下一節中,會以半無橋PFC為例,具體說說如何編寫代碼。