51单片机PID算法程序(三)增量式PID控制算法要点
- 格式:doc
- 大小:377.00 KB
- 文档页数:16
增量式PID的整型算法对于PID控制的程序算法,很多书上都讲了。
但是,最近真正要用PID算法的时候,发现书上的代码在我们51单片机上来实现还不是那么容易的事情。
简单的说来,就是不能直接调用。
仔细分析你可以发现,教材上的、网上现行的PID实现的C语言代码几乎都是用浮点型的数据来做的,可以想象,如果我们的计算使用浮点数据,那我们的51单片机来运行的话会有多痛苦。
所以,本人自己琢磨着弄了一个整型变量来实现了PID算法,由于是用整型数来做的,所以也不是很精确,但是对于很多的使用场合,这个精度也够了。
关于系数和采样电压全部是放大10倍处理的。
所以精度不是很高,但是也不是那么低,大部分的场合都够用了。
实在觉得精度不够,可以再放大10倍或者100倍处理,但是要注意不超出整个数据类型的范围就可以了。
以下是具体的程序代码:typedef struct PIDValue{uint32 Ek_Uint32[3]; //差值保存,给定和反馈的差值uint8 EkFlag_Uint8[3]; //符号,1则对应的Ek[i]为负数,0为对应的Ek[i]为正数uint8 KP_Uint8;uint8 KI_Uint8;uint8 KD_Uint8;uint8 B_Uint8; //死区电压uint8 KP; //显示修改的时候用uint8 KI;uint8 KD;uint8 B;uint16 Uk_Uint16; //上一时刻的控制电压}PIDValueStr;PIDValueStr xdata PID;//PID = Uk + (KP*E(k) - KI*E(k-1) + KD*E(k-2));void PIDProcess(void){uint32 idata Temp[3]; //uint32 idata PostSum; //正数和uint32 idata NegSum; //负数和Temp[0] = 0;Temp[1] = 0;Temp[2] = 0;PostSum = 0;NegSum = 0;if( ADPool.Value_Uint16[UINADCH] > ADPool.Value_Uint16[UFADCH] )//给定大于反{Temp[0] = ADPool.Value_Uint16[UINADCH] - ADPool.Value_Uint16[UFADCH];//计算Ek[0]if( Temp[0] > PID.B_Uint8 ){//数值移位PID.Ek_Uint32[2] = PID.Ek_Uint32[1];PID.Ek_Uint32[1] = PID.Ek_Uint32[0];PID.Ek_Uint32[0] = Temp[0];//符号移位PID.EkFlag_Uint8[2] = PID.EkFlag_Uint8[1];PID.EkFlag_Uint8[1] = PID.EkFlag_Uint8[0];PID.EkFlag_Uint8[0] = 0; //当前EK为正数Temp[0] = (uint32)PID.KP_Uint8 * PID.Ek_Uint32[0]; // KP*EK0Temp[1] = (uint32)PID.KI_Uint8 * PID.Ek_Uint32[1]; // KI*EK1Temp[2] = (uint32)PID.KD_Uint8 * PID.Ek_Uint32[2]; // KD*EK2}}else //反馈大于给定{Temp[0] = ADPool.Value_Uint16[UFADCH] - ADPool.Value_Uint16[UINADCH]; //计算Ek[0]if( Temp[0] > PID.B_Uint8 ){//数值移位PID.Ek_Uint32[2] = PID.Ek_Uint32[1];PID.Ek_Uint32[1] = PID.Ek_Uint32[0];PID.Ek_Uint32[0] = Temp[0];//符号移位PID.EkFlag_Uint8[2] = PID.EkFlag_Uint8[1];PID.EkFlag_Uint8[1] = PID.EkFlag_Uint8[0];PID.EkFlag_Uint8[0] = 1; //当前EK为负数Temp[0] = (uint32)PID.KP_Uint8 * PID.Ek_Uint32[0]; // KP*EK0Temp[1] = (uint32)PID.KI_Uint8 * PID.Ek_Uint32[1]; // KI*EK1Temp[2] = (uint32)PID.KD_Uint8 * PID.Ek_Uint32[2]; // KD*EK2}}/*以下部分代码是讲所有的正数项叠加,负数项叠加*/if(PID.EkFlag_Uint8[0]==0){PostSum += Temp[0]; //正数和}else{NegSum += Temp[0]; //负数和} // KP*EK0if(PID.EkFlag_Uint8[1]!=0){PostSum += Temp[1]; //正数和}else{NegSum += Temp[1]; //负数和} // - kI * EK1if(PID.EkFlag_Uint8[2]==0){PostSum += Temp[2]; //正数和}else{NegSum += Temp[2]; //负数和} // KD * EK2PostSum += (uint32)_Uint16; //if( PostSum > NegSum ) // 是否控制量为正数{Temp[0] = PostSum - NegSum;if( Temp[0] < (uint32)ADPool.Value_Uint16[UMAXADCH] )//小于限幅值则为计算值输出 {_Uint16 = (uint16)Temp[0];}else{_Uint16 = ADPool.Value_Uint16[UMAXADCH]; //否则为限幅值输出}}else //控制量输出为负数,则输出0{_Uint16 = 0;}}=============================================================================== //总体调节=比例系数×压力误差+积分系数×积分误差+微分系数×(本次误差-前次误差)//P就是比例,就是输入偏差乘以一个系数;//I就是积分,就是对输入偏差进行积分运算;//D就是微分,对输入偏差进行微分运算;PIDValueStr xdata PID;void PIDCalc(unsigned int idata data1,unsigned int idata data2,unsigned int idata minfreq){unsigned int idata svdata;unsigned int idata pvdata;unsigned long idata dError,Error;unsigned long idata ResultP,ResultI,ResultD,PIDout,Result;svdata=data1;pvdata=data2;if(svdata>pvdata){Error=svdata-pvdata;// 压力偏差PID.SumError+=Error;// 积分dError=PID.LError-PID.PError;// 当前微分PID.PError=PID.LError;PID.LError=Error;ResultP=PID.KP*Error*100;// 比例项ResultI=PID.KI*(PID.SumError);// 积分项ResultD=PID.KD*dError;// 微分项PIDout=ResultP+ResultI+ResultD;Result+=PIDout;if(PIDout>=5000){PIDout=5000;PID.SumError-=Error;}else{ PIDout=ResultP+ResultI+ResultD;}}if(svdata<pvdata){Error=svdata-pvdata;// 压力偏差PID.SumError+=Error;// 积分dError=PID.LError-PID.PError;// 当前微分PID.PError=PID.LError;PID.LError=Error;ResultP=PID.KP*Error*100;//比例项ResultI=PID.KI*(PID.SumError);// 积分项ResultD=PID.KD*dError;// 微分项PIDout=ResultP+ResultI+ResultD;Result+=PIDout;if (PIDout>=5000){PIDout=0;PID.SumError-=Error;}else{ PIDout=ResultP+ResultI+ResultD;}}if (PIDout<minfreq){PIDout=0;}=PIDout; }。
温度控制的增量式pid算法温度控制是工业生产中非常重要的一项技术,它可以保证生产过程中的温度稳定,从而保证产品的质量。
而PID算法是一种常用的控制算法,它可以根据当前的误差来调整控制器的输出,从而实现对温度的精确控制。
在本文中,我们将介绍一种基于增量式PID算法的温度控制方法。
增量式PID算法是一种常用的控制算法,它可以根据当前的误差和误差变化率来计算控制器的输出。
具体来说,增量式PID算法可以分为三个部分:比例控制、积分控制和微分控制。
比例控制是根据当前误差来计算控制器的输出,积分控制是根据误差的积分来计算控制器的输出,微分控制是根据误差的变化率来计算控制器的输出。
这三个部分的输出可以相加得到最终的控制器输出。
在温度控制中,我们可以将温度传感器的输出作为反馈信号,将设定温度作为目标信号,然后使用增量式PID算法来计算控制器的输出。
具体来说,我们可以将当前温度与设定温度的差值作为误差,将当前温度与上一次温度的差值作为误差变化率,然后使用增量式PID算法来计算控制器的输出。
控制器的输出可以通过控制加热器或冷却器的功率来实现对温度的控制。
需要注意的是,增量式PID算法需要对控制器的输出进行积分和微分,这可能会导致控制器的输出出现过冲或震荡的情况。
为了避免这种情况的发生,我们可以使用一些技巧来优化控制器的输出。
例如,我们可以使用限幅器来限制控制器的输出范围,或者使用滤波器来平滑控制器的输出。
增量式PID算法是一种非常有效的温度控制方法,它可以根据当前的误差和误差变化率来计算控制器的输出,从而实现对温度的精确控制。
在实际应用中,我们需要根据具体的情况来选择合适的控制参数,并使用一些技巧来优化控制器的输出,从而实现更加稳定和精确的温度控制。
编码器输出的A向脉冲接到单片机的外部中断INTO, B向脉冲接到I/O端口P1.0。
当系统工作时,首先要把INTO设置成下降沿触发,并开相应中断。
当有有效脉冲触发中断时,进行中断处理程序,判别B脉冲是高电平还是低电平,若是高电平则编码器正转,加1计数;若是低电平则编码器反转,减1计数。
基于51单片机的直流电机PID闭环调速系统原理详解与程序(2013-08-04 01:18:15)转载▼标签:分类:单片机51单片机直流电机pidpcf8591基于51单片机的直流电机PID闭环调速系统1. 电机转速反馈:原理:利用光电编码器作为转速的反馈元件,设电机转一周光电编码器发送N个PWM波形,利用测周法测量电机转速。
具体实现:将定时器0设置在计数模式,用来统计一定的时间T内接受到的脉冲个数M个,而定时器0置在计时模式,用来计时T时间。
则如果T时间接受到M 个PWM波形,而电机转一圈发出N个PWM波形,则根据测周法原理,电机的实际的转速为:real_speed=M/ ( N*T),单位转/秒。
若将定时器1置在计数模式,则PWM波形应该由P3A3脚输入。
代码实现://定时器0初始化,用来定时10msvoid Init_Timer0(void){TMOD |= 0x01; // 使用模式 1,16位定时器 ,且工作在计时模式TH0=(65536-10000)/256; // 定时 10msTL0=(65536-10000)%6;//计数器1初始化,用来统计定时器1计时250ms 内PWM 波形个数 voidInit_Timer1(void){ TMOD |= 0x50; // 使用计数模式 1, 16位计数器模式TH1=0x00; // 给定初值,由 0往上计数TL1=0x00;EA=1; // 总中断打开ET1=1; // 定时器中断打开TR1=1; }// 定时器开关打开// 定时器0的中断服务子函数, 主要完成脉冲个数的读取, 实际转速的计算和 控制以及控制结// 果输出等工作void Timer0_isr(void) interrupt 1 { unsigned char count;TH0=(65536-10000)/256; // 重新赋值 10msTL0=(65536-10000)%6;count++;if (count==25)// 如果达到250ms,则计算一次转速并进行一次控制运算{ EA=1; // ET0=1; // TR0=1; // }总中断打开定时器中断打开定时器开关打开PIDcount=0;// 清零以便于定时下一个250msTR1=0;// 关闭定时器1,统计脉冲个数real_speed=(256*TH1+TL1)*4/N;//250ms 内脉冲个数并由此计算转速TH1=0x00; // 计数器1清零,重新开始计数TL1=0x00;TR1=1;OUT=contr_PID();// 进入PID 控制 , PID 控制子函数代码在后面给出write_add(0x40,OUT);〃进行DA转换,将数字量转换为模拟量,后面会介绍到}}2. PID 控制:PID 的基本原理在这里不作具体讲解,这里主要给出PID 算法的实现,通过调节结构体中比例常数( Proportion )、积分常数( Integral )、微分常数 ( Derivative )使得转速控制达到想要的精度。
pid 算法原理及c51应用
PID(Proportional-Integral-Derivative)是一种经典的控制算法,它结合了比例、积分和微分三种控制方式,用于控制系统的稳定性和精度。
PID控制器根据系统的当前状态和期望状态之间的偏差来调整输出,以使系统的响应更快速、更稳定。
PID控制器的工作原理如下:
1. 比例(P)控制,根据偏差的大小来调整输出,偏差越大,输出调节量越大。
这种控制方式能够快速地减小偏差,但可能会导致系统的超调和震荡。
2. 积分(I)控制,根据偏差的累积量来调整输出,用于消除系统的静态误差,提高系统的稳定性和精度。
3. 微分(D)控制,根据偏差的变化率来调整输出,用于抑制系统的振荡和减小超调。
在C51单片机上应用PID算法,首先需要将PID控制器的数学模型转化为C语言代码。
通常,可以使用定时器中断来周期性地计
算PID控制器的输出,并通过数字输出口来控制被控对象。
在C51单片机上实现PID算法需要考虑计算精度、定时器中断的设置、输出口的控制等方面。
在实际应用中,PID控制器可以用于温度控制、速度控制、位置控制等各种控制系统中。
通过调节PID参数,可以使系统快速、稳定地达到期望状态,并且对于不同的被控对象,可以根据实际情况调整PID参数以获得最佳的控制效果。
总之,PID算法结合了比例、积分和微分三种控制方式,通过调节输出来使系统稳定并快速响应。
在C51单片机上应用PID算法需要将其数学模型转化为C语言代码,并考虑各种实际应用中的因素。
51单片机PID算法程序(一)PID算法(原创文章,转载请注明出处/tengjingshu) 比例,积分,微分的线性组合,构成控制量u(t),称为:比例(Proportional)、积分(Integrating)、微分(Differentiation)控制,简称PID控制图1控制器公式在实际应用中,可以根据受控对象的特性和控制的性能要求,灵活地采用不同的控制组合,构成比例(P)控制器比例+积分(PI)控制器比例+积分+微分(PID)控制器式中或式中控制系统中的应用在单回路控制系统中,由于扰动作用使被控参数偏离给定值,从而产生偏差。
自动控制系统的调节单元将来自变送器的测量值与给定值相比较后产生的偏差进行比例、积分、微分(PID)运算,并输出统一标准信号,去控制执行机构的动作,以实现对温度、压力、流量、也为及其他工艺参数的自动控制。
比例作用P只与偏差成正比;积分作用I是偏差对时间的积累;微分作用D 是偏差的变化率;比例(P)控制比例控制能迅速反应误差,从而减少稳态误差。
除了系统控制输入为0和系统过程值等于期望值这两种情况,比例控制都能给出稳态误差。
当期望值有一个变化时,系统过程值将产生一个稳态误差。
但是,比例控制不能消除稳态误差。
比例放大系数的加大,会引起系统的不稳定。
图2比例(P)控制阶跃响应积分(I)控制在积分控制中,控制器的输出与输入误差信号的积分成正比关系。
为了减小稳态误差,在控制器中加入积分项,积分项对误差取决于时间的积分,随着时间的增加,积分项会增大。
这样,即使误差很小,积分项也会随着时间的增加而加大,它推动控制器的输出增大使稳态误差进一步减少,直到等于零。
积分(I)和比例(P)通常一起使用,称为比例+积分(PI)控制器,可以使系统在进入稳态后无稳态误差。
如果单独用积分(I)的话,由于积分输出随时间积累而逐渐增大,故调节动作缓慢,这样会造成调节不及时,使系统稳定裕度下降。
图3积分(I)控制和比例积分(PI)控制阶跃相应微分(D)控制在微分控制中,控制器的输出与输入误差信号的微分(即误差的变化率)成正比关系。
51单片机PID算法程序(三)增量式PID控制算法前言在之前的两篇文章中,我们分别介绍了基础PID算法和位置式PID控制算法。
在本文中,我们将介绍另一种常见的PID算法——增量式PID控制算法,以及如何在51单片机上实现增量式PID控制算法。
增量式PID控制算法简介增量式PID控制算法与位置式PID控制算法最大的区别在于输出控制量的计算方式不同。
位置式PID算法的输出控制量是与目标值的误差和历史误差之和的积分和误差的比例和微分,而增量式PID算法的输出控制量只与误差和历史误差的差值有关。
在增量式PID控制算法中,输出控制量的计算方式如下:$$ OutPut=K_p \\cdot Err+K_i \\cdot \\Delta Err+K_d \\cdot \\Delta^2 Err $$ 其中,K p、K i和K d分别是比例、积分和微分系数。
增量式PID控制算法的优点在于可以避免积分饱和、能够快速响应控制量变化,因此在某些要求高响应速度的应用中,常选择使用增量式PID控制算法。
51单片机上的增量式PID控制算法相比较于位置式PID控制算法,增量式PID控制算法的实现更加复杂,需要考虑历史误差的存储、误差的差值计算等问题。
因此,在51单片机上实现增量式PID控制算法需要一些特殊的处理方式。
我们可以通过以下三个步骤来实现增量式PID控制算法:步骤一:初始化变量在增量式PID控制算法中,需要定义一些变量,如上一次的误差值和输出控制量等。
因此,在使用增量式PID控制算法之前,需要先初始化这些变量。
//定义变量double set_point=0; //目标值double process_pv=0; //实际值double Kp=1,Ki=1,Kd=1; //PID参数double last_error=0,prev_error=0; //历史误差double output=0, dInput=0; //输出控制量和误差的差值double output_max=100.0,output_min=-100.0; //控制量范围//初始化变量void PID_Init(){last_error = 0;prev_error = 0;dInput = 0;output = 0;}步骤二:控制量计算根据增量式PID控制算法的公式,我们可以计算控制量的值。
51单片机PID的算法实现程序用整型变量来实现PID算法,由于是用整型数来做的,所以也不是很精确,但是对于很多的使用场合,这个精度也够了,关于系数和采样电压全部是放大10倍处理的.所以精度不是很高. 但是也不是那么低,大部分的场合都够了. 实在觉得精度不够, 可以再放大10倍或者100倍处理,但是要注意不超出整个数据类型的范围就可以了.本程序包括PID计算和输出两部分.当偏差>10度全速加热,偏差在10度以内为PID计算输出. 具体的参考代码参见下面:*///================================================================// pid.H// Operation about PID algorithm procedure// C51编译器Keil 7.08//================================================================// 作者:zhoufeng// Date :2007-08-06// All rights reserved.//================================================================#include <reg52.h>#include <intrins.h>typedef unsigned char uint8;typedef unsigned int uint16;typedef unsigned long int uint32;/**********函数声明************/void PIDOutput ();void PIDOperation ();/*****************************/typedef struct PIDValue{uint32 Ek_Uint32[3]; //差值保存,给定和反馈的差值uint8 EkFlag_Uint8[3]; //符号,1则对应的为负数,0为对应的为正数uint8 KP_Uint8;uint8 KI_Uint8;uint8 KD_Uint8;uint16 Uk_Uint16; //上一时刻的控制电压uint16 RK_Uint16; //设定值uint16 CK_Uint16; //实际值}PIDValueStr;PIDValueStr PID;uint8 out ; // 加热输出uint8 count; // 输出时间单位计数器/*********************************PID = Uk + KP*[E(k)-E(k-1)]+KI*E(k)+KD*[E(k)-2E(k-1)+E(k-2)];(增量型PID算式)函数入口: RK(设定值),CK(实际值),KP,KI,KD函数出口: U(K)//PID运算函数********************************/void PIDOperation (void){uint32 Temp[3]; //中间临时变量uint32 PostSum; //正数和uint32 NegSum; //负数和Temp[0] = 0;Temp[1] = 0;Temp[2] = 0;PostSum = 0;NegSum = 0;if( PID.RK_Uint16 > PID.RK_Uint16 ) //设定值大于实际值否?{if( PID.RK_Uint16 - PID.RK_Uint16 >10 ) //偏差大于10否?{_Uint16 = 100; } //偏差大于10为上限幅值输出(全速加热) else{Temp[0] = PID.RK_Uint16 - PID.CK_Uint16; //偏差<=10,计算E(k)PID.EkFlag_Uint8[1]=0; //E(k)为正数//数值移位PID.Ek_Uint32[2] = PID.Ek_Uint32[1];PID.Ek_Uint32[1] = PID.Ek_Uint32[0];PID.Ek_Uint32[0] = Temp[0];/****************************************/if( PID.Ek_Uint32[0] >PID.Ek_Uint32[1] ) //E(k)>E(k-1)否?{Temp[0]=PID.Ek_Uint32[0] - PID.Ek_Uint32[1]; //E(k)>E(k-1)PID.EkFlag_Uint8[0]=0; } //E(k)-E(k-1)为正数else{Temp[0]=PID.Ek_Uint32[0] - PID.Ek_Uint32[1]; //E(k)<E(k-1)PID.EkFlag_Uint8[0]=1; } //E(k)-E(k-1)为负数/****************************************/Temp[2]=PID.Ek_Uint32[1]*2 ; // 2E(k-1)if( (PID.Ek_Uint32[0]+ PID.Ek_Uint32[2])>Temp[2] ) //E(k-2)+E(k)>2E(k-1)否?{Temp[2]=(PID.Ek_Uint32[0]+PID.Ek_Uint32[2])-Temp[2]; //E(k-2)+E(k)>2E(k-1) PID.EkFlag_Uint8[2]=0; } //E(k-2)+E(k)-2E(k-1)为正数else{Temp[2]=Temp[2]-(PID.Ek_Uint32[0]+ PID.Ek_Uint32[2]); //E(k-2)+E(k)<2E(k-1)PID.EkFlag_Uint8[2]=1; } //E(k-2)+E(k)-2E(k-1)为负数/****************************************/Temp[0] = (uint32)PID.KP_Uint8 * Temp[0]; // KP*[E(k)-E(k-1)]Temp[1] = (uint32)PID.KI_Uint8 * PID.Ek_Uint32[0]; // KI*E(k)Temp[2] = (uint32)PID.KD_Uint8 * Temp[2]; // KD*[E(k-2)+E(k)-2E(k-1)]/*以下部分代码是讲所有的正数项叠加,负数项叠加*//**********KP*[E(k)-E(k-1)]**********/if(PID.EkFlag_Uint8[0]==0)PostSum += Temp[0]; //正数和elseNegSum += Temp[0]; //负数和/********* KI*E(k)****************/if(PID.EkFlag_Uint8[1]==0)PostSum += Temp[1]; //正数和else; //空操作,E(K)>0/****KD*[E(k-2)+E(k)-2E(k-1)]****/if(PID.EkFlag_Uint8[2]==0)PostSum += Temp[2]; //正数和elseNegSum += Temp[2]; //负数和/***************U(K)***************/PostSum += (uint32)_Uint16;if(PostSum > NegSum ) // 是否控制量为正数{ Temp[0] = PostSum - NegSum;if( Temp[0] < 100 ) //小于上限幅值则为计算值输出_Uint16 = (uint16)Temp[0];else_Uint16 = 100; //否则为上限幅值输出}else //控制量输出为负数,则输出0(下限幅值输出)_Uint16 = 0;}}else{ _Uint16 = 0; }}*********************************函数入口: U(K)函数出口: out(加热输出)//PID运算植输出函数********************************/void PIDOutput (void){static int i;i=_Uint16;if(i==0)out=1;else out=0;if((count++)==5)//如定时中断为40MS,40MS*5=0.2S(输出时间单位),加热周期20S(100等份) { //每20S PID运算一次count=0;i--;}}。
增量式PID公式的理解增量式PID控制是一种基于比例、积分和微分算法的控制方法,用于控制系统中的物理量,以使其达到预期的目标值。
相对于传统的位置式PID控制方法,增量式PID控制方法可以减少参数调整的工作量,并且对于模型复杂、非线性系统的控制更为有效。
传统的位置式PID控制器的计算公式为:u(t) = Kp * e(t) + Ki * ∫[0,t] e(τ) dτ + Kd * de(t)/dt其中,u(t)为控制器输出,e(t)为目标值与实际值之间的误差,Kp、Ki、Kd为分别为比例、积分和微分增益,τ为积分上限,de(t)/dt为误差的时间导数。
相比之下,增量式PID控制器的计算公式为:u(t)=u(t-1)+Kp*(e(t)-e(t-1))+Ki*e(t)+Kd*(e(t)-2*e(t-1)+e(t-2))公式中,u(t)为当前时刻的控制器输出,e(t)为当前时刻的误差,e(t-1)为上一时刻的误差,e(t-2)为上上一时刻的误差。
增量式PID控制器在计算当前的控制器输出时,只需要当前的误差和前两个时刻的误差信息,相对于位置式PID控制,减少了对历史数据的依赖。
1.减少了参数调整的工作量:增量式PID控制器仅依赖当前的误差和前两个时刻的误差,相对位置式PID控制器,简化了参数调整的过程。
这对于复杂的系统来说,减轻了人工调试的工作量,提高了系统的鲁棒性。
2.适用于模型复杂、非线性系统:增量式PID控制器在控制非线性系统时,具有更好的鲁棒性和稳定性。
尤其是对于存在延迟和滞后的系统,增量式PID控制器能够快速响应并调整控制器输出,减少超调和振荡。
3.具有较好的控制精度和稳定性:增量式PID控制器通过不断地调整控制器输出,使得误差逐渐趋于零,从而提高控制精度。
同时,增量式PID控制器能够及时地对系统的变化作出响应,从而保持系统的稳定性。
然而,增量式PID控制器也存在一些问题:1.对系统噪声敏感:增量式PID控制器在计算当前的控制器输出时,需要使用前两个时刻的误差信息。
增量式PID控制算法程序;T、TD、TI、KP依次从30H,33H,36H,39H开始。
;A,B,C的值依次存在BLOCK1,BLOCK2,BLOCK3的地址里; 这里R(k)给的是定值;ORG 0000HBLOCK1 EQU 43H ;A,B ,CBLOCK2 EQU 46HBLOCK3 EQU 49HUK EQU 4CH ;存结果UKRK EQU 50HEK EQU 53H ;存放偏差值E(k)的始址EK1 EQU 56H ;存放E(k-1)的始址EK2 EQU 59H ;存放E(k-2)的始址CK EQU 5CH ;采样数据始址BUFF EQU 60H ;暂存区BUFF1 EQU 63HBUFF2 EQU 66HREC EQU 69HTEST:MOV RK,#01H ;常数Rk的BCD码浮点数MOV RK+1,#12H ;1.25MOV RK+2,#50HMOV 3CH,#01H ;常数1的BCD码浮点数MOV 3DH,#10HMOV 3EH,#00HMOV 40H,#01H ;常数2的BCD码浮点数MOV 41H,#20HMOV 42H,#00HMOV 30H,#01H ;T的BCD 码浮点数MOV 31H,#23H ;2.34MOV 32H,#40HMOV 33H,#01H ;Td的BCD码浮点数MOV 34H,#35H ;3.54MOV 35H,#40HMOV 36H,#01H ;Ti的BCD码浮点数MOV 37H,#11H ;1.12MOV 38H,#20HMOV 39H,#01H ;Kp的BCD码浮点数MOV 3AH,#12H ;1.25MOV 3BH,#50HMOV R0,#RK ;指向BCD码浮点操作数LCALL BTOF ;将其转换成二进制浮点操作数MOV R0,#3CHLCALL BTOFMOV R0,#40HLCALL BTOFMOV R0,#39HLCALL BTOFMOV R0,#36H ;指向BCD码浮点操作数Ti LCALL BTOF ;将其转换成二进制浮点操作数MOV R0,#33H ;指向BCD码浮点操作数Td LCALL BTOF ;将其转换成二进制浮点操作数MOV R0,#30H ;指向BCD码浮点操作数T LCALL BTOF ;将其转换成二进制浮点操作数MOV R1, #BUFF1 ;保存30H中的值即T值LCALL FMOVR0MOV R1, #36H ;计算A值(1+T/Ti+Td/T).Kp LCALL FDIVMOV R1,#3CH ;常数1LCALL FADDMOV R0,#33H ;保存33H中的值MOV R1,#BUFFLCALL FMOVR0MOV R1,#BUFF1LCALL FDIVMOV R1,#30H ;30H里存的是T/Ti+1LCALL FADDMOV R1,#39HLCALL FMULMOV R1 ,#BLOCK1 ;将结果保存在BLOCK1中LCALL FMOVR0MOV R1,#BUFF1 ;30H恢复原值MOV R0,#30HLCALL FMOVMOV R1,#BUFF ;33H恢复原值MOV R0,#33HLCALL FMOVMOV R0,#40H ;计算B的值Kp.(1+2.Td/T) MOV R1,#33HLCALL FMULMOV R1,#30HLCALL FDIVLCALL FADDMOV R1,#39HLCALL FMULMOV R1,#BLOCK2 ;保存B值到BLOCK2中LCALL FMOVR0MOV R0,#39H ;计算C的值Kp.Td/TMOV R1,#33HLCALL FMULMOV R1,#30HLCALL FDIVMOV R1,#BLOCK3 ;保存C值到BLOCK3中LCALL FMOVR0MOV R0,#EK1 ;将EK1,EK2设初值0LCALL FCLRMOV R0,#EK2LCALL FCLRMOV REC,#03H ;设置采样次数LOOP: MOV CK,#7eH ;采样数据暂时给了一个定值MOV CK+1,#21H ;0.002112MOV CK+2,#12HMOV R0,#CKLCALL BTOFMOV R0,#RK ;保存R(k)中的值MOV R1,#BUFFLCALL FMOVR0MOV R1,#CKLCALL FSUB ;计算R(k)-C(k)的值送给E(k)MOV R1,#EKLCALL FMOVR0MOV R1,#BUFF ;恢复RK的值释放BUFFMOV R0,#RKLCALL FMOVMOV R0,#BLOCK2 ;将B.e(k-1)的值暂存在BUFF1中MOV R1,#BUFF ;保存BLCALL FMOVR0MOV R1,#EK1LCALL FMULMOV R1,#BUFF1LCALL FMOVR0MOV R1,#BUFF ;恢复B释放BUFFLCALL FMOVMOV R0,#BLOCK3 ;将C.e(K-2)的值暂存在BUFF2中MOV R1,#BUFF ;保存CMOV R1,#EK2LCALL FMULMOV R1,#BUFF2LCALL FMOVR0MOV R1,#BUFF ;恢复C释放BUFFLCALL FMOVMOV R0,#BLOCK1 ;A.E(k)MOV R1,#BUFFLCALL FMOVR0MOV R1,#EKLCALL FMULMOV R1,#BUFF1 ;计算Uk值A.E(k)-B.E(k-1)+C.E(k-2) LCALL FSUBMOV R1,#BUFF2LCALL FADDMOV R1,#UK ;保存结果到UK中LCALL FMOVR0MOV R1,#BUFF ;恢复A 释放BUFFLCALL FMOVMOV R0,#UK ;UK转换成BCD码浮点数输出LCALL FTOBMOV R1,#EK1 ;将E(k-1)-->E(k-2),E(k)-->E(k-1)MOV R0,#EK2LCALL FMOVMOV R1,#EKMOV R0,#EK1LCALL FMOVLCALL DELAY ;等待采样时刻DJNZ REC,NEXT1SJMP $NEXT1: LJMP LOOPDELAY: MOV R7,#02HDELAY1: MOV R6,#0FFHDELAY2: DJNZ R6,DELAY2DJNZ R7,DELAY1RET; (1)标号:FSDT功能:浮点数格式化;入口条件:待格式化浮点操作数在[R0]中。
51单片机PID算法程序(三)增量式PID控制算法当执行机构需要的不是控制量的绝对值,而是控制量的增量(例如去驱动步进电动机)时,需要用PID 的“增量算法”。
增量式PID控制算法可以通过(2-4)式推导出。
由(2-4)可以得到控制器的第k-1个采样时刻的输出值为:(2-5)将(2-4)与(2-5)相减并整理,就可以得到增量式PID控制算法公式为:(2-6)其中由(2-6)可以看出,如果计算机控制系统采用恒定的采样周期T,一旦确定A、B、C,只要使用前后三次测量的偏差值,就可以由(2-6)求出控制量。
增量式PID控制算法与位置式PID算法(2-4)相比,计算量小得多,因此在实际中得到广泛的应用。
位置式PID控制算法也可以通过增量式控制算法推出递推计算公式:(2-7)(2-7)就是目前在计算机控制中广泛应用的数字递推PID控制算法。
增量式PID控制算法C51程序/*==================== =====================================================PID FunctionThe PID (比例、积分、微分) function is used in mainlycontrol applications. PIDCalc performs one iteration of the PIDalgorithm.While the PID function works, main is just a dummy program showinga typical usage.==========================================================================*/typedef struct PID{int SetPoint; //设定目标 Desired Valuelong SumError; //误差累计double Proportion; //比例常数 Proportional Constdouble Integral; //积分常数 Integral Constdouble Derivative; //微分常数 Derivative Constint LastError; //Error[-1]int PrevError; //Error[-2]} PID;static PID sPID;static PID *sptr = &sPID;/*================================================================================ Initialize PID Structure PID参数初始化===============================================================================*/ void IncPIDInit(void){sptr->SumError = 0;sptr->LastError = 0; //Error[-1]sptr->PrevError = 0; //Error[-2]sptr->Proportion = 0; //比例常数 Proportional Constsptr->Integral = 0; //积分常数Integral Constsptr->Derivative = 0; //微分常数 Derivative Constsptr->SetPoint = 0;}/*=============================================================================== 增量式PID计算部分=================================================================================*/ int IncPIDCalc(int NextPoint){register int iError, iIncpid; //当前误差iError = sptr->SetPoint - NextPoint;//增量计算iIncpid = sptr->Proportion * iError //E[k]项- sptr->Integral * sptr->LastError //E[k-1]项+ sptr->Derivative * sptr->PrevError; //E[k-2]项//存储误差,用于下次计算sptr->PrevError = sptr->LastError;sptr->LastError = iError;//返回增量值return(iIncpid);}。
单片机pid算法程序
PID控制算法是一种常用的控制算法,适用于各种控制系统的设
计中。
下面是基于单片机的PID算法程序:
1. 初始化参数
在程序开始时,需要先对PID控制算法的三个参数——比例、积
分和微分系数进行初始化,一般设置为:Kp=1.2、Ki=1.0、Kd=0.001,然后将误差值、上次误差值和累积误差值都设置为0。
2. 计算PID输出值
在每个控制周期内,先读取被控制的变量的实际值和期望值,计
算出两者之间的误差值err。
然后按照PID控制算法公式,分别计算出比例、积分和微分三个修正量的值,最后将它们相加,得到PID输出值。
3. 更新参数
PID控制算法是一种自适应算法,需要不断地根据实际情况来更
新算法参数。
如果当前的误差值较大,说明控制效果不佳,应当增加
比例系数Kp和微分系数Kd,以提高控制效果。
否则,应当增加积分系数Ki,以提高稳定性。
4. 输出控制信号
最后,将PID输出值转换成相应的控制信号,输出给执行机构,
实现对被控制系统的控制。
以上就是单片机PID算法程序的基本步骤,可以根据实际需求进
行适当的优化和改进。
单片机PID的算法程序用整型变量来实现PID算法,由于是用整型数来做的,所以也不是很精确,但是对于很多的使用场合,这个精度也够了,关于系数和采样电压全部是放大10倍处理的.所以精度不是很高. 但是也不是那么低,大部分的场合都够了. 实在觉得精度不够, 可以再放大10倍或者100倍处理,但是要注意不超出整个数据类型的范围就可以了.本程序包括PID计算和输出两部分.当偏差>;10度全速加热,偏差在10度以内为PID计算输出. 具体的参考代码参见下面:*///=============================================== =================// pid.H// Operation about PID algorithm procedure// C51编译器 Keil 7.08//=============================================== =================// 作者:zhoufeng// Date :2007-08-06// All rights reserved.//================================================================#include#includetypedef unsigned char uint8;typedef unsigned int uint16;typedef unsigned long int uint32;void PIDOutput ();void PIDOperation ();typedef struct PIDValue{uint32 Ek_Uint32[3]; //差值保存,给定和反馈的差值uint8 EkFlag_Uint8[3]; //符号,1则对应的为负数,0为对应的为正数uint8 KP_Uint8;uint8 KI_Uint8;uint8 KD_Uint8;uint16 Uk_Uint16; //上一时刻的控制电压uint16 RK_Uint16; //设定值uint16 CK_Uint16; //实际值}PIDValueStr;PIDValueStr PID;uint8 out ; // 加热输出uint8 count; // 输出时间单位计数器void PIDOperation (void){uint32 Temp[3]; //中间临时变量uint32 PostSum; //正数和uint32 NegSum; //负数和Temp[0] = 0;Temp[1] = 0;Temp[2] = 0;PostSum = 0;NegSum = 0;if( PID.RK_Uint16 >; PID.RK_Uint16 ) //设定值大于实际值否?{if( PID.RK_Uint16 - PID.RK_Uint16 >;10 ) //偏差大于10否?{_Uint16 = 100; } //偏差大于10为上限幅值输出(全速加热)else{Temp[0] = PID.RK_Uint16 - PID.CK_Uint16; //偏差;PID.Ek_Uint32[1] ) //E(k)>;E(k-1)否?{Temp[0]=PID.Ek_Uint32[0] - PID.Ek_Uint32[1];//E(k)>;E(k-1)PID.EkFlag_Uint8[0]=0; } //E(k)-E(k-1)为正数else{Temp[0]=PID.Ek_Uint32[0] - PID.Ek_Uint32[1];//E(k)PID.EkFlag_Uint8[0]=1; } //E(k)-E(k-1)为负数Temp[2]=PID.Ek_Uint32[1]*2 ; // 2E(k-1)if( (PID.Ek_Uint32[0]+ PID.Ek_Uint32[2])>;Temp[2] ) //E(k-2)+E(k)>;2E(k-1)否?{Temp[2]=(PID.Ek_Uint32[0]+PID.Ek_Uint32[2])-Temp[2];//E(k-2)+E(k)>;2E(k-1)PID.EkFlag_Uint8[2]=0; }//E(k-2)+E(k)-2E(k-1)为正数else{Temp[2]=Temp[2]-(PID.Ek_Uint32[0]+PID.Ek_Uint32[2]); //E(k-2)+E(k);0if(PID.EkFlag_Uint8[2]==0)PostSum += Temp[2]; //正数和elseNegSum += Temp[2]; //负数和PostSum += (uint32)_Uint16;if(PostSum >; NegSum ) // 是否控制量为正数{ Temp[0] = PostSum - NegSum;if( Temp[0] < 100 ) //小于上限幅值则为计算值输出_Uint16 = (uint16)Temp[0];else_Uint16 = 100; //否则为上限幅值输出}else //控制量输出为负数,则输出0(下限幅值输出) _Uint16 = 0;}}else{ _Uint16 = 0; }}void PIDOutput (void){static int i;i=_Uint16;if(i==0)out=1;else out=0;if((count++)==5)//如定时中断为40MS,40MS*5=0.2S(输出时间单位),加热周期20S(100等份){ //每20S PID运算一次count=0;i--;}}。