222 lines
7.7 KiB
C
222 lines
7.7 KiB
C
#include "provalctrl.h"
|
||
#include "modbus.h"
|
||
#include "dac7311.h"
|
||
#include "main.h"
|
||
|
||
propotion_valve pv_one;
|
||
propotion_valve pv_two;
|
||
|
||
//4-20mA电流输出
|
||
float ao_dwq = 0; //AO输出电流值(定位器)
|
||
float ao_blf1 = 0; //AO输出电流值(比例阀)
|
||
float ao_blf2 = 0; //AO输出电流值(比例阀)
|
||
|
||
void prov_init(void) //比例阀结构体参数初始化
|
||
{
|
||
pv_one.current_pressure = 0; //当前气压,Kpa
|
||
pv_one.current_percent = 0; //当前气压百分比( 0~900Kpa -> 0~100% )
|
||
pv_one.target_pressure = 0; //目标气压,Kpa
|
||
pv_one.target_percent = 0; //目标气压百分比( 0~900Kpa -> 0~100% )
|
||
pv_one.current_input = 0; //当前输入电流
|
||
pv_one.input_min = 4; //输入电流下限4mA
|
||
pv_one.input_max = 20; //输入电流上限20mA
|
||
pv_one.bias = 0; //偏差 = 目标气压百分比 - 当前气压百分比
|
||
pv_one.bias_previous = 0; //前一个时刻的偏差
|
||
pv_one.bias_area = 0.5; //允许的误差范围,±a(%)
|
||
|
||
pv_one.Kp = 0.02; //pid控制
|
||
pv_one.Ti = 2500;
|
||
pv_one.Ing = 0;
|
||
pv_one.Ing_max = 3;
|
||
pv_one.Ing_min = -3;
|
||
pv_one.Td = 5;
|
||
pv_one.pidout = 0;
|
||
pv_one.pidout_max = 0;
|
||
pv_one.pidout_min = 0;
|
||
|
||
pv_one.cstep_gasin = 0.001; //逐步接近的电流步长,mA,充气
|
||
pv_one.cstep_gasout = 0.002; //逐步接近的电流步长,mA,排气
|
||
pv_one.cstep_max = 0; //逐步接近的电流范围上限
|
||
pv_one.cstep_min = 0; //逐步接近的电流范围下限
|
||
pv_one.cstep_wait = 0;
|
||
|
||
pv_one.pvout = ao_blf1_set;
|
||
pv_one.pvout(0);
|
||
/************************************************/
|
||
pv_two.current_pressure = 0;
|
||
pv_two.current_percent = 0;
|
||
pv_two.target_pressure = 0;
|
||
pv_two.target_percent = 0;
|
||
pv_two.current_input = 0;
|
||
pv_two.input_min = 4;
|
||
pv_two.input_max = 20;
|
||
pv_two.bias = 0;
|
||
pv_one.bias_previous = 0; //前一个时刻的偏差
|
||
pv_two.bias_area = 0.5;
|
||
|
||
pv_two.Kp = 0;
|
||
pv_two.Ti = 1000000;
|
||
pv_two.Ing = 0;
|
||
pv_two.Ing_max = 5;
|
||
pv_two.Ing_min = -5;
|
||
pv_two.Td = 0;
|
||
pv_two.pidout = 0;
|
||
pv_two.pidout_max = 0;
|
||
pv_two.pidout_min = 0;
|
||
|
||
pv_two.cstep_gasin = 0.001; //逐步接近的电流步长,mA,充气
|
||
pv_two.cstep_gasout = 0.002; //逐步接近的电流步长,mA,排气
|
||
pv_two.cstep_max = 0;
|
||
pv_two.cstep_min = 0;
|
||
pv_two.cstep_wait = 0;
|
||
|
||
pv_two.pvout = ao_blf2_set;
|
||
pv_two.pvout(0);
|
||
}
|
||
|
||
void prov_ctrl(float target_p, propotion_valve *pvx)
|
||
{
|
||
target_p = (target_p < pvx->input_max)?(target_p):(pvx->input_max); //dac输出限幅
|
||
target_p = (target_p > 0)?(target_p):(0);
|
||
|
||
pvx->target_percent = (target_p - pvx->input_min) / (pvx->input_max - pvx->input_min)*100;
|
||
pvx->target_pressure = pvx->target_percent/100*900; //Kpa, 比例阀 (4~20mA -> 0~0.9Mpa)
|
||
|
||
pvx->current_input = target_p; //记录当前理论模拟输出
|
||
|
||
pvx->cstep_max = pvx->current_input + (float)0.8; //逐步输出调节上限
|
||
pvx->cstep_min = pvx->current_input - (float)0.8; //逐步输出调节下限
|
||
pvx->cstep_wait = 0; //等待计数清零
|
||
|
||
pvx->pidout_max = pvx->current_input + (float)0.8; //pid输出调节上限
|
||
pvx->pidout_min = pvx->current_input - (float)0.8; //pid输出调节下限
|
||
|
||
pvx->pvout(target_p); //dac输出
|
||
}
|
||
|
||
float abs_bias(float bias)
|
||
{
|
||
bias =( bias>=0 )?(bias):(-bias);
|
||
return bias;
|
||
}
|
||
void prov_calibrate_pid(propotion_valve *pvx)
|
||
{
|
||
if( (abs_bias(pvx->bias) > pvx->bias_area ) && (abs_bias(pvx->bias) < BIAS_MAX) ) //误差进入目标±BIAS_MAX%以内后再进行控制
|
||
{
|
||
if( (pvx->Ing >= pvx->Ing_min) && (pvx->Ing <= pvx->Ing_max) ) //积分累加与限幅
|
||
{
|
||
pvx->Ing += pvx->bias * (float)0.1; //偏差的更新周期为100ms
|
||
}else
|
||
{
|
||
pvx->Ing = (pvx->Ing > 0)?(pvx->Ing_max):(pvx->Ing_min);
|
||
}
|
||
|
||
pvx->pidout = pvx->Kp*( pvx->bias + (1/pvx->Ti)*pvx->Ing + pvx->Td*(pvx->bias - pvx->bias_previous) );
|
||
pvx->current_input += (pvx->pidout/100) * (pvx->input_max - pvx->input_min);
|
||
|
||
pv_one.bias_previous = pvx->bias; //更新前一个时刻的偏差
|
||
|
||
pvx->current_input = (pvx->current_input < pvx->pidout_max)?(pvx->current_input):(pvx->pidout_max); //pid输出限幅
|
||
pvx->current_input = (pvx->current_input > pvx->pidout_min)?(pvx->current_input):(pvx->pidout_min);
|
||
|
||
pvx->current_input = (pvx->current_input < pvx->input_max)?(pvx->current_input):(pvx->input_max); //dac输出限幅
|
||
pvx->current_input = (pvx->current_input > pvx->input_min)?(pvx->current_input):(pvx->input_min);
|
||
pvx->pvout(pvx->current_input);
|
||
}else
|
||
{
|
||
pvx->Ing = 0;
|
||
}
|
||
|
||
}
|
||
|
||
|
||
float atm_pressure = 0; //用于存放大气绝压,单位:0.1Kpa
|
||
void analog_ctrl(void)
|
||
{
|
||
if(ao_dwq != (float)(HoldReg[0]) / 1000) //保持寄存器值发生变化时dac输出
|
||
{
|
||
ao_dwq = (float)(HoldReg[0]) / 1000; // uA -> mA
|
||
if(ao_dwq > 25) ao_dwq = 25; //定位器控制
|
||
ao_dwq_set(ao_dwq);
|
||
}
|
||
|
||
if(ao_blf1 != (float)(HoldReg[1]) / 1000) //保持寄存器值发生变化时dac输出
|
||
{
|
||
ao_blf1 = (float)(HoldReg[1]) / 1000; // uA -> mA
|
||
prov_ctrl(ao_blf1,&pv_one); //控制比例阀1
|
||
}
|
||
|
||
if(ao_blf2 != (float)(HoldReg[2]) / 1000) //保持寄存器值发生变化时dac输出
|
||
{
|
||
ao_blf2 = (float)(HoldReg[2]) / 1000; // uA -> mA
|
||
prov_ctrl(ao_blf2,&pv_two); //控制比例阀2
|
||
}
|
||
|
||
if(it_100ms_flag_pv == 1) //每隔100ms更新一次数据
|
||
{
|
||
it_100ms_flag_pv = 0;
|
||
|
||
atm_pressure = ( (InputReg[7] - 4000)/(float)16000.0 ) * 2000; //大气绝压更新,4~20mA->0~200Kpa
|
||
|
||
//比例阀1数据更新:当前气压、当前气压百分比、百分比偏差、当前输入电流(单片机->比例阀)
|
||
pv_one.current_pressure = (InputReg[16] - atm_pressure)/(float)10; //Kpa,sensor1 A口绝压转表压
|
||
pv_one.current_percent = pv_one.current_pressure/900*100;
|
||
pv_one.bias = pv_one.target_percent - pv_one.current_percent;
|
||
|
||
//比例阀2数据更新:当前气压、当前气压百分比、百分比偏差、当前输入电流(单片机->比例阀)
|
||
pv_two.current_pressure = (InputReg[17] - atm_pressure)/(float)10; //Kpa,sensor1 B口绝压转表压
|
||
pv_two.current_percent = pv_two.current_pressure/900*100;
|
||
pv_two.bias = pv_two.target_percent - pv_two.current_percent;
|
||
}
|
||
|
||
if(it_50ms_flag_pv == 1) //每隔50ms校准一次
|
||
{
|
||
it_50ms_flag_pv = 0;
|
||
|
||
if( (CoilState[0]&(0x03)) == 0x03 ) //两个电磁阀都开启的情况下才进行校准
|
||
{
|
||
// prov_calibrate_step(&pv_one);
|
||
// prov_calibrate_step(&pv_two);
|
||
|
||
prov_calibrate_pid(&pv_one);
|
||
prov_calibrate_pid(&pv_two);
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
|
||
|
||
void prov_calibrate_step(propotion_valve *pvx)
|
||
{
|
||
pvx->cstep_wait = (pvx->cstep_wait > 254)?(pvx->cstep_wait):(pvx->cstep_wait + 1); //每100ms加一次,上限255
|
||
|
||
if( pvx->cstep_wait > CSTEP_WAIT_MAX) //目标更新X秒后,误差仍不符合条件时再进行微步调节
|
||
{
|
||
if( (pvx->bias > pvx->bias_area) && (pvx->bias < BIAS_MAX) ) //正偏差(目标-实际),输出偏小
|
||
{
|
||
pvx->current_input += ((pvx->bias < 1))?(pvx->cstep_gasin):(pvx->cstep_gasin*3);
|
||
|
||
pvx->current_input = (pvx->current_input <= pvx->cstep_max)?(pvx->current_input):(pvx->cstep_max); //dac输出限幅
|
||
pvx->current_input = (pvx->current_input <= pvx->input_max)?(pvx->current_input):(pvx->input_max);
|
||
|
||
pvx->pvout(pvx->current_input);
|
||
}
|
||
|
||
if( (pvx->bias < -pvx->bias_area) && (pvx->bias > -BIAS_MAX) ) //负偏差(目标-实际),输出偏大
|
||
{
|
||
pvx->current_input -= ((pvx->bias > -1))?(pvx->cstep_gasin):(pvx->cstep_gasout*3);
|
||
|
||
pvx->current_input = (pvx->current_input >= pvx->cstep_min)?(pvx->current_input):(pvx->cstep_min); //dac输出限幅
|
||
pvx->current_input = (pvx->current_input >= pvx->input_min)?(pvx->current_input):(pvx->input_min);
|
||
|
||
pvx->pvout(pvx->current_input);
|
||
}
|
||
}
|
||
|
||
|
||
}
|
||
|
||
|
||
|