单片机PID的算法程序

发布者:数字舞者最新更新时间:2015-01-14 来源: 51hei关键字:单片机  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
#include
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;               // 输出时间单位计数器
 
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否?
  {
   PID.Uk_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)
        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)]
 
    
 
if(PID.EkFlag_Uint8[0]==0)
  PostSum += Temp[0];                                    //正数和
else                                             
  NegSum += Temp[0];                                    //负数和
 
if(PID.EkFlag_Uint8[1]==0)     
  PostSum += Temp[1];                                 //正数和
else
   ;                                                 //空操作,E(K)>0
                          
if(PID.EkFlag_Uint8[2]==0)
PostSum += Temp[2];                               //正数和
else
  NegSum += Temp[2];                             //负数和
                            
PostSum += (uint32)PID.Uk_Uint16;   
       
if(PostSum > NegSum )                         // 是否控制量为正数
{ Temp[0] = PostSum - NegSum;
if( Temp[0] < 100 )                         //小于上限幅值则为计算值输出
PID.Uk_Uint16 = (uint16)Temp[0];
else
  PID.Uk_Uint16 = 100;                     //否则为上限幅值输出
}
else                                     //控制量输出为负数,则输出0(下限幅值输出)
   PID.Uk_Uint16 = 0;
}
}
else
{ PID.Uk_Uint16 = 0;  }
 
}
 
 
void     PIDOutput (void) 
{
static  int i;
i=PID.Uk_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的算法程序

上一篇:教你自制12V 呼吸灯,附电路图,制作过程
下一篇:MSP430中定义大数组存在的问题及解决方案

推荐阅读最新更新时间:2024-03-16 13:50

基于微控制器的倒计时算法与实现
1 引 言   这里的倒计时就是计算出从当前时间点需要经过多长时间才能到达目标时间点。从另一个角度讲, 就是计算出两个时间点之间的时间差。   目前, 倒计时系统正得到越来越广泛的应用。   在体育比赛、公交系统乃至铁路系统中出现了很多倒计时的时间显示。就在前不久, 关于上海世博会的倒计时正式启动, 其精度精确到天。   在类似的应用中, 大多数情况下, 倒计时功能(包括显示功能)是由微控制器实现的。微控制器不同于桌面电脑或笔记本电脑, 其系统资源非常有限, 也不能安装复杂的操作系统, 没有现成的倒计时系统可以应用。下面将讨论适合在微控制器中运行的倒计时算法。   2 倒计时算法的两种常用思路   关于倒计时的计算主要有两
[工业控制]
基于<font color='red'>微控制器</font>的倒计时<font color='red'>算法</font>与实现
单片机固件的"驱动分离"式设计思想
今天跟大家找了一种常见的应用与驱动分离设计的方式,对于目前一些高性能MCU还是值得使用一下的,不过对于原本主频不够高、性能不太强的MCU不建议使用,毕竟这样的设计还是牺牲了一定的性能。 在正规的项目开发中,项目往往是并行开发的,也就是说硬件设计、底层软件设计、应用软件设计等是同步进行的。比如说在开发板上调试模块驱动,在其他平台上调试应用程序再移植到目前这个平台等。 1、为何不见嵌入式软件架构师职位? 在招聘网站搜索架构师,会出现各种系统架构师:web架构师,后台服务端架构师等等,但是唯独很难看到嵌入式软件架构师。嵌入式软件不需要架构吗,驱动不需要架构吗? 答案当然是需要,不过为什么没有这方面的职位? 一般的人会说,小项目才
[单片机]
<font color='red'>单片机</font>固件的
基于单片机设计的交流数字电压表
传统的电压表在测量电压时需要手动切换量程,不仅不方便,而且要求不能超过该量程。如果在测量时忘记改变量程,则会出现很大的测量误差,甚至有将电压表烧坏的可能。 本文中采用运算放大器和集成多路模拟开关电路设计了电压表量程自动切换技术,通过单片机检测可实现电压表量程的自动转换。它具有体积小,驱动电流小,动作快,结构简单,操作方便的优点,可用于实验教学中。 1 技术要求 电压测量范围:0~500 V;测量精度:0.5%;量程自动切换;采用LED显示;可用现场提供的220 V交流电源。 2 基本原理 基本原理如图1所示,信号经过衰减处理后通过采样保持器采样保持,由A/D转换成数字信号,再由单片机控制和计算后将结果送LED显示
[单片机]
基于<font color='red'>单片机</font>设计的交流数字电压表
51单片机按键控制舵机
#include reg52.h #define Stop 0 //宏定义,停止 #define Left 1 //宏定义,左转 #define Right 2 //宏定义,右转 sbit ControlPort = P1^0; //舵机信号端口 sbit KeyLeft = P1^1; //左转按键端口 sbit KeyRight = P1^2; //右转按键端口 sbit KeyStop = P1^3; //归位按键端口 unsigned char TimeOutCounter = 0,LeftOrRight = 0; //TimeOutCounter:定时器溢出计数 LeftOrRigh
[单片机]
STC89系列单片机看门狗的使用及应用程序
“看门狗”概念及其应用在由单片机构成的系统中,由于单片机的工作有可能会受到来自外界电磁场的干扰,造成程序的跑飞,从而陷入死循环,程序的正常运行被打断,由单片机控制的系统便无法继续工作,这样会造成整个系统陷入停滞状态,发生不可预料的后果,所以出于对单片机运行状态进行实时监测的考虑,便产生了一种专门用于监测单片机程序运行状态的芯片,俗称“看门狗”(watch dog)。 加入看门狗电路的目的是使单片机可以在无人状态下实现连续工作, 其工作过程如下:看门狗芯片和单片机的一个I/O引脚相连,该I/O引脚通过单片机的程序控制,使它定时地往看门狗芯片的这个引脚上送入高电平(或低电平),这一程序语句是分散地放在单片机其他控制语句中间的,一旦单片
[单片机]
51单片机定时控制灯
让第一个小灯亮0.5秒,再熄灭0.5秒。 我们先随便写一个小灯闪烁的程序,以第一个小灯为例: view plain copy #include reg52.h sbit L1=P1^0; void main() { int a; while(1) { a=66666; L1=0; while(a--); a=66666; L1=1; while(a--); } } 那么怎么知道这个小灯亮了多长时间呢? 我们可以debug来知道小灯亮的时间。 首先,我们需要设置模拟器的时钟频率。点击
[单片机]
单片机有啥用?现在用的还多吗?
在刚开始工作的时候,当时也没想这么远,一心只想学习一门技术,然后找到一份不错的工作。 至少比去工地搬砖,做普工要强的就可以。 早期在做单片机开发的时候,我一直认为单片机是上个时代的产品,也是属于很传统的行业。 那个时候应该很少人听过单片机,到底是个什么东西? 最近这几年,我明显感觉变化地很快,可能是更多智能产品的带动下,比如说机器人、无人机、智能家居、充电桩,让越来越多人认识到单片机。 另外一个角度就是工资,在这几年都有明显地上涨。 记得我在5年前,当时公司研发岗位缺人,一时半会也招不到合适的。 就计划从公司内部找人来培养,后面找了一个在产线做公司产品维修的小伙子。 他也比较会做人,也聊得来,领导让我们带一下他,我们很爽快也就答应
[单片机]
NEC:四大优势相辅相成,“全闪存”开启微控制器发展新时代!
NEC电子携其阵容强大的8位、16位、32位“All Flash(全闪存)”微控制器(MCU)产品亮相2007年高交会电子展,其展台上60%的产品均为全闪存MCU。本届高交会上NEC电子的全闪存MCU产品包括两大部分:一是通常用于白色家电等的通用8位MCU(NEC电子的78K0系列方案)以及PG-FP5等开发环境;另一类是车载MCU和汽车音响等车载解决方案。 NEC电子通用微控制器事业部事业部长石川重信在接受“电子工程专辑”网站记者的采访时表示,NEC电子已经扩展了它的全闪存产品系列。截止到目前为止,经过三年的研发工作,NEC电子从8位到32位的全闪存产品已经多达316个品种,应用范围覆盖数字影音、家用电器、变频电机、医疗保
[焦点新闻]
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
随便看看
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved