初级会员

- 积分
- 75
- 金钱
- 75
- 注册时间
- 2011-10-12
- 在线时间
- 9 小时
|
硬件:
1。用可控硅控制4.5KW电炉 用K型热电偶采集温度,采用cs1242做温度转换,可以到正负一度的精度
实验目标:
在300度到1000度内可对任意设定的温度恒温,精度先做到+/-1度吧
基本的控制实现方法:
因为是对加热的炉子温度进行控制,属于滞后效应系统,所以采样周期先定为2秒(这里指的是PID计算的周期,注意我的温度采样是实时的),所以CPU外部中断次数为15次/S,对应的功率计算结果输出为0~255,就是说把这2秒钟划分为255等份,根据计算的结果来决定在这2秒钟内应该加热多少等份

/******************************************************************************
FILE: FUZZY.C
POPURSE:
WRITER: Xukaiming
DATE: 2007.03.08
******************************************************************************/
#include "main.h"
#include "task.h"
#include "fuzzy.h"
#include "ied_ctrl.h"
#include "math.h"
#include "x5043.h"
#include "manctrl.h"
#define ERRORCNT 9 //误差记录
#define DERRORCNT 10 //误差变化率记录
//#define DOOROPENSPEED -15L //开门时的升温速度,如果低于此温度,认为电阻丝的热量完全散发出来或者开门升温
xdata long DOOROPENSPEED = - 15L;
#define MAXNEGINTERG (-200L*KI/Ki)
extern code unsigned int K_Temp_Tab[];
typedef struct AI_CONTROL
{
long gDest; //目标温度的AD值
long CTEMP; //开始控制温度
long Error[ERRORCNT]; //偏差
long dErr[DERRORCNT]; //偏差变化率
long ECSUM; //10S内的偏差变化率之和
long SumErrLimit; //加热初值
long PreviewOut;
long du;
long DoorOpenValue; //保存炉子门状态
char LowSpeedCnt;
unsigned int iDestTemp; //目标温度值
};
#define Kp 15 //输出变量u比例因子
#define Ki 1/10 //衰减系数;
#define KI 15
//Kp 变小的时候 ki要变大
xdata struct AI_CONTROL Ai_CTRL;
void TaskFuzzy(void)
{
char cnt;
_nop_();
if (IED.lADTemp > MAX_TEMP)
//超温保护
{
SetPWM(PWM_PITCED);
return ;
}
//求偏差
for (cnt = ERRORCNT - 1; cnt > 0; cnt--)
{
Ai_CTRL.Error[cnt] = Ai_CTRL.Error[cnt - 1];
} //保存上次偏差值
Ai_CTRL.Error[0] = (long)(((Ai_CTRL.gDest - IED.lADTemp) / KC));
for (cnt = DERRORCNT - 1; cnt > 0; cnt--)
{
Ai_CTRL.dErr[cnt] = Ai_CTRL.dErr[cnt - 1];
} //保存上次偏差率值
Ai_CTRL.dErr[0] = Ai_CTRL.Error[0] - Ai_CTRL.Error[1]; //计算偏差变化率
Ai_CTRL.ECSUM = Ai_CTRL.dErr[0] + Ai_CTRL.dErr[1] + Ai_CTRL.dErr[2] +
Ai_CTRL.dErr[3] + Ai_CTRL.dErr[4]; //10s的温升速率 =iol
if (Ai_CTRL.Error[0] < Ai_CTRL.CTEMP)
{
if (((Ai_CTRL.Error[0] *Ai_CTRL.dErr[0]) > 0) || ((Ai_CTRL.Error[0] == 0)
&& (Ai_CTRL.dErr[0] != 0)))
//误差变大的情况
{
Ai_CTRL.SumErrLimit += Ai_CTRL.Error[0]; //误差变大的时候,求积分
if (Ai_CTRL.SumErrLimit < MAXNEGINTERG)
//限幅,如果超过负的最大值, 保持为负的最大值
Ai_CTRL.SumErrLimit = MAXNEGINTERG;
////////////////////////////////////////////////////////////
Ai_CTRL.du = Ai_CTRL.Error[0] *Kp + Ai_CTRL.SumErrLimit * Ki / KI * Kp;
//增益抑制模式 //
}
else
//开环保持模式
{
if (((Ai_CTRL.Error[0] *Ai_CTRL.dErr[0]) < 0) || (Ai_CTRL.dErr[0] == 0))
//误差变小的情况
{
Ai_CTRL.du = Ai_CTRL.SumErrLimit * Ki / KI * Kp;
}
else
{
Ai_CTRL.du = Ai_CTRL.PreviewOut;
}
}
}
else
Ai_CTRL.du = PWM_PERIOD;
//升温
if (Ai_CTRL.du < 0)
Ai_CTRL.du = 0;
if (Ai_CTRL.du > PWM_PERIOD)
Ai_CTRL.du = PWM_PERIOD;
#ifdef _DEBUG
printf("%ld,", Ai_CTRL.CTEMP);
printf("%ld,%ld,", Ai_CTRL.Error[0], Ai_CTRL.dErr[0]);
printf("%ld,%ld,%d\n", Ai_CTRL.ECSUM, Ai_CTRL.SumErrLimit, (int)Ai_CTRL.du);
#endif
SetPWM((unsigned char)Ai_CTRL.du);
//保存上次输出
Ai_CTRL.PreviewOut = Ai_CTRL.du;
}
//functions prototype
/************************************************************************
仿人智能控制器//Humanoid Intelligent Controller
************************************************************************/
/*******************************************************************
模糊控制数据变量
********************************************************************/
void InitFuzzy(void)
{
Ai_CTRL.DoorOpenValue = 0; // 重新统计升温速度
Ai_CTRL.LowSpeedCnt = 0;
SetPWM(PWM_PITCED);
}
/*********************************************************************
启动高温炉
**********************************************************************/
void CtrlStove(UCHAR cOpen, long lDefTemp, UCHAR cRate)
{
xdata StableTempTab psTmpTab;
//停止
SuspendTask(TASK_FUZZY);
InitFuzzy();
if (cOpen)
//启动
{
Ai_CTRL.gDest = (((double)(0xFFFFFFUL << 2)) / 5000000UL)
*K_Temp_Tab[lDefTemp] + 20; //将 目标 温度值 转换 为 AD值
Ai_CTRL.CTEMP = (1010L - lDefTemp); //控温范围
ActiveTask(TASK_FUZZY, PWM_SCAN);
}
}
/**********************************************************************
设置PWM,PWM0控制高温炉
16MHz时,T=2*512/16=64uS,F=42.666KHz,计数周期=256,占空比=0%--99.61%
***********************************************************************/
sbit POUT = P1 ^ 3;
char gcPoutTimer = - 1;
void StopPOut()
{
POUT = 1;
}
void SetPWM(UCHAR cPeriod)
{
/*
CMOD = 0x00; // Setup PCA timer
// Configure PCA0 Counter operating mode
CCAP0L=CCAP0H=cPeriod; // Set duty for TCM0
CCON =0x40;
CCAPM0=0x42; // Set TCM0 operationg mode
*/
long period;
StopTimer(&gcPoutTimer);
POUT = 1;
period = PWM_SCAN * cPeriod / 255 / 10;
if (period > 0)
{
POUT = 0;
gcPoutTimer = StartTimer(TIMER_MODE_ONCEROUTINE, period, StopPOut, 0);
}
}
|
|