#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); } } }