常见的PID实现方法多是基于浮点数来计算的,如果选用的MCU的Flash资源紧张,
或是想提高MCU效率,也可以使用整数来实现PID,代码如下:
typedef struct
{
short Proportion; //比例常数 Proportional Cons
short Integral; //积分常数 Integral Const
short Derivative; //微分常数 Derivative Const
short LastError; //Error[-1]
short PrevError; //Error[-2]
u16 SetPoint; //设定目标 Desired Value
u16 SetPointBack;
u32 SumError; //误差累计
} stc_PID_t;
/* 一般先调整P,再调整D,最后调整I
* P的调整要看系统的响应程度,当调整适当后,超调比较小
* D的调整是为了减少震荡,尽量少的增加,大概为P的5%
* 当震荡减小后,调整I时,对P要适当减小为80%左右,I的调整是为了减小静态误差,大约为10%的P值,不要过大
*/
void PID_Arg_Init(stc_PID_t *sPtr, u16 P, u16 I, u16 D, u16 Aims)
{
sPtr->SumError = 0;
sPtr->LastError = 0;
sPtr->PrevError = 0;
sPtr->SetPoint = Aims;
sPtr->SetPointBack = Aims;
sPtr->Proportion = P;
sPtr->Integral = I;
sPtr->Derivative = D;
}
/*******************************************************************************
* 函数名称 : IncPIDCalc
* 函数描述 : 增量式 PID 控制计算
* 函数输入 : int 当前位置
* 函数输出 : 无
* 函数返回 : 增量式PID结果
*******************************************************************************/
int16_t IncPIDCalc(stc_PID_t *sPtr, u16 NextPoint)
{
int iError, iIncpid;
// 当前误差
iError = sPtr->SetPoint - NextPoint;
// 增量计算
iIncpid = (sPtr->Proportion * iError //E[k]项
- sPtr->Integral * sPtr->LastError //E[k-1]项
+ sPtr->Derivative * sPtr->PrevError) / 32768; //E[k-2]项
// 存储误差,用于下次计算
sPtr->PrevError = sPtr->LastError;
sPtr->LastError = iError;
// 返回增量值
return(iIncpid);
}
/*******************************************************************************
* 函数名称 : LocPIDCalc
* 函数描述 : 位置式 PID 控制计算
* 函数输入 : int 当前位置
* 函数输出 : 无
* 函数返回 : 位置式PID结果
*******************************************************************************/
int16_t LocPIDCalc(stc_PID_t *sPtr, u16 NextPoint)
{
int iError,dError;
iError = sPtr->SetPoint - NextPoint; // 偏差
sPtr->SumError += iError; // 积分
dError = iError - sPtr->LastError; // 微分
sPtr->LastError = iError;
return(sPtr->Proportion * iError // 比例项
+ sPtr->Integral * sPtr->SumError // 积分项
+ sPtr->Derivative * dError) / 32768; // 微分项
}
|