⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pid.c

📁 一个锅炉温度控制程序
💻 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 + -