PID通常和PWM一起使用。
PWM配置
void PWM_init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd( RCC_APB2Periph_TIM8, ENABLE);
RCC_AHB1PeriphClockCmd( RCC_AHB1Periph_GPIOC|RCC_AHB1Periph_CRC,ENABLE);
/*PC8 PWM管脚初始化*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 ;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_pp;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC , &GPIO_InitStructure);
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_DeInit(TIM8);
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStructure.TIM_Period = 4000 - 1;
TIM_TimeBaseInitStructure.TIM_Prescaler = 17;
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM8, &TIM_TimeBaseInitStructure);
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = 0;//初始占空比
TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset;
TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset;
TIM_OC3Init(TIM8, &TIM_OCInitStructure);
//TIM8 第3通道
TIM_OC3PreloadConfig(TIM8, TIM_OCPreload_Enable);
TIM_CtrlPWMOutputs(TIM8, ENABLE);
TIM_ARRPreloadConfig(TIM8, ENABLE);
TIM_Cmd(TIM8, ENABLE);
}
增量式PID初始化
typedef struct{
float SetValue; //设定值
float ActualValue; //实际值,控制量
float Err; //本次误差
float Err_Prev; //上一次误差
float Err_Last; //最上次误差
float Kp,Ki,Kd; //比例系数,微分系数
}Inc_PID; //增量式PID结构体定义
Inc_PID IncPID;
//增量式PID初始化
void Init_IncPID(void)
{
IncPID.SetValue = 0;
IncPID.ActualValue = 0;
IncPID.Err = 0;
IncPID.Err_Last = 0;
IncPID.Err_Prev = 0;
IncPID.Kp = 5;
IncPID.Ki = 0;
IncPID.Kd = 3;
}
/*增量式PID控制*/
float IncPIDFun(float SetValue,float RetValue)
{
float IncValue = 0.0;
IncPID.SetValue = SetValue;
IncPID.Err = IncPID.SetValue - RetValue;
IncValue = IncPID.Kp * (IncPID.Err - IncPID.Err_Prev) + IncPID.Ki * IncPID.Err + IncPID.Kd * (IncPID.Err - 2*IncPID.Err_Prev + IncPID.Err_Last);
IncPID.ActualValue += IncValue;
IncPID.Err_Last = IncPID.Err_Prev;//下一次迭代
IncPID.Err_Prev = IncPID.Err;
return IncPID.ActualValue;
}
应用
int main(void)
{
PWM_init();
Init_IncPID();
while(1)
{
/*以下运用代码最好写在定时器中断中,通过更改KP,Ki,Kd的初始化来进行PID控制*/
uint16_t PWMWidth = 0,PWM = 0;
PWMWidth =IncPIDFun(SEtTemp,TemP);//控制温度(设定温度,实际温度)
if(PWMWidth<0)
{
PWM=0;
}
else
{
PWM= PWMWidth ;
}
//修改占空比
TIM_SetCompare3(TIM8,PWM);
IWDG_Feed();//喂狗
}
}
以下是位置式PID代码
typedef struct{
float SetValue; //设定值
float ActualValue; //实际值
float ControlValue; //生成控制量
float Err; //本次误差
float Err_Last; //上次误差
float Kp,Ki,Kd; //比例系数,微分系数
float Integral; //误差累计
}Pos_PID; //位置式PID结构体定义
Pos_PID PosPID;
void Init_PosPID(void)
{
PosPID.SetValue = 0;
PosPID.ActualValue = 0;
PosPID.ControlValue = 0;
PosPID.Err = 0;
PosPID.Err_Last = 0;
PosPID.Integral = 0;
PosPID.Kp = 5;
PosPID.Ki = 0.001;
PosPID.Kd = 3;
}
float PosPIDFun(float SetValue,float Value)
{
PosPID.SetValue = SetValue;
PosPID.Err = PosPID.SetValue - Value;//PosPID.ActualValue;
PosPID.Integral += PosPID.Err;
PosPID.ControlValue = PosPID.Kp*PosPID.Err + PosPID.Ki*PosPID.Integral + PosPID.Kd*(IncPID.Err - PosPID.Err_Last);
PosPID.Err_Last = PosPID.Err;
PosPID.ActualValue = PosPID.ControlValue * 1.0;
return PosPID.ActualValue;
}