會員登陸
帳號:

密碼:

記住我



忘記密碼?

現在註冊!
網站導航
最新下載
訪問統計 (自2012/5/3)


正在流覽:   1 名訪客





Dspic30f4011 DSP引擎 PID lib 問題 與 PWM、ADC觀念確認。
新會員
註冊日期:
2018/08/30 18:33
所屬群組:
註冊會員
文章: 14
等級: 2; EXP: 50
HP : 0 / 37
MP : 4 / 80
離線
各位先進前輩大家好,

小弟我最近使用 Dspic30f4011 DSP引擎 PID lib 的時候發現只給Kp 數值,Ki 與 Kd 給0x0000的時候會,輸出在過一定時間後(有時候幾秒、有時後幾個小時),會直接飽和

沒接DSP引擎的PID lib時又很正常,想知道是哪裡觀念有問題?

以下是我的測試方法,
測試頻率:100kHz、晶體:7.3728Mhz、PLL:x16、clock無前後scaler
利用APP020 PLUS開發板 VR1接上 ADC RB6腳位(參考曾老師範例),
打開PWM特殊事件觸發使ADC自動轉換。
設定太冗長就不貼了,需要會再補上。

轉換ADC數值,等到AD中斷發生儲存至 PI_in 變數並打開自定義旗標(自己定義),關閉中斷轉換ADC數值,等到AD中斷發生儲存至 PI_in 變數並打開自定義旗標(自己定義),關閉中斷

void __attribute__((interrupt, auto_psv)) _ADCInterrupt(void){
sample = 1;
PI_in = ReadADC10(0);
IFS0bits.ADIF = 0;}

//為了不在中斷進行運算,並結合曾老師 Ex10-1自定義旗標。
Main偵測到自定義旗標發生進型PID運算,
運算後進行飽合處理
輸出至PWM模組 用示波器觀察。


int main(void){
Init_ADC();
Init_MCPWM();
fooPID.abcCoefficients = &abcCoefficient[0];
fooPID.controlHistory = &controlHistory[0];
PIDInit(&fooPID);
kCoeffs[0] = 0x024c; // KP
kCoeffs[1] = 0x0000; // KI
kCoeffs[2] = 0x0000; // KD
PIDCoeffCalc(&kCoeffs[0], &fooPID);
fooPID.controlReference = Vref; //取 0x0000 : 2.5V

while(1) {
while(!sample);
sample = 0;
PID(&fooPID);
fooPID.measuredOutput = PI_in;

if(fooPID.controlOutput > (PWM_Duty_Max - PWM_Duty_Ref)){
PWM_Duty = PWM_Duty_Max; }
else if((fooPID.controlOutput + PWM_Duty_Ref) < PWM_Duty_Min ){
PWM_Duty = PWM_Duty_Min; }
else{
PWM_Duty = fooPID.controlOutput + PWM_Duty_Ref; }

PDC1 = PWM_Duty ;
}}

計算如下:
1.系統頻率:
7.3728 MHz x 16, 每一指令週期需 4 個 clock,
FCY = (7.3728 * 16 / 4 ) MHz = 7372800* 4 => 33.908 ns

2.PWM PTPER 計算與設定:
100kHz = 7.3728 M *4 / 100 k = 294.9120 取 294 = 0x126 (+1也忽略,想要比較快)
所以 PDC1: max: 0x126*2 =0x24c、min: 0x0000;
PWM 重點設定: PWM_INT_DIS、PWM_MOD_FREE。


3.ADC計算與設定:
ADC 重點設定: ADC_FORMAT_SIGN_FRACT、ADC_CLK_MPWM、ADC_INT_PRI_7 & ADC_INT_ENABLE。
ADC 在 特殊事件觸發器發生時,轉換,因此,在PWM負源開始轉換。
ADC 為 signed fractional格是輸出,其值在 0x7fc0 ~ 0x8000 => 0.9980 ~ -1
AD CONVERSION CLOCK (from datasheet):
ADCS<5:0> = 2*154 ns / 33.908 ns -1 = 9.0833 -1 = 8.0833 取 9
=> 設定為 ADC_CONV_CLK_9Tcy
驗算:0.5* 33.908 *(9+1) = 169.54 ns
CONVERSION 需要13個clock => 169.54 ns * 13= 2.204 us < 10us(100khz)


