工具/软件:Code Composer Studio
你(们)好
我在使用 C2000 - F28069M 进行 PWM 和 ADC 配置时遇到问题。 我需要对 ADC 读取的某些值应用电流 PI 控制器、并通过 ePWM 发送控制器输出。 出现了问题、似乎是时钟? 受控值的变化过多、我有一个具有相同值的仿真、并且控制器增益工作正常。 我将我的代码放在下面。 我认为问题可能与 ADC 和 PWM 的时钟有关、也可能与之相关。 我需要读取5个 ADC 通道。
提前感谢您的帮助、请查看以下代码
#include "DSP28x_Project.h"//器件头文件和示例 include 文件
//#include
#include
_interrupt void ADC_ISR (void);
void ADC_Config (void);
void InitEPwm1Examples(void);
uint32 EPwm1TimerIntCount;
uint16 EPwm1_DB_DIRECTION;
//初始值
#define INTERINAL_CMPA 2250;
#define Epwm1_TBPRD 2250;//
//此示例中使用的全局变量:
uint16环计数;
UINT16转换计数;
uint16 i_count=0;
uint16 i_val=0;
uint16 adc_sample;
uint16 Voltage1[10];
float32 iboost = 0;
uint16 iBOOST_DSP = 0;
float32 VIN = 0;
uint16 VIN_DSP = 0;
float32 IPV = 0;
uint16 IPV_DSP = 0;
float32 Vout = 0;
uint16 Vout_DSP = 0;
uint16k;
//控制器设置
浮点32 KP = 5.78;
float32 Ki = 33.333;
float32 ini=0;
float32错误=0;
float32 v_inductor=0;
float32 pi=0;
float32 vcdc=0;
float32 m=0;
uint16 m_CMPA=0;
float32dt = 1/10e3;
float32 iboost_sp = 0;//1755 -近30安培
//控制器内部环路
float32 e_new = 0;
float32 e_old = 0;
float32 y_new = 0;
float32 y_old = 0;
float32 delta_y = 0;
//控制器外部环路
float32 VIN_sp = 100;
float32 e_new_o = 0;
float32 e_old_o = 0;
float32 y_new_o = 0;
float32 y_old_o = 0;
float32 delta_y_o = 0;
float32 to_time = 0;
float32 sine_50Hz = 0;
float32 f = 50;
uint16 sine_CMPA = 0;
float32 Icpv = 0;
float32 Kp_o = 0.066667;
float32 KI_o = 25.641;
#define ADC_MODCLK 0x96 // HSPCLK = SYSCLKOUT/2*ADC_MODCLK2 = 150/(2*3)= 25.0MHz
MAIN ()
{
//步骤1. 初始化系统控制:
// PLL、安全装置、启用外设时钟
InitSysCtrl();
//步骤2. 初始化 GPIO:
InitEPwm1Gpio();
//步骤3. 清除所有中断并初始化 PIE 矢量表:
//禁用 CPU 中断
Dint;
//将 PIE 控制寄存器初始化为默认状态。
//默认状态为禁用所有 PIE 中断和标志
//被清除。
InitPieCtrl();
//禁用 CPU 中断并清除所有 CPU 中断标志:
IER = 0x0000;
IFR = 0x0000;
//使用指向 shell 中断的指针初始化 PIE 矢量表
InitPieVectTable();
//此示例中使用的中断被重新映射到
//此文件中的 ISR 函数。
EALLOW;//这是写入 EALLOW 受保护寄存器所必需的
PieVectTable.ADCINT1 =&ADC_ISR;
SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC=0;
EDIS;//这是禁止写入 EALLOW 受保护寄存器所必需的
//步骤4. 初始化所有器件外设:
对于(I = 0;I< ADC_BUF_LEN;I++)
{
AdcBuf[i]= 0x0000;
AdcFiltBuf[i]= 0x0000;
}
// init_cla();
init_adc();
InitEPwm1Examples();
InitAdc ();//对于此示例,初始化 ADC
AdcOffsetSelfCal();
EALLOW;
SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC=1;
EDIS;
//步骤5. 特定于用户的代码、启用中断:
EPwm1TimerIntCount = 0;
//在 PIE 中启用 ADCINT1启用中断
PieCtrlRegs.PIEIER1.bit.INTx1 = 1;//在 PIE 中启用 INT 1.1
IER |= M_INT1;//启用 CPU 中断1
EINT;//启用全局中断 INTM
ERTM;//启用全局实时中断 DBGM
LoopCount = 0;
ConversionCount = 0;
//配置 ADC
EALLOW;
AdcRegs.ADCCTL2.bit.ADCNONOVERLAP = 1;//启用非重叠模式
AdcRegs.ADCCTL1.bit.INTPULSEPOS = 1;// ADCINT1在 AdcResults 锁存后跳闸
AdcRegs.INTSEL1N2.bit.INT1E = 1;//启用 ADCINT1
AdcRegs.INTSEL1N2.bit.INT1CONT = 0;//禁用 ADCINT1连续模式
AdcRegs.INTSEL1N2.bit.INT1SEL = 1;//设置 EOC1以触发 ADCINT1触发
AdcRegs.ADCSOC0CTL.bit.CHSEL = 11;//将 SOC0通道选择设置为 ADCINB3
AdcRegs.ADCSOC1CTL.bit.CHSEL = 2;//将 SOC1通道选择设置为 ADCINA2
AdcRegs.ADCSOC2CTL.bit.CHSEL = 9;//将 SOC1通道选择设置为 ADCINB1
AdcRegs.ADCSOC3CTL.bit.CHSEL = 10;//将 SOC1通道选择设置为 ADCINB2
//AdcRegs.ADCSOC4CTL.bit.CHSEL = 12;//将 SOC1通道选择设置为 ADCINB14
AdcRegs.ADCSOC0CTL.bit.TRIGSEL = 5;//设置 SOC0在 EPWM1A 上启动触发器,因为轮询 SOC0先转换,然后 SOC1
AdcRegs.ADCSOC1CTL.bit.TRIGSEL = 5;//设置 EPWM1A 上的 SOC1启动触发器,因为 SOC0先转换,然后 SOC1
AdcRegs.ADCSOC2CTL.bit.TRIGSEL = 5;//设置 EPWM1A 上的 SOC1启动触发器,因为 SOC0先转换,然后 SOC1
AdcRegs.ADCSOC3CTL.bit.TRIGSEL = 5;//设置 EPWM1A 上的 SOC1启动触发器,因为 SOC0先转换,然后 SOC1
//AdcRegs.ADCSOC4CTL.bit.TRIGSEL = 5;//设置 EPWM1A 上的 SOC1启动触发器、因为轮询 SOC0先转换、然后 SOC1
AdcRegs.ADCSOC0CTL.bit.ACQPS = 6;//将 SOC0 S/H 窗口设置为7个 ADC 时钟周期(6个 ACQPS 加1)
AdcRegs.ADCSOC1CTL.bit.ACQPS = 6;//将 SOC1 S/H 窗口设置为7个 ADC 时钟周期(6个 ACQPS 加1)
AdcRegs.ADCSOC2CTL.bit.ACQPS = 6;//将 SOC1 S/H 窗口设置为7个 ADC 时钟周期(6个 ACQPS 加1)
AdcRegs.ADCSOC3CTL.bit.ACQPS = 6;//将 SOC1 S/H 窗口设置为7个 ADC 时钟周期(6个 ACQPS 加1)
//AdcRegs.ADCSOC4CTL.bit.ACQPS = 6;//将 SOC1 S/H 窗口设置为7个 ADC 时钟周期(6个 ACQPS 加1)
EDIS;
//假设 ePWM1时钟已在 InitSysCtrl()中启用;
EPwm1Regs.ETSEL.bit.SOCAEN = 1;//启用组上的 SOC
EPwm1Regs.ETSEL.bit.SOCASEL = 2;//在向上计数时从 CMPA 中选择 SOC --- 在中间
EPwm1Regs.ETPS.bit.SOCAPRD = 1;//在发生第一个事件时生成脉冲
//等待 ADC 中断
for (;;)
{
LoopCount++;
_asm (" NOP");
}
}
_interrupt void ADC_ISR (void)
{
IF (((m<-0.5)||(m>1.5))
{
M = 0;e_new_o=0;delta_y_o=0;y_new_o=0;Icpv=0; iBOOST_sp=0;y_old_o=0;e_old_o=0;
e_new=0;delta_y=0;y_new=0;v_inductor=0;vcdc=0; m_CMPA=0;y_old=0;e_old=0;e_old=0;
}
I_COUNT = I_COUNT+1;
tot_time = tot_time + dt;
Sine 50Hz = 2250* sin (2*3.14* f*tot_time)+2250;
Sine CMPA = Sine 50Hz;
//读取升压值后,我们需要使用开关模型中使用的光石值对其进行缩放
//ADC 转换器从0到4096读取 alue、这意味着升压转换器从0到3.3V 的电压范围
//根据每个值,我们都有一个比例因子
iBOOST_DSP = AdcResult.ADCRESULT0;
iboost =(unsigned int)(((float) iboost_dsp)/4096*3.3* 700/33);//缩放因子33/700在升压输出端实现3.3V 电压
VIN_DSP = AdcResult.ADCRESULT1;
Vin =(unsigned int)(((float) VIN_DSP)/4096*3.3* 5000/33);//缩放因子33/5000在升压输出端实现3.3V 电压
Vout_DSP = AdcResult.ADCRESULT2;
Vout=(unsigned int)(((float) Vout_DSP)/4096*3.3* 9000/11);//缩放因子11/9000在升压输出端实现3.3V 电压
IPV_DSP = AdcResult.ADCRESULT3;
IPV =(无符号整数)(((浮点) IPV_DSP)/4096*3.3* 700/33);//缩放因子33/700在升压输出端实现3.3V 电压
Voltage1[ConversionCount]= AdcResult.ADCRESULT0;
//控制器 FF
//error = iBOOST_sp - iBOOST;
//integral = integre+Ki*error*dt;
//PI = KP*ERROR+INTEGRAL;
//v_inductor = PI;
//新控制器外部环路
//e_new_o = VIN_sp - VIN;//新错误(实际)
//delta_y_o = kp_o*(e_new_o-e_old_o)+dt * ki_o* e_old_o;
//y_new_o = y_old_o + delta_y_o;
//Icpv = y_new_o;
//vcdc = VIN-v_inductor;
//iboost_sp = IPV - Icpv;
//m = 1- vcdc/Vout;
//m_CMPA =(unsigned int)(m*4500);
y_old_o = y_new_o;
e_old_o = e_new_o;
iboost_sp = 30;
//新建控制器内部环路
e_new =(iboost_sp - iboost);//新错误(实际)
Δ_y = KP*(e_new-e_old)+dt * KI* e_old;
y_new = y_old + delta_y;
V_inductor = y_new;
vcdc = VIN-v_inductor;
M = 1- vcdc/Vout;
m_CMPA =(unsigned int)(m*2250);
y_old = y_new;
e_old = e_new;
//如果记录了10次转换,则重新开始
if (ConversionCount = 9)
{
ConversionCount = 0;
}
else ConversionCount++;
EPwm1Regs.CMPA.half.CMPA = m_CMPA;//(unsigned int)(((float) ADC_sample)* 1.095);//140;或280/2=0.5 dutycycle、用于检查是否为10K 完全 FFT
//我使用15除法作为比例因子!!! (PWM 载波几乎为我的波的15个)
EPwm1TimerIntCount++;
//清除此计时器的 INT 标志
EPwm1Regs.ETCLR.bit.INT = 1;
AdcRegs.ADCINTFLGCLR.bit.ADCINT1 = 1;//清除 ADCINT1标志为下一个 SOC 重新初始化
PieCtrlRegs.PIEACX.ALL = PIEACK_Group1;//确认 PIE 中断
返回;
}
空 InitEPwm1Examples()
{
EPwm1Regs.TBPRD = EPwm1_TBPRD;//10Kz -第1KHz 段 funciona mux bien poner 2750
EPwm1Regs.TBPHS.Half.TBPHS = 0x0000;//相位为0
EPwm1Regs.TBCTR = 0x0000;//清除计数器
//设置 TBCLK
EPwm1Regs.TBCTL.bit.CTRMODE = TB_COUNT_UPDOWN;//向上计数
EPwm1Regs.TBCTL.bit.PHSEN = TB_DISABLE;//禁用相位加载
EPwm1Regs.TBCTL.bit.HSPCLKDIV = TB_DIV1;//时钟与 SYSCLKOUT 的比率
EPwm1Regs.TBCTL.bit.CLKDIV = TB_DIV1;
EPwm1Regs.CMPCTL.bit.SHDWAMODE = CC_SHADODE;//每0加载一次寄存器
EPwm1Regs.CMPCTL.bit.SHDWBMODE = CC_SHADOW;
EPwm1Regs.CMPCTL.bit.LOADAMODE = CC_CTR_ZERO;
EPwm1Regs.CMPCTL.bit.LOADBMODE = CC_CTR_ZERO;
//设置比较
EPwm1Regs.CMPA.half.CMPA =初始化 CMPA;
//设置操作
EPwm1Regs.AQCTLA.bit.CAU = AQ_SET;//在 CAU 上设置 PWM1A
EPwm1Regs.AQCTLA.bit.CAD = AQ_CLEAR;//清除 CAD 上的 PWM1A
EPwm1Regs.AQCTLB.bit.CAU = AQ_CLEAR;//清除 CAU 上的 PWM1B
EPwm1Regs.AQCTLB.bit.CAD = AQ_SET;//在 CAD 上设置 PWM1B
//低电平有效 PWM -设置死区
EPwm1Regs.DBCTL.bit.OUT_MODE = DB_FUL_ENABLE;
EPwm1Regs.DBCTL.bit.POLSEL = DB_ACTV_LO;
EPwm1Regs.DBCTL.bit.IN_MODE = DBA_ALL;
// EPwm1Regs.DBRED = EPWM1_MIN_DB;
// EPwm1Regs.DBFED = EPWM1_MIN_DB;
//中断,我们将在其中更改死区
EPwm1Regs.ETSEL.bit.INTSEL = ET_CTR_ZERO;//选择零事件时的 INT
EPwm1Regs.ETSEL.bit.INTEN = 1;//启用 INT
EPwm1Regs.ETPS.bit.INTPRD = et_3rd;//在第三个事件发生时生成 INT
}
此致
Maria