ADC BX,WORD PTR ENINT+2 //微分项加入 INTSEP2: MOV WORD PTR ENSUM,AX //结果保存 MOV WORD PTR ENSUM+2,BX MOV UN,AX
MOV UNOV,BX //之前和PID2完全一样,把控制量结果存入UN和UNOV
//限幅环节
// AND BX,8000H //高位和0相与 // JZ LOOP_PID1
// MOV UN,-100 //不为0,说明输出为负数,此时限幅下限为-100 // JMP LOOP_PID2
// LOOP_PID1: MOV BX,UNOV //输出为正数的条件下继续比较 // CMP BX,0 //看高位是否有正值 // JZ LOOP_PID3
// MOV UN,0064H //高位字不为0说明结果高于上限,直接赋上限值100
// JMP LOOP_PID2
//AND AX,8000H //高位和0相与 //JZ LOOP_PID3 //MOV AX,0001H //MOV UN,AX //JMP LOOP_PID2
// LOOP_PID3: MOV AX,UN //正数,且只有低位字有数值的条件下继续比较
// CMP AX,0064H
// JB LOOP_PID2 //小于100时,UN赋值为该值, 不用改 // MOV UN,0064H
//和PID2算法一样,此处为下一控制周期计算做准备 LOOP_PID2: MOV AX,WORD PTR UD1+2 MOV WORD PTR UD0+2,AX MOV AX,WORD PTR UD1
MOV WORD PTR UD0,AX //UD1取代上一时刻的UD0 MOV AX,EN2 // 误差替换 MOV EN1,AX
POP CX //堆栈值弹出,恢复寄存器原来的值 POP BX POP AX RET PID3 ENDP
//-----------------------一阶闭环响应子程序----------------------- //设定值仍为SV的值 PIDG1 PROC
MOV AX,KP3 //为PID的参数赋值 MOV KP,AX MOV AX,KD3 MOV KD,AX MOV AX,TI3 MOV TI,AX MOV AX,TD3 MOV TD,AX
MOV AX,PV2 //此处的被控量为一阶系统的被控量PV2 MOV PV,AX
CALL PID3 //首先调用PID3算法
MOV AX,K1 //进入一阶系统自身的算法 MOV KG,AX //赋值 MOV AX,T1 MOV TG,AX
MOV AX,PV2 //把上次计算得到的PV2带入一阶系统 MOV PV,AX
CALL G1 //调用一阶惯性环节,得到新的PV MOV AX,PV
MOV PV2,AX //把输出值存在PV2中 //MOV DISPLAYWORD,AX
//CALL DISPLAYS //显示被控量PV的值
//MOV DL,0AH // 每次调用显示时生成换行 //MOV AH,02H //INT 21H RET PIDG1 ENDP
//----------------------串级控制子程序---------------------
//被控对象有两个,副调节器负责一阶系统,主调节器负责二阶系统 PIDCAS PROC
//进入主控制器的计算 MOV AX,PV1
MOV PV,AX //为PV和SV赋值,SV是整个系统的设定值 MOV AX,SV1 MOV SV,AX
MOV AX,KP3 //为副调节器参数赋值 MOV KP,AX MOV AX,TI3 MOV TI,AX MOV AX,TD3 MOV TD,AX MOV AX,KD3 MOV KD,AX
MOV AX,EN11 //把一阶系统上一时刻的误差带入PID
MOV EN1,AX MOV AX,UN1
MOV WORD PTR ENSUM,AX //上时刻的UN赋值给ENSUM,然后进行累加
MOV AX,UD11 //存储上次运行的微分项 MOV WORD PTR UD0,AX CALL PID3
MOV AX,WORD PTR UD0 //存储上次运行的微分项 MOV UD11,AX MOV AX,EN1
MOV EN11,AX //误差作为上一时刻的值保存 MOV AX,UN
MOV UN1,AX //获得控制量的值,存入UN1 //至此主控制器计算完成,得到UN1 //计算内环,也就是副调节器的值
MOV SV,AX //设定值为主调节器的输出UN1 MOV AX,PV2 //被控量为PV2 MOV PV,AX
MOV AX,KP4 //为副调节器参数赋值 MOV KP,AX MOV AX,TI4 MOV TI,AX MOV AX,TD4 MOV TD,AX MOV AX,KD4 MOV KD,AX
MOV AX,EN21 //把一阶系统上一时刻的误差带入PID MOV EN1,AX MOV AX,UN2
MOV WORD PTR ENSUM,AX //上时刻的UN赋值给ENSUM,然后进行累加
// PID算法需要保存的值有U(n-1)和e(n-1)和Ud(n-1) MOV AX,UD21 //存储上次运行的微分项 MOV WORD PTR UD0,AX CALL PID3
MOV AX,WORD PTR UD0 //存储上次运行的微分项 MOV UD21,AX MOV AX,EN1
MOV EN21,AX //误差作为上一时刻的值保存 MOV AX,UN
MOV UN2,AX //获得控制量的值,存入UN2 //一阶PID控制器完成,得到的结果存入UN2
MOV AX,K1 //进入一阶系统自身的算法 MOV KG,AX //赋值
MOV AX,T1 MOV TG,AX
MOV AX,PV2 //给PV赋上一时刻得到的值 MOV PV,AX
MOV AX,UN2 //给UN赋上一时刻得到的值 MOV UN,AX CALL G1 MOV AX,PV MOV PV2,AX
//一阶对象完成,进入二阶对象 MOV UN,AX
CALL G2 //调用G2时不需要为参数赋值,得到PV1 RET
//二阶系统输出为PV1 PIDCAS ENDP
//----------------------被控对象子程序---------------------- //一阶惯性系统G1
//使用时需要为KG和KT赋值,在K1,T1处更改即可
//输入为控制量UN,输出为被控量PV,通过差分运算获得二者的转换关系 //PV(n)={[(TG/TC)-1]×PV(n-1)+KG×UN}/(TG/TC)
//≈[(TG/TC)×PV(n-1)+KG×UN]/(TG/TC)≈PV(n-1)+k×UN,其中k=(KG×TC)/TG //需要保存好上时刻的PV值 G1 PROC
PUSH AX
MOV AX,KG //首先计算KG×TC MOV MUL1,AX MOV AX,TC MOV MUL2,AX
MOV SHIFTTIME1,4 CALL MULTIPLICATION
MOV AX,WORD PTR PRODUCT
MOV DIV1,AX //计算(KG×TC)/TG MOV AX,TG MOV DIV2,AX
MOV SHIFTTIME2,4 CALL DIVISION
MOV AX,QUOTIENT //得到商的值,存在AX中 MOV MUL2,AX //利用该商乘以UN,此处不知道UN是否溢出,是否考虑UN2△
MOV AX,UN //利用UN的值 MOV MUL1,AX
MOV SHIFTTIME1,4 CALL MULTIPLICATION
MOV AX,WORD PTR PRODUCT //第二项计算完成
ADD PV,AX //和上一时刻的PV值相加,得到的值存放在PV中
POP AX RET G1 ENDP //二阶惯性系统G2
//两个一阶系统的串联,构成二阶系统,系数有所不同
//调用时不需要在为系数赋值,在K1,T1,K2,T2处更改数值即可,计算需要赋UN的值 G2 PROC
PUSH AX
MOV AX,K1 //为KG和TG赋值 MOV KG,AX MOV AX,T1 MOV TG,AX MOV AX,PV3 MOV PV,AX CALL G1
MOV AX,PV //获得此时一阶系统的响应 MOV PV3,AX //保存PV的值给PV3 MOV UN,AX //第二个一阶系统 MOV AX,K2 //为KG和TG赋值 MOV KG,AX MOV AX,T2 MOV TG,AX MOV AX,PV1 MOV PV,AX
CALL G1 //调用一阶系统 MOV AX,PV
MOV PV1,AX //保存PV的值给PV1 //二阶系统计算完成,输出结果为PV1或PV POP AX RET G2 ENDP
//-----------------------显示字子程序----------------------- DISPLAYS PROC
PUSH CX //压入堆栈,保存各寄存器的值 PUSH BX
PUSH AX //调用AH=02的功能,改变了AX的值 //MOV DL,0AH // 每次调用显示时生成换行 //MOV AH,02H //INT 21H
MOV CL,4 //移位次数CL赋值为4,每4位显示一次 MOV BX,DISPLAYWORD //BX为要显示的字
MOV CH,4 //CH用作计数
LOOP_DISPLAY: ROL BX,CL //BX循环移位四次 MOV AX,BX //AX作为运算量 AND AX,0FH CMP AL,0AH
JB LOOP_DISPLAY1 //若小于10,则直接加30H即可转换为ASCII码
ADD AL,07H
LOOP_DISPLAY1: ADD AL,30H //转化为ASCII码 MOV DL,AL MOV AH,02H INT 21H DEC CH
JNZ LOOP_DISPLAY //不为0时,继续显示 POP AX POP BX POP CX RET DISPLAYS ENDP
//---------------------------------------------------------------------------- CODES ENDS
END START