小弟我對DSP lib的了解,如下,
fractional 為 Q15格式 其值在 +0.999x ~ -1 之間,所以怎麼乘都不會超過1。
因此,計算時要先 normalize => kp= 0x143= 就是將輸出限制在 323~-323 之間 加上 PWM_Duty_Ref(245) = 568 ~ -78。
PID lib 係數:
[n]:a = kp + ki + kd
[n-1]:b = -(kp + 2*kd)
[n-2]:c = kd
根據 "16-BIT LANGUAGE TOOLS LIBRARIES" 所述
Cycles (including C-function call and return overheads):30
需要30個 Tcy => 30* 33.908 ns = 1.01724 us 加上conversion rate 後為 1.01724 us + + 2.204 us = 3.22124 us < 10us(100khz)
還有很多時間可以處理其他指令。

怎麼算都不會積分上去,不知道哪裡有問題。


PS. 將PDC1直接接 ADCBUF0 就很正常(放一天都沒事),所以我覺得是PID lib可能還有不懂的地方。

麻煩各位先進前輩、板主與管理員解惑,

感謝。

2月16日 21:49:55

W.W. 於 2019年02月16日 22:05:46
轉換PDF檔 列印


Re: Dspic30f4011 DSP引擎 PID lib 問題 與 PWM、ADC觀念確認。
新會員
註冊日期:
2018/11/12 10:01
所屬群組:
註冊會員
文章: 11
等級: 2; EXP: 12
HP : 0 / 28
MP : 3 / 44
離線
你的問題是說積分會積不上去,可是你只用了KP何來積分?

2月20日 08:39:08
轉換PDF檔 列印


Re: Dspic30f4011 DSP引擎 PID lib 問題 與 PWM、ADC觀念確認。
新會員
註冊日期:
2018/08/30 18:33
所屬群組:
註冊會員
文章: 14
等級: 2; EXP: 50
HP : 0 / 37
MP : 4 / 80
離線
引用:

bear.red 寫道:
你的問題是說積分會積不上去,可是你只用了KP何來積分?


bear.red大你好,我的意思是 我只用了 Kp 可是隔一段時間他就會往 0x0006 與 0x024c saturation。

感覺是被積分上去,用探棒量 VAR1 輸出是正常的,
直接將 ADCBUF0 與 PDC1相接也沒問題。

問題就在 為何只做 Kp 比例放大卻會慢慢飽和?
速度跟PWM頻率有關,PWM越高頻飽和速度越快。

2月20日 09:57:25
轉換PDF檔 列印


Re: Dspic30f4011 DSP引擎 PID lib 問題 與 PWM、ADC觀念確認。
新會員
註冊日期:
2018/11/12 10:01
所屬群組:
註冊會員
文章: 11
等級: 2; EXP: 12
HP : 0 / 28
MP : 3 / 44
離線
了解了,會不會是你資料長度對不上。

PI_in = ReadADC10(0);

fooPID.controlReference = Vref; //取 0x0000 : 2.5V

你的PI_in是數值是0~1023
你的Ref寫取0x0000是2.5V,表示應該是有做資料轉換,應該是-32768~32767

這樣你KP * Error應該很容易超過你設定的飽和上下限吧

以上是我的猜想!

2月20日 15:25:16
轉換PDF檔 列印


Re: Dspic30f4011 DSP引擎 PID lib 問題 與 PWM、ADC觀念確認。
新會員
註冊日期:
2018/08/30 18:33
所屬群組:
註冊會員
文章: 14
等級: 2; EXP: 50
HP : 0 / 37
MP : 4 / 80
離線
bear.red大你好,感謝你的回覆,

在這裡我的ADC輸出格式為 ADC_FORMAT_SIGN_FRACT

所以 根據 dsPIC30F Family Reference Manual Section 17 page 17-5

Signed Fractional (DOUT = sddd dddd dd00 0000)所以輸出會在 0x7fc0 ~ 0x8000 (第一位為正負號)

在dsp lib中 皆是以Q15格式作運算,所以ADC輸出會以2.5V為基準再對 2^15 = 32768做規一化。

進入P控制器後為了不讓資料飽和 將數值乘上 0x0286 (輸出最大值,程式碼好像打錯,copy到亂調的時候...)
保證
ADC輸入最大 0x7FFF 時輸出為 (0x7FFF *0x0286) >> 16 = 0x142 ( fractional 相乘後取前16位 )
ADC輸入最小 0x8000 時輸出同理。

理論上,怎樣都不會超過範圍,而且剛燒入的時候很正常,都要隔一段時間才會慢慢飽和。

想要開始用Dsp引擎增加運算速度,結果一開始嘗試就遇到問題...。

2月20日 16:45:27
轉換PDF檔 列印


Re: Dspic30f4011 DSP引擎 PID lib 問題 與 PWM、ADC觀念確認。
新會員
註冊日期:
2018/11/12 10:01
所屬群組:
註冊會員
文章: 11
等級: 2; EXP: 12
HP : 0 / 28
MP : 3 / 44
離線
你是想控制什麼呢?
或者把整個程式po出來讓大家看看

2月20日 19:41:10
轉換PDF檔 列印


Re: Dspic30f4011 DSP引擎 PID lib 問題 與 PWM、ADC觀念確認。
新會員
註冊日期:
2018/08/30 18:33
所屬群組:
註冊會員
文章: 14
等級: 2; EXP: 50
HP : 0 / 37
MP : 4 / 80
離線
引用:

bear.red 寫道:
你是想控制什麼呢?
或者把整個程式po出來讓大家看看



我只是習慣用 PWM 確認 code 對不對,沒有要特別控制甚麼。

程式碼如下,

#include <p30F4011.h>
#include <pwm.h> // 將pwm函式的原型宣告檔案含入
#include <adc10.h> // 將adc10函式的原型宣告檔案含入
#include "C30EVM_LCD.h" // 將LCD函式的原型宣告檔案含入
#include <dsp.h>

#define FCY 7372800 * 4 // 因為使用頻率為將外部 7.3728 MHz * 16 的模式 , 每一指令週期需 4 個 clock
// 所以 FCY = (7.3728 * 16 / 4 ) MHz = 7372800* 4

_FOSC(CSW_FSCM_OFF & XT_PLL16); //XT with 8xPLL oscillator, Failsafe clock off
_FWDT(WDT_OFF); //Watchdog timer disabled
_FBORPOR(PBOR_OFF & MCLR_EN); //Brown-out reset disabled, MCLR reset enabled
_FGS(CODE_PROT_OFF); //Code protect disabled
//Triger
union {
unsigned char ByteAccess ;
struct {
unsigned Bit0 :1;
unsigned unused :7;
};
}Triger;
#define sample Triger.Bit0



//PID
fractional PI_in;
fractional abcCoefficient[3] __attribute__ ((space(xmemory)));
fractional controlHistory[3] __attribute__ ((space(ymemory)));
fractional kCoeffs[] = {0,0,0};

#define PWM_Duty_Max 568 // PWM Duty 最大值, 44%
#define PWM_Duty_Min 20 // PWM Duty 最小值,
#define PWM_Duty_Ref 245 // PWM Duty 參考準位
#define Vref 0x0000

unsigned int PWM_Duty ;
tPID fooPID;

void Init_MCPWM(void);
void Init_ADC(void) ;

void __attribute__((interrupt, auto_psv)) _ADCInterrupt(void) //Timer1中斷副程式
{
sample = 1;
PI_in = ReadADC10(0);
IFS0bits.ADIF = 0; //清除中斷旗標

}


int main(void)
{
Init_ADC(); //將ADC進行初始化設定
Init_MCPWM(); //將PWM進行初始化設定

fooPID.abcCoefficients = &abcCoefficient[0];
fooPID.controlHistory = &controlHistory[0];
PIDInit(&fooPID);
kCoeffs[0] = 0x0286; // KP
kCoeffs[1] = 0x0000; // KI
kCoeffs[2] = 0x0000; // KD
PIDCoeffCalc(&kCoeffs[0], &fooPID);
fooPID.controlReference = Vref;
TRISEbits.TRISE2 = 0 ;
TRISEbits.TRISE3 = 0 ;

while(1)
{
while(!sample);
LATEbits.LATE3 = ~LATEbits.LATE3;
sample = 0;
PID(&fooPID);
fooPID.measuredOutput = PI_in;

if(fooPID.controlOutput > (PWM_Duty_Max - PWM_Duty_Ref)){ // 處理可能造成的溢位
PWM_Duty = PWM_Duty_Max;
}
else if((fooPID.controlOutput + PWM_Duty_Ref) < PWM_Duty_Min ){
PWM_Duty = PWM_Duty_Min;
}
else{
PWM_Duty = fooPID.controlOutput + PWM_Duty_Ref;
}

PDC1 = PWM_Duty ;

}
}

/******************************************************/
// Subroutine to configure the Motor Control PWM module

void Init_MCPWM(void)
{
/* Holds the PWM interrupt configuration value*/
unsigned int config;
/* Holds the value to be loaded into dutycycle register */
unsigned int period;
/* Holds the value to be loaded into special event compare register */
unsigned int sptime;
/* Holds PWM configuration value */
unsigned int config1;
/* Holds the value be loaded into PWMCON1 register */
unsigned int config2;
/* Holds the value to configure the special event trigger postscale and dutycycle */
unsigned int config3;
/* The value of ‘dutycyclereg’ determines the duty cycle register(PDCx) to be written */
unsigned int dutycyclereg;
/*The pointer to the Duty Cycle register*/
unsigned int dutycycle;
/*The value to be stored in the Duty Cycle register*/
unsigned char updatedisable;
/*The value to be loaded into the ‘Update Disable’ bit of PWMCON2.*/
unsigned int config_DT;
/*The parameters to be configured in the DTCON2 register */
unsigned int config_F;
/*The parameters to be configured in the FLTACON register*/

/* Configure pwm interrupt enable/disable and set interrupt priorties */
config = (PWM_INT_DIS & PWM_FLTA_DIS_INT & PWM_INT_PR1
& PWM_FLTA_INT_PR0);
ConfigIntMCPWM( config );
/* configures the Duty Cycle register and updates the "PWM" */
dutycyclereg = 1;
dutycycle = 0x0126;
updatedisable = 0;
SetDCMCPWM(dutycyclereg,dutycycle,updatedisable);
/*configures the dead-time values and clock prescalers*/
config_DT = ( PWM_DTBPS1 & PWM_DTB0 & PWM_DTAPS1 & PWM_DTA6 );
SetMCPWMDeadTimeGeneration(config_DT);
/*configures the Fault A Override bits, the Fault A Mode bit and the Fault Input A Enable bits of the PWM*/
config_F = ( PWM_OVA1H_INACTIVE & PWM_OVA1L_INACTIVE
& PWM_FLTA_MODE_CYCLE & PWM_FLTA1_EN );
SetMCPWMFaultA(config_F);
/* configures the Motor Control PWM module*/
period = 0x0126;
sptime = 0x0000;
config1 = (PWM_EN & PWM_IDLE_STOP & PWM_OP_SCALE1
& PWM_IPCLK_SCALE1 & PWM_MOD_FREE);
config2 = (PWM_MOD1_COMP & PWM_MOD2_COMP & PWM_MOD3_COMP &
PWM_PDIS3H & PWM_PDIS2H & PWM_PEN1H &
PWM_PDIS3L & PWM_PDIS2L & PWM_PEN1L);
config3 = (PWM_SEVOPS1 & PWM_OSYNC_PWM & PWM_UEN);
OpenMCPWM(period,sptime,config1,config2,config3);
}

/***********************************************/
// Subroutine to configure the A/D module

void Init_ADC(void)
{

unsigned int Channel, PinConfig, Scanselect, Adcon3_reg, Adcon2_reg, Adcon1_reg;

ADCON1bits.ADON = 0; /* turn off ADC */

PinConfig = ENABLE_AN0_ANA & // Select port pins as analog inputs ADPCFG<15:0>
ENABLE_AN6_ANA ;

Adcon1_reg = ADC_MODULE_ON & // Turn on A/D module (ADON)
ADC_IDLE_STOP & // ADC turned off during idle (ADSIDL)
ADC_FORMAT_SIGN_FRACT & // Output in integer format (FORM)
ADC_CLK_MPWM & //*Conversion trigger automatically (SSRC)
ADC_SAMPLE_SIMULTANEOUS & //*Sample channels simultaneously (SIMSAM)
ADC_AUTO_SAMPLING_ON & //*Sample trigger automatically (ASAM)
ADC_SAMP_ON ; //

Adcon2_reg = ADC_VREF_AVDD_AVSS & // Voltage reference : +AVdd, -AVss (VCFG)
ADC_SCAN_OFF & // Scan off (CSCNA)
ADC_ALT_BUF_OFF & // Use fixed buffer (BUFM)
ADC_ALT_INPUT_OFF & // Does not alternate between MUX A & MUX B (ALTS)
ADC_CONVERT_CH_0A & // Convert only channel 0 (CHPS)
ADC_SAMPLES_PER_INT_1; //*2 samples between interrupt (SMPI)

Adcon3_reg = ADC_SAMPLE_TIME_1 & // Auto-Sample time (SAMC)
ADC_CONV_CLK_SYSTEM & // Use system clock (ADRC)
ADC_CONV_CLK_9Tcy ; // Conversion clock = 4 Tcy (ADCS)
// ADCS = 2*(154ns)/(1/Fcy)-1 = 8.0833
// TAD = (ADCS+1)/(2*Fcy) = 169.54ns

Scanselect = SCAN_NONE; // ADC scan no channel (ADCSSL)

OpenADC10(Adcon1_reg, Adcon2_reg, Adcon3_reg, PinConfig, Scanselect);

Channel = ADC_CH0_POS_SAMPLEA_AN6 & //*CH0 Pos. : AN6, Neg. : Nominal Vref- Defined in ADCON2
ADC_CH0_NEG_SAMPLEA_NVREF &
ADC_CHX_POS_SAMPLEA_AN0AN1AN2 &
ADC_CHX_NEG_SAMPLEA_NVREF ; // (ADCHS)

SetChanADC10(Channel);

ConfigIntADC10( ADC_INT_PRI_7 & ADC_INT_ENABLE); // Disable ADC interrupt

}

2月20日 21:51:29
轉換PDF檔 列印


Re: Dspic30f4011 DSP引擎 PID lib 問題 與 PWM、ADC觀念確認。
新會員
註冊日期:
2018/11/12 10:01
所屬群組:
註冊會員
文章: 11
等級: 2; EXP: 12
HP : 0 / 28
MP : 3 / 44
離線
你好,我想請問你的ADCBUF0的輸入信號是?
我手邊剛好有dsPIC30F4011的板子,可以來嘗試看看

2月21日 16:49:36
轉換PDF檔 列印


Re: Dspic30f4011 DSP引擎 PID lib 問題 與 PWM、ADC觀念確認。
新會員
註冊日期:
2018/08/30 18:33
所屬群組:
註冊會員
文章: 14
等級: 2; EXP: 50
HP : 0 / 37
MP : 4 / 80
離線
bear.red大你好,

輸入是 VR1 開發板是 APP020PLUS,開關為預設開關,

示波器探棒勾在 CON9 的 RE0(PWM1) 與 RB6 (ADC、AN6),SW5是PWM Faltout。

麻煩 bear.red 測試了,

謝謝。

2月21日 17:15:41
轉換PDF檔 列印


Re: Dspic30f4011 DSP引擎 PID lib 問題 與 PWM、ADC觀念確認。
新會員
註冊日期:
2018/08/30 18:33
所屬群組:
註冊會員
文章: 14
等級: 2; EXP: 50
HP : 0 / 37
MP : 4 / 80
離線
最近用 MPLAB X simulator 測試手算 與 模擬的值比對,發現算出來得值真有差異,

手動計算如下:
PI_in = 0xFAC0

kCoeffs[0] = 0x0286
kCoeffs[1] = 0x0000
kCoeffs[2] = 0x0000

abcCoefficient[0] = Kp + Ki + Kd = kCoeffs[0] = 0x0286

abcCoefficient[1] = -(Kp + 2*Kd) = -Kp 等於 kCoeffs[0] 取補數,所以
abcCoefficient[1] = FD7A

abcCoefficient[2] = Kd = kCoeffs[2] = 0x0000

PI_in為固定值 controlHistory 為固定值
controlHistory [n] = MeasuredOutput[n] - ReferenceInput[n]
= 0x0000-0xFAC0 等於 0xFAC0 取補數,所以
controlHistory = 0x0540

Kp * controlHistory = 0x 000D 3F80 (小算盤)



查看 simulator

PI_in = 0xFAC0

kCoeffs[0] = 0x0286
kCoeffs[1] = 0x0000
kCoeffs[2] = 0x0000

abcCoefficient[0] = 0x0286
abcCoefficient[1] = FD7A
abcCoefficient[2] = 0x0000

controlHistory[0] = 0x0540
controlHistory[1] = 0x0540
controlHistory[2] = 0x0540

controlOuput = 0x001A

比較 手算 與 模擬器 顯示結果

0x000D 3F80 = ________0000 0000 0000 1101 0011 1111 1000 0000 (binary)
controlOuput = 0x001A = 0000 0000 0001 1010

完全一樣....
看不出來哪裡有問題...

3月01日 16:29:22
轉換PDF檔 列印






無法在此發表文章
可以在此觀看文章
無法回覆文章
無法編輯自己的文章
無法刪除自己的文章
無法發起投票調查
無法在此投票
無法上傳附加檔案
無法不經審核直接發表文章

[進階搜尋]


搜尋
Microchip連結

網頁捷徑
教育訓練
其它網站連結
電話: 02-25000405
產品技術問題產品技術支援專線:0800-717718 台北02-25088600 新竹03-5778366 Ext. 8600 高雄07-2137830 MicrochipDIRECT 專線: 07-2137830
Powered by XOOPS © 2001-2012 The XOOPS Project