$TITLE(PID.A51) ; Module PID.A51 Rev 1.0 $XREF ; By Frank Fritz -- Copyright 1997 (C) Frank Fritz $DEBUG ; $NOLIST ; switch off generation of the listing file $NOMOD51 ; switch off 8051 controller defaults and use... $INCLUDE (c:\fsi\inc\reg51.inc) ; Include the 8051 register definitions/declarations. $LIST ; switch on listing. EXTRN DATA (temperature, intr_count, disp_val, ee_address, ee_lsb, ee_msb, ee_cntrl, pwm_cntr, error, cv, duty_cycle, i_old_h, i_old_l) EXTRN DATA (active_pb, limit_cntr_lo, limit_cntr_hi, old_temp, h_list_dptr, c_list_dptr) EXTRN XDATA (h_list, c_list) EXTRN BIT (on_targ_flag, pid_error_flag, limit_flag, DS1620_FLAG, eesv_flag, neg_flag, while_flag1, mode, while_dtt_flag, ai_tl_flag) EXTRN NUMBER (TL0_val, TH0_val, TL1_val, TH1_val, intr_service, read_ee, write_ee, ewen, ewds, setpoint) EXTRN NUMBER (gain_p, gain_i, deadband_val, limit_lo_val, limit_hi_val) EXTRN CODE (clock_strobe) PUBLIC pid, dtt PID_MOD SEGMENT CODE RSEG PID_MOD ; switch to PID code segment USING 1 ; Use register set 0 ; ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ; Module: PID ; Revision: 1.0 ; Date: August 8, 1997 ; By: Frank Fritz ; About: The PID module provides the output control to the system. ; ; The PID algorithm in general: ; ; 1. Calculate error (setpoint - temperature) ; 2. If error <= deadband, set on-target-flag, exit routine. ; 3. If error > deadband, calculate Proportional term (P_term = error * p_gain) ; 4. Calculate Integeral term (I_term = (error * i_gain) + old I_term. ; 5. Calculate the Derivative term (not active for now). ; 6. Sum all terms in control variable -- cv. (cv = P_term + I_term + D_term). ; 7. Test for overflow (>7FH) or underflow (<00H) of cv, integrator. ; 8. If overflow or underflow, set pid_error_flag and clamp output to max or min condition. ; ; Program Flow ; Called From: INTR_0 ; Input: temperature, old integrator value. ; Output: cv, pid_error_flag ; Modifies: R14567 ; Calls: add_16, sub_16 ; ; History: Date Comments ; ---------------- ------------------------------------------------------------------------------------------------------------------------------- ; 08/08/97 Developed code. ; ; -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- pid: MOV A,#setpoint ; Perform the PID - Calculate the error. CLR C ; - SUBB A,temperature ; Error = (Setpoint - PV) --> ACC. JB ACC.7,calc_neg ; Test for Negative error. MOV error,A ; Save error value. CLR neg_flag ; Positive error SJMP calc_db ; - calc_neg: SETB neg_flag ; Set negative flag. CLR C ; - MOV R7,#00H ; - XCH A,R7 ; - SUBB A,R7 ; - MOV error,A ; Save corrected error value. calc_db: CLR pid_error_flag ; Reset integrator windup error bit. SETB on_targ_flag ; Determine if within Deadband. CLR C ; - SUBB A,#deadband_val ; Error always positive. JC pid_exit ; If error < deadband (i.e. C = 1) then exit, else do the PID. calc_p: CLR on_targ_flag ; Not within deadband, clear the on target flag. MOV A,error ; Error in Acc. MOV B,#gain_p ; Proportional Gain in B. MUL AB ; P_term = (Error * Proportional Gain.) JB neg_flag,calc_p_inv ; - MOV R1,B ; R1 = P_Term / FF SJMP calc_i ; Move on to Integeral. calc_p_inv: MOV R6,A ; R6 is P term LSB. MOV R7,B ; R7 is P term MSB. MOV R4,#00H ; - MOV R5,#00H ;- LCALL sub_16 ; Take 2's compliment of P_Term. (Returned in R67). MOV A,R7 ; - MOV R1,A ; R1 = P_Term / FF calc_i: MOV A,error ; Error in Acc. MOV B,#gain_i ; Integral gain in B MUL AB ; Operation: I_Part = (Error * Integral Gain). JB neg_flag,calc_i_inv ; - MOV R6,A ; R6 is LSB. MOV R7,B ; R7 is MSB. calc_i_0: MOV R5,i_old_h ; R5 is MSB. MOV R4,i_old_l ; R4 is LSB. LCALL add_16 ; Operation: I_Term = I_Part + I_Old. I_Term returned in R7,R6. MOV A,R7 ; Check for reset-windup limit (7F max). JNB ACC.7,calc_i_2 ; Test MSBit. JB neg_flag,calc_i_1 ; Test condition to limit hi or lo. MOV R7,#7FH ; Limit I_Term to max positive limit if neg_flag = 0. MOV R6,#00H ; - SJMP calc_i_2 ; - calc_i_1: MOV R7,#00H ; Limit to MIN value. MOV R6,#00H ; - calc_i_2: MOV i_old_h,R7 ; Update I_Old value. MOV i_old_l,R6 ; - SJMP calc_d ; Do derivative. calc_i_inv: MOV R6,A ; R6 is P term LSB. MOV R7,B ; R7 is P term MSB. MOV R4,#00H ; - MOV R5,#00H ;- LCALL sub_16 ; Take 2's compliment of I_Part. (Returned in R67). SJMP calc_i_0 ; Continue. calc_d: NOP ; No Derivitive term for now. calc_pid: MOV A,R7 ; Acc = I_Term / 256. ADD A,R1 ; Operation: (I_Term / 256) + (P_term / 256) --> ACC. JNB ACC.7,calc_pid_1 ; Test for overflow / underflow. JB neg_flag,calc_pid_0 ; Status of bit determines limit hi or lo. MOV A,#07FH ; Overflow condition, set to MAX ON condition. SETB pid_error_flag ; Set error (limit) bit. SJMP calc_pid_1 ; - calc_pid_0: CLR A ; Underflow condition, set to MIN ON (i.e.OFF) condition. SETB pid_error_flag ; Set error (limit) bit. calc_pid_1: MOV cv,A ; CV is now P + I. JNB mode,pid_exit ; If control mode is HEAT (bulbs) then don't invert CV. CLR C ; Mode is COOL (fans). Invert CV (i.e. max cv = max cooling). MOV A,#07FH ; Invert CV. SUBB A,cv ; - MOV cv,A ; Inverted cv. pid_exit: RET ; Exit PID routine. ; ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ; Module: add_16 ; Revision: 1.0 ; Date: August 8, 1997 ; By: Frank Fritz ; About: ADD_16 will take two 16 bit numbers and add them together. ; ; Program Flow ; Called From: PID ; Input: R4567 (R46 = lsb, R57 = msb) ; Output: R6 (lsb), R7 (msb) ; Modifies: R4567 ; Calls: Nothing ; ; History: Date Comments ; ---------------- ------------------------------------------------------------------------------------------------------------------------------- ; 08/08/97 Developed code. ; ; -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ; Operation: R45 + R67 --> R67 (R4,R6 = LSB, R5,R7 = MSB) add_16: MOV A,R4 ; LSB in Acc. ADD A,R6 ; Acc = R4 + R6 (LSB's) MOV R6,A ; Return LSB in R6. MOV A,R5 ; MSB in Acc. ADDC A,R7 ; Acc = R5 + R7 (MSB's) MOV R7,A ; Return MSB in R7. RET ; ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ; Module: sub_16 ; Revision: 1.0 ; Date: August 8, 1997 ; By: Frank Fritz ; About: SUB_16 will take two 16 bit numbers and subtract them. ; ; Program Flow ; Called From: PID ; Input: R4567 (R46 = lsb, R57 = msb) ; Output: R6 (lsb), R7 (msb) ; Modifies: R4567 ; Calls: Nothing ; ; History: Date Comments ; ---------------- ------------------------------------------------------------------------------------------------------------------------------- ; 08/08/97 Developed code. ; ; -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ; Operation: R45 - R67 --> R67 (R4,R6 = LSB, R5,R7 = MSB) sub_16: MOV A,R4 ; LSB in Acc. CLR C ; Clear Carry. SUBB A,R6 ; Acc = R4 - R6 (LSB's) MOV R6,A ; Return LSB in R6. MOV A,R5 ; MSB in Acc. SUBB A,R7 ; Acc = R5 - R7 (MSB's) MOV R7,A ; Return MSB in R7. RET ; --------------------------------------------------- Service the Dallas DS1620 Thermometer --------------------------------------------------------- ; ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ; Module: ; Revision: 1.0 ; Date: August 8, 1997 ; By: Frank Fritz ; About: ; ; Program Flow ; Called From: Interrupt 0 (INTR_0) ; Input: ; Output: ; Modifies: ; Calls: ; ; History Date Comments ; ---------------- -------------------------------------------------------------------------------------------------------------------------------- ; 08/08/97 Developed code. ; ; -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- dtt: SETB P3.3 ; Select Dallas DS1620 device. JBC DS1620_FLAG,dtt_2 ; Test for read or start convert cycle. MOV A,#0AAH ; Read the temperature from the DS1620. LCALL dtt_4 ; Write the Protocol byte (READ) to the DS1620. CLR A ; Setup for data xfr. SETB P3.2 ; Set up bit P3.2 as an INPUT bit. CLR C ; - MOV R0,#08H ; R0 is bit counter. dtt_1: NOP ; Perform clock strobe here - MUST read DQ while CLK=0 (inverted). SETB P3.0 ; Set clock line to '1'. NOP ; Delay 3 us. NOP NOP MOV C,P3.2 ; Read the DS1620 DQ line (data in).DG CLR P3.0 ; Set clock line back to '0'. RRC A ; Rotate carry bit into MSB of Acc. DJNZ R0,dtt_1 ; Loop for remaining bits. SETB DS1620_FLAG ; Configure for convert cycle next time. MOV temperature,A ; Save the temperature data. CLR while_dtt_flag ; Clear the while-dtt active flag. JB ai_tl_flag,dtt_3 ; If performing the AI Training/Learning algorithm, then don't do PID. LCALL pid ; We have the latest temperature, so now do the PID. SJMP dtt_3 ; Done. dtt_2: MOV A,#0EEH ; Tell the DS1620 to start a temperature conversion. LCALL dtt_4 ; Write the Protocol byte (CONVERT) to the DS1620. dtt_3: CLR P3.3 ; Deselect the DS1620. RET ; Exit. dtt_4: MOV R0,#08H ; R0 is bit counter. dtt_5: RRC A ; Rotate the LSBit to the Carry bit. MOV P3.2,C ; Move Carry bit to DATA READ (DQ) bit. LCALL clock_strobe ; Send the bit out to the display. DJNZ R0,dtt_5 ; Repeat for remaining bits. RET ; Return. ; -------------------------------------------------------------------------------------------------------------------------------------------------------------------- END