📄 pid.c
字号:
#include <absacc.h>
#include "s_table.h"
#include "jdq.h"
#include "delay.h"
#include <reg52.h>
#include "pid.h"
#include <string.h>
#include <math.h>
#include "Xdata.h"
#include "watchdog.h"
#include "sja.h"
const int DUmax = 2; /*控制量增量最大值*/
/*========================================================================
数据采集
========================================================================*/
UINT CalcTemp() /* 计算当前温度 返回16进制数据*/
{
UINT airtemp = cool_temp_bk >> 4;
float bias_vol = temp2vol(airtemp);
float ad_vol = ad_val_bk[0]/1310.7; /*2500.0/((64*1024-1)*50.0);*/
float vol = bias_vol + ad_vol;
clear_watchdog();
return vol2temp(vol);
}
float CalcAngle() /* 计算当前角度 */
{
float vol = ad_val_bk[1]*2500.0/(64*1024-1);
return (90.0 * vol)/1000.0 ;/*测得角度满偏时电压为2V*/
clear_watchdog();
}
void Init_Para() /*参数初始化*/
{
/*========================================================
设定值曲线参数
==========================================================*/
p = 100;
I = 100;
D = 1;
Rk = 50; /*==================++++++++++++++++++++++===========*/
Ts = 4;
EnablePID = 1; /*模块PID计算*/
Sens = .1; /*灵敏度*/
DataFrame = 10; /*初始无有效数据帧编号*/
Ek1 = 0;
DeltEk1 = 0;
Yk1 = 0;
DeltYk1 = 0;
/*========================================================
设定值曲线参数
==========================================================*/
U=12; /***********+++++++++++++++++++**************/
SP2 = 1200;
SP_temp = Rk;
SPOneStepVal = 1; //步长
SP1toSP2Time = 0; //时间间隔
/*****************************************************************
临时:测试用
/*****************************************************************/
Yk = 1000;
TempPIDUINT = 0;
}
void save_pid(BYTE nrfrm,BYTE idata* dat)/*将上位机发送过来的值放到接收缓冲区中*/
{
EA = 0;
memcpy((BYTE xdata*)(sPID.ReceiveValue.bValue+6*nrfrm),dat,6);
EA = 1;
clear_watchdog();
}
void Update_PID_Para()/*更新PID参数及其他数据,来自计算缓冲区内*/
{
if(OnNewData == FALSE)
return;
EA = 0;/*禁止对接收缓冲区的访问*/
memcpy((BYTE xdata*)(sPID.CalValue.bValue),(BYTE xdata*)(sPID.ReceiveValue.bValue),PIDLEN);
EA = 1;
OnNewData = FALSE;
if (DataFrame==0) {
if (CheckPara(sPID.CalValue.sValue._P))
p=sPID.CalValue.sValue._P;
if (CheckPara(sPID.CalValue.sValue._I))
I=sPID.CalValue.sValue._I;
if (CheckPara(sPID.CalValue.sValue._D))
D=sPID.CalValue.sValue._D;
}
else if (DataFrame==1) {
if (CheckPara(sPID.CalValue.sValue.SetPoint)){
Rk=sPID.CalValue.sValue.SetPoint;
}
Sens=sPID.CalValue.sValue.SensitiveH+sPID.CalValue.sValue.SensitiveL/256.0;
}
else if (DataFrame==2) {
Ts=sPID.CalValue.sValue.CMod.Tsample;
EnablePID=sPID.CalValue.sValue.CMod.EnPID;
if (EnablePID == 2)
MotorDir=sPID.CalValue.sValue.CMod.MotorDirec;
}
clear_watchdog();
return;
}
void Update_Calbuffer_Para2Send() /*更新发送缓冲区数据,来自PID参数*/
{
BYTE i;
EA=0;
sPID.SendValue.sValue._P=p;
sPID.SendValue.sValue._I=I;
sPID.SendValue.sValue._D=D;
sPID.SendValue.sValue.CMod.Tsample=Ts;
sPID.SendValue.sValue.SetPoint=Rk;
sPID.SendValue.sValue.SensitiveH=(BYTE)(Sens);
sPID.SendValue.sValue.SensitiveL=(BYTE)((Sens-sPID.SendValue.sValue.SensitiveH)*256);
sPID.SendValue.sValue.CMod.EnPID=EnablePID;
EA=1;
clear_watchdog();
return;
}
void CheckU() /*检验控制量是否超过上下限*/
{
if (U>=Umax) {
U = Umax;
}
else if(U<=Umin) {
U = Umin;
}
}
BYTE CheckPara(float Para)
{
if ((Para >= 0)&&(Para<=1300))
return 1;
else
return 0;
clear_watchdog();
}
/*校验各参数的有效性*/
void UpdateData() /*更新检测数据,置于发送缓冲区*/
{
BYTE i;
Update_Calbuffer_Para2Send(); /*将PID参数送回发送缓冲区*/
/*当前温度,控制量,阀位反馈值 送回发送缓冲区*/
EA=0;
sPID.SendValue.sValue.Temperature = Yk; /*温度检测值*/
sPID.SendValue.sValue._UH = (BYTE)(U);
sPID.SendValue.sValue._UL = (BYTE)((U-sPID.SendValue.sValue._UH)*256); /*控制量*/
sPID.SendValue.sValue._AngleH = (BYTE)(Angle);/*阀位反馈,角度*/
sPID.SendValue.sValue._AngleL = (BYTE)((Angle-sPID.SendValue.sValue._AngleH)*256);
sPID.SendValue.sValue.CMod.MotorDirec = MotorDir;/*电机转动方向*/
EA=1;
clear_watchdog();
return;
}
/*========================================================================
pid主函数 通过控制量或增量控制电机转动
========================================================================*/
/*========================================================================
王占成:精简PID算法,只用一种PID微分先行,有阀位反馈
========================================================================*/
void PID()
{
signed long tempDeltU;
float tempU;
tempU = U;
/*计算Kp,Ki,Kd*/
/*================================
将float乘以1000,转化成long型进行计算
===================================*/
Kp = 100000/p;
Ki = Kp/I*Ts;
/*Kd少乘100,方便与上层通讯*/
Kd = Kp*D/(Ts*100);
/*计算DeltU*/
/*================================
将float乘以1000,转化成long型进行计算
===================================*/
//扩大1000倍,ymax-ymin = 1000*/
DeltYk = (signed int)(Yk - Yk1);
Ek = (signed int)(Rk-Yk);
DeltEk = Ek - Ek1;
tempDeltU = Kp*DeltEk;
tempDeltU += Ki*Ek;
tempDeltU += Kd*(DeltYk - DeltYk1);
//反归一化
DeltU = (float)tempDeltU/10000.0;
//控制量变化量限幅
if(DeltU >= DUmax) {
U += DUmax;
}
else if(DeltU <= -DUmax) {
U -= DUmax;
}
else {
U += DeltU;
}
/*控制量限幅*/
CheckU();
/*防止出现控制量突变*/
if(abs(U-tempU) > DUmax) {
U = tempU;
}
/*动作继电器*/
if ((U-Angle)>Sens) {
set_jdq_mode(2);
MotorDir =2;
} /*正转*/
else if((U-Angle)<-Sens){
set_jdq_mode(1);
MotorDir =1;
} /*反转*/
else {
set_jdq_mode(0);
MotorDir =0;
}
/*保存参数*/
Ek1 = Ek;
DeltEk1 = DeltEk;
Yk1 = Yk;
DeltYk1 = DeltYk;
clear_watchdog();
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -