下面这段程序是前辈写的控制电动执行器的小型PI控制器的程序,采集现场温度,通过PI调节,输出0-10V或者2-10V控制阀门开度。
************************************************************************/ int Goal;//设定值
int ei;//最近的一次偏差 int abs_ei;//偏差的绝对值 int LastError;// 上次偏差
int ADC_date[3];//近三次的测量值 其中ADC_date[0]为最近一次的测量量
unsigned char Limit_PIDorKey;//PID控制的分界值 int ui;//PID输出
int second_tn_count ;//积分复位时间计时 char sampl_time ; //取样周期计时
int P = 24;//比例值默认设置 int I = 8;//积分值默认设置
int Tn = 2 ;//积分复位时间,键盘设置范围(0-300)S
int Tn_second;//积分复位时间转换成秒
unsigned char p_temp = 5 ;// 启动PI控制的温度差值(比例带)
int I_add_test = 0; int I_add_test_1 = 0; long int I_add_test_2 = 0;//积分量之和 /************************************************************************
/************************************************************************ ATmega32定时器1初始化程序 ---中断间隔10ms ************************************************************************/ void timer1_init(void) { TCCR1B = 0x00; //stop TCNT1H = 0xFE; //setup TCNT1L = 0xE1; OCR1AH = 0x01; OCR1AL = 0x1F; OCR1BH = 0x01; OCR1BL = 0x1F; ICR1H = 0x01; ICR1L = 0x1F; TCCR1A = 0x00; TCCR1B = 0x04; //start Timer }
/************************************************************************ ATmega32定时器1中断程序 ----10ms一次中断 ************************************************************************/ #pragma interrupt_handler timer1_ovf_isr:iv_TIM1_OVF void timer1_ovf_isr(void) { //TIMER1 has overflowed TCNT1H = 0xFE; //reload counter high value TCNT1L = 0xE1; //reload counter low value
if (time_dis_count++>=100)//1S { time_dis_count = 0; second_tn_count++;//积分复位时间 1S加1 second++; if(second>=60)//1分钟 second = 0; sampl_time++; if(sampl_time>=10)//采样周期 10分钟 { sampl_time = 0;
PID_Ctrl(); //10分钟进行一次PID调节
} } }
/************************************************************************ *函数名称:PID_Ctrl *功能说明:PID的计算部分 *入口参数:无 *出口参数:无 *调用函数:无 ************************************************************************/ void PID_Ctrl(void) { long int ts; int p; int x1_h1_integer;//存放读取温度的整数部分 int x1_h1_decimal;//存放读取温度的小数部分
int a ; p = P*100;//比例系数扩大100倍 Tn_second = Tn;//积分复位时间
x1_h1_integer = X1_integer; //温度整数部分 x1_h1_decimal = X1_decimal; //温度小数部分
ADC_date[0] = x1_h1_integer*10+x1_h1_decimal;//将最新测量的温度存入ADC_date[0]
Limit_PIDorKey = p_temp*10;//启动PI控制的温度差值( 比例带)扩大10倍
LastError = ei;//保存这次误差
ei = Goal*10 - ADC_date[0];//目标值与最新温度偏差===当前误差 if(ei<0)//当前偏差的绝对值 abs_ei = -ei; else abs_ei = ei;
I_add_test_1 = close_to_5(I*abs_ei*10);//四舍五入(积分系数*偏差绝对值*10) I_add_test_2 += I_add_test_1;//多次积分值 求和
if(second_tn_count>=Tn_second) //如果计数时间大于 积分复位时间 { I_add_test = I_add_test_2/100;//积分量 ts = ((long int)p)*((long int) abs_ei);//比例量 ts = close_to_5(ts);//四舍五入
ui =ts+I_add_test;//PI之和 if((abs_ei>=Limit_PIDorKey)|(ui>=output_high_date))//当差值大于伐值的时候 不进行PI调节 { ui = output_high_date; //output_high_date为当前AO输出的模拟量 NOP(); }
if(((ei>=5)&(set_win_sum==0))|((ei<=-5)&(set_win_sum==1))) { ui = 0; }
da_output_date = ui+output_low;//输出模拟量=ui+(0或2v)
ui = 0; I_add_test = 0; I_add_test_2 = 0;
second_tn_count = 0; } }
有几点疑惑
1.这个是位置式pi么?
2.10分钟才进一次PI程序,为啥这么长时间?
3,。对于积分复位时间不太理解。每10分钟 也就是600S进入PI调节后,second_tn_count计数肯定会大于Tn_second(键盘设置的积分复位时间),那么每次积分量都会复位清零。每次使用的积分量只是I*abs_ei*10,并不是积分量的累加。这个是不是有误?
|