用整型变量来实现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.CK_Uint16 ) //设定值大于实际值否?
{
if( PID.RK_Uint16 - PID.CK_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--;
}
}
关键字:51单片机 PID算法 温度控制
引用地址:
51单片机实现PID算法(温度控制)
推荐阅读最新更新时间:2024-03-16 14:35
51单片机数码管显示的数字钟
这是一个基于51单片机的数字钟程序用数码管来显示数据. 原理图源代码及仿真文件下载地址: http://www.51hei.com/bbs/dpj-20407-1.html 下面是源码: #include AT89X51.H unsigned char code dispcode ={0x3f,0x06,0x5b,0x4f, 0x66,0x6d,0x7d,0x07, 0x7f,0x6f,0x77,0x7c, 0x39,0x5e,0x79,0x71,0x00}; unsigned char dispbitcode ={0
[单片机]
基于MCS-51单片机的IEEE-488接口设计
1 概 述 智能仪器程控接口电路的设计,首先是根据仪器的功能确定该仪器的接口功能。文中所涉及的仪器是以MCS-51系列单片机作为内部控制器的高速数据采集装置,由于A/D转换器既要向计算机输送采集结果,又要接受计算机对其工作条件的控制,因此,在程控接口电路设计时,设置了六种接口功能:源挂钩功能(选用SH1功能子集)、受者挂钩功能(选用AH1功能子集)、讲功能(选用T5功能子集)、听功能(选用L4功能子集)、远地/本地功能(选用RL功能子集)和器件触发功能(选用DT1功能子集)。 2 接 口 功 能 (IF) 设 计 如图1所示是该仪器的原理框图,其中接口功能电路由时序转换与信号控制电路、MC68488和四片M
[应用]
51单片机~串口通信
(一)计算机串行通信原理: 综上:所以在设置的时候,经常将SCON设置为0X50==0101 0000 ,使用方式1. (二)工作: 中断控制 led灯,每发送一条指令灯亮或灭(反转一下) #include reg52.h typedef signed char int8; typedef signed int int16; typedef signed long int32; typedef unsigned char uint8; //字符型 typedef unsigned int uint16; typedef unsigned long
[单片机]
基于51单片机的一键多功能识别技术
1.实验任务 如图4.9.1所示,开关SP1接在P3.7/RD管脚上,在AT89S51单片机的P1端口接有四个发光二极管,上电的时候,L1接在P1.0管脚上的发光二极管在闪烁,当每一次按下开关SP1的时候,L2接在P1.1管脚上的发光二极管在闪烁,再按下开关SP1的时候,L3接在P1.2管脚上的发光二极管在闪烁,再按下开关SP1的时候,L4接在P1.3管脚上的发光二极管在闪烁,再按下开关SP1的时候,又轮到L1在闪烁了,如此轮流下去。 2.电路原理图 图4.9.1 3.系统板上硬件连线 (1).把“单片机系统”区域中的P3.7/RD端口连接到“独立式键盘”区域中的SP1端口上; (2).把“单片机系统”区域中的P1.0-P1
[单片机]
51单片机设计的电子密码锁
该程序是基于51单片机设计的电子密码锁,功能较为简单,目前仅有修改密码和检测这一功能,以下是操作过程 运行仿真的初始界面 左边矩阵按键从左边第一行第一列起为0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f 按下按键后界面如下,当四位数码管都显示后,按下矩阵键盘上任意按键确认密码 密码错误D1红灯亮起,密码正确D2绿灯亮起 当按下独立按键时,中断触发,进入密码修改,此时界面如同初始界面,输入原始密码,原始密码正确,绿灯亮起,等待输入新密码,此时界面显示原始密码。原始密码错误红灯亮起,退出修改,返回初始状态。 新密码输入会将原始密码覆盖,输入完成红绿灯同时亮起。 1s后返回初始界面,
[单片机]
80C51单片机中断的编程使用方法介绍
1、单片机中断: 找了一张 80C51 单片机的图如下: 其中,在 P3.2、P3.3 的位置,即 12 ,13 引脚处,标有 INT0 和 INT1,那两个引脚就是外部中断的输入。上面一个横杠代表低电平有效,给 P3.2、P3.3 赋值 0,就可以运行已经写好的中断服务程序。具体怎么用,还要熟悉一些中断寄存器的使用。 2、中断寄存器: (1)、IE (Interrupt Enable):中断允许控制寄存器 EA (IE.7):EA=0 时,所有中断禁止(即不允许中断) EA=1 时,各中断的产生由个别的允许位决定 ET2 (IE.5):定时器 2 溢出中断允许(8052 用,博主用的 STC89C54RD+ 也有) ES
[单片机]
51单片机 AD转换
在数逻的课程中,已经学习过AD转换的概念:将模拟信号采样、量化、编码后转换为数字信号。但是未学习过通过单片机编程,显示结果。 编码分有舍有入、只舍不入两种,量化误差前者更小。=2Vm/(2^n+1 - 1 ) 注意,为了达到精确度高、稳定性好的目的,最好将所有器件的模拟地和数字分别连接,最后将模拟地和数字地仅在一点相连。 此处,使用的是STC12C5A60S2内部的AD转换。 1 /* 功能:使用12C5A60S2内部AD读取外部电压,显示在1602上 */ 2 3 #include STC12C5A60S2.H 4 #include intrins.h 5 sbit RS = P2^6; //1602
[单片机]
MCS51单片机的滤波程序
MCS51单片机的滤波程序 ;限幅滤波程序 ;入口 :A,SDAT,DELTY ;占用资源:B ;堆栈需求:2字节 ;出口 :A JUGFILT :MOV B,A CLR C SUBB A,SDAT JNC JUGFT1 CPL A INC A JUGFT1 :SETB A SUBB A,#DELTY JNC JUGFT3 MOV A,SDAT RET JUGFT3 :MOV A,B MOV SDAT,A RET ;中位值滤波程序 ;入口 :ADDPH,ADDPL,N ;占用资源:E
[单片机]