我們以進階(1)中,用MCC生成的文件為基礎,先編寫PFC電流內(nèi)環(huán)的算法代碼。在進階(1)中,已經(jīng)提到了,電流內(nèi)環(huán)的采樣頻率為100KHz,電壓外環(huán)的采樣頻率為50KHz。而且電流內(nèi)環(huán)是PWM2發(fā)生器觸發(fā),即TRIG2為觸發(fā)的寄存器。而電壓外環(huán)為主時基觸發(fā),是用SEVTCMP做為觸發(fā)寄存器。由于是平均電流型控制,要求采集電感電流的平均值,所以要求TRIG2跟隨占空比的變化而變化,電壓環(huán)路沒有這個要求,就在一個固定的時間觸發(fā)即可。
除了MCC生成的文件,還要添加5個需要自己編寫的文件,如圖:
1.defines.h文件把所有需要定義的常量在該頭文件中定義。
2.pfc_variables.h和pfc_variables.c,其中.c文件用來定義用到的全局變量或函數(shù),另外PID算法用到的兩個數(shù)組以及數(shù)組的初始化也在該文件中完成。.h文件是將這些全局變量做extern聲明。
3.initCONTEXT.S文件是初始化context的匯編代碼。
4.PID.s是PID的算法函數(shù),其中的代碼就是PID實現(xiàn)的過程。
1)context的初始化:
相比microchip的8位MCU只有一個工作寄存器,dspic16位MCU由16個工作寄存器陣列(w0-w15)組成一組,而且有多組,比如:dspic33ep128gs806就有4組這樣的工作寄存器組。在調(diào)用函數(shù)或進入中斷時,工作寄存器就不需要壓棧,而是直接切換到另外一組工作寄存器組,函數(shù)返回或出中斷時也不用再將寄存器彈出棧,只需要把原來的工作寄存器組再切換回來。
官方編寫的smps_control_library庫函數(shù)中的硬件加速函數(shù)就是應用了上述的工作寄存器組切換的特點,減少了調(diào)用函數(shù)的時間。在用這種方法之前,首先要用匯編代碼初始化一組工作寄存器。代碼在initCONTEXT.S文件中編寫:
#include "defines.h"
.text
.global _initCTXT1
_initCTXT1:
CTXTSWP #1
mov #_pfcCurrentRef, w0
mov #_pfcCurrentSample, w1
mov #_pfcCurrPIDout, w2
mov #currentLoop_postScalar, w6
mov #currentLoop_postShift, w7
mov #_CurrentPID_Coeff, w9
mov #_CurrentLoopHistory, w10
mov #CurrPIDoutMin, w11
mov #CurrPIDoutMax, w12
mov #preShift, w13
CTXTSWP #0
return
.end
文件的開頭包含預定義常量的.h文件。.text表示代碼開始。然后聲明一個全局函數(shù)_initCTXT1,接著用“CTXTSWP #1”切換到工作寄存器1組,隨后就是工作寄存器的定義,定義完成后,還要切換回工作寄存器0組,就是dsp上電后默認的工作寄存器組。最后函數(shù)返回。以.end結束。
2)在dsp上電時初始化工作寄存器1組
筆者將context初始化的工作放在系統(tǒng)初始化函數(shù)中,如圖:
在system.c文件中,先聲明initCTXT1函數(shù),然后就可以調(diào)用該函數(shù)了。注意在C文件中沒有下劃線。
3)PID參數(shù)的初始化
PID的參數(shù)Ka、Kb和Kc是在defines.h中定義,PID參數(shù)的初始化就是定義的兩個數(shù)組的初始化。電流環(huán)路中的這兩個數(shù)組是在pfc_variables.c中定義的。這兩個數(shù)組是:
CurrentPID_Coeff[3]和CurrentLoopHistory[3]
將計算好的Ka、Kb和Kc參數(shù)放入CurrentPID_Coeff[3]中,而CurrentLoopHistory[3]元素要全部清零。
關于參數(shù)Ka、Kb和Kc的計算,筆者參考了microchip官方的一篇文章《使用dsPIC® DSC 實現(xiàn)能量轉換應用中的功率因數(shù)校正(DS01106A_CN)》中第13頁的公式,最終得到的差分方程是:
根據(jù)前面文章中介紹的方法:
Ka=26772,Kb=-25460,Kc=0,postScalar=32767,postShift=0。
4)加入PID.s文件
就是上一篇文章中修改后的smps_pid_dspic_v2.s文件。
5)ADC采樣中斷并計算PID差分方程
在PWM2觸發(fā)ADC模塊的AN0通道(mos管電流采樣)中斷時,進行電流環(huán)路PID計算。所以在_ADCAN0Interrupt中斷時加入代碼。PID的函數(shù)不是放在回調(diào)函數(shù)中,而直接放到中斷函數(shù)里,這樣能減少延時時間。另外,在中斷函數(shù)屬性中使用"no_auto_psv",還能再節(jié)省100ns的時間。
從代碼中可以看到,進中斷后,將AN0通道的采樣值讀出(如果在中斷的過程中不去讀ADCBUF0,就會不停的再次進入該中斷,影響其它代碼的執(zhí)行。),然后用匯編指令手動切換到工作寄存器1組,執(zhí)行PID算法。計算結果保存在pfcCurrPIDout變量中。然后更新PDC2寄存器。PDC2中的值除2就是TRIG2的值,使下一次ADC采樣在占空比一半時觸發(fā)。
到此,電流內(nèi)環(huán)的PID算法的流程已經(jīng)完成。
另外要提一下的是,最好不要使用ADC中斷等級綁定的自動context切換。因為自動切換context后,要十分小心,先要在中斷函數(shù)屬性中要添加context屬性。而且最好在一進入中斷后立即調(diào)用PID算法,不要有任何C語句,否則用C編譯器編譯后,可能會覆蓋工作寄存器1組的w0等工作寄存器,導致PID出現(xiàn)未知的錯誤。所以為了避免出現(xiàn)此情況,還是手動切換更為保險。
如果必需用到context自動切換,建議直接用匯編編寫ADC中斷代碼,不要再用C編寫。官方給出的參考代碼中的關于ADC的電流采樣中斷就是用匯編語言編寫的。
關于context切換的更詳細內(nèi)容,請參考smps_control_library中的doc目錄中的幫助文件help_smps_control.pdf中的第21頁。