Minimum on, minimum off and interstage delay on a small DX stage start at five minutes each, which is a TON with a 300000 ms preset and the cheapest compressor protection in the panel. Leave them out and the short cycling costs more than any control strategy you could write will save. PLC building automation gets judged years later, by a facilities technician with no documentation, on habits like that one. These are the habits that make the difference on air handlers, chillers and pumps: naming, sequences kept in the code, staging that respects equipment, deliberate BACnet mapping, trends, and overrides that expire.
Examples use a CompactLogix 5380 on an air handling unit with a BACnet/IP gateway to the building system. The same rules apply on an S7-1200 or a native BAS controller.
Put the sequence of operation inside the code
The sequence of operation is the contract. It arrives as a Word document, it gets amended three times during commissioning, and then it disappears. Paste each clause into the routine description and each step into the rung comment that implements it.
Routine AHU1_Econ Description:
SOO 3.4 Economizer (per ASHRAE Guideline 36, adapted)
a) Economizer is available when OAT < RAT - 1.0 degC and no freeze alarm.
b) When available and cooling is required, modulate the outside air damper
from minimum position to 100 percent to hold supply air setpoint.
c) Mechanical cooling is inhibited until the OA damper has been above
95 percent for 5 minutes continuously.
d) On loss of the OAT sensor, damper goes to minimum position and the
economizer is disabled until the sensor is restored.
Revision: C, 14 Mar, after witness test comment 12
When clause (c) gets argued about in two years, the answer is in the controller next to the code that does it, with the revision that changed it. A document on a server nobody can find is not a record. Wider structure for this is in PLC program documentation.
Name points so the building can be read
Pick one scheme and never deviate. Equipment, then point, then function.
| Tag | Means | Type |
|---|---|---|
AHU1_SF_CMD | Supply fan start command | BOOL |
AHU1_SF_STS | Supply fan status from the current switch | BOOL |
AHU1_SF_SPD | Supply fan speed reference, percent | REAL |
AHU1_SAT | Supply air temperature | REAL |
AHU1_SAT_SP | Supply air temperature setpoint | REAL |
AHU1_MAD_CMD | Mixed air damper command, percent | REAL |
AHU1_CLG_VLV | Chilled water valve command, percent | REAL |
AHU1_ALM_FRZ | Freeze alarm | BOOL |
Command and status are separate points, always. A fan command with no status is a fan you cannot prove is running, and proving it is the whole basis of alarm and interlock logic. Build one UDT for a fan, one for a valve and one for a damper, then instantiate them per unit so AHU2 looks exactly like AHU1.
Stage equipment with timers, not with hope
Short cycling kills compressors and costs more than any control strategy saves. Every stage needs a minimum on time, a minimum off time, and an interstage delay.

Rung 12 Stage 2 cooling, DX unit
Clg_Demand Stg1_Run IS_Dly.DN Min_Off.TT Stg2_CMD
-----] [--------] [--------] [----------]/[------------( )---
Rung 13 Interstage delay starts when stage 1 has been proven
Stg1_Sts TON IS_Dly
-----] [-------------------------------------[ Preset 300000 ms ]
Rung 14 Minimum off time begins when stage 2 drops
Stg2_CMD TOF Min_Off
-----]/[-------------------------------------[ Preset 300000 ms ]
Five minutes is a common interstage and minimum off figure for small DX equipment, and the compressor manufacturer’s data overrides it. On a chiller with its own controller, do not stage it yourself. Send a demand signal and let the machine protect itself.
Lead and lag rotation belongs on runtime, not on a calendar:
(* Runtime based lead/lag, evaluated hourly *)
IF (P1_Runtime_Hr - P2_Runtime_Hr) > 100.0 THEN
Lead_Pump := 2;
ELSIF (P2_Runtime_Hr - P1_Runtime_Hr) > 100.0 THEN
Lead_Pump := 1;
END_IF;
(* Never swap while both are off and a start is pending *)
IF Pump_Start_Pending THEN
Lead_Pump := Lead_Pump_Last;
END_IF;
Map BACnet objects on purpose
The BAS integrator sees your controller as a list of objects. Decide what that list looks like rather than exporting every tag.
| Your point | BACnet object | Notes |
|---|---|---|
AHU1_SAT | Analog Input, AI:101 | Read only to the BAS, units degC |
AHU1_SAT_SP | Analog Value, AV:201 | Writable, with a sensible relinquish default |
AHU1_SF_CMD | Binary Output, BO:301 | Priority array applies |
AHU1_SF_STS | Binary Input, BI:302 | Read only |
AHU1_OCC_SCHED | Binary Value, BV:401 | Written by the building schedule |
AHU1_ALM_FRZ | Binary Input, BI:501 | Alarm points in their own instance range |
Two things to agree in writing before commissioning. First, the instance numbering plan: give each unit a block of one hundred and keep alarms in their own range, so adding a point later does not renumber the site. Second, the priority array. The BACnet priority array runs from 1 to 16 with 1 as the highest. Life safety sits at 1 and 2, minimum on and off at 6, manual operator at 8. Your program should write at a low priority such as 16, so an operator override at 8 wins and a life safety command beats both. Writing your normal control at priority 8 is the fastest way to lock out the people who have to run the building.
On MS/TP rather than IP, keep the MAC addresses contiguous from 0, set every device to the same baud rate, and do not let the token pass through a device that gets powered down at night.
Trend the things that get argued about
| Point type | Interval | Keep |
|---|---|---|
| Space and supply temperatures | 1 minute | 90 days |
| Setpoints and damper or valve commands | On change, plus 5 minutes | 90 days |
| Fan and pump status, alarms | On change | 1 year |
| Energy meters | 15 minutes | 3 years |
Trends are how you answer “it was too warm last Tuesday”. Without them you are guessing in a meeting with a facilities manager who is not guessing. Log setpoint and command together with the measured value, because a space that never reached setpoint and a space whose setpoint was changed by somebody look identical in a single trend line. Setting them up on the Rockwell side is covered in PLC trend chart settings and monitoring.
Set alarm limits that survive a Monday morning
- Put an on delay on every analog alarm. Fifteen minutes on a space temperature deviation, five on a supply air deviation.
- Alarm on deviation from setpoint, not on an absolute value. A 22 degC space is fine in an office and a fault in a cold store.
- Suppress during startup, unoccupied mode and morning warmup. A nuisance alarm at 4am trains people to ignore alarms.
- Give every alarm a deadband so it clears cleanly.
- Add a fan failure alarm from the mismatch of command and status, delayed by ten seconds so it ignores the start.
- Add runtime alarms at the filter change interval, based on differential pressure where you have the sensor.
Make overrides expire
Overrides are how a building gets fixed at 2am and how it quietly becomes uncontrolled for a year. Every manual override needs a timestamp, an owner and an expiry. Write a routine that collects every override bit into one array and shows a count on the home screen. When a technician is in the building and the count is not zero, someone can ask why.
Hardwired hand/off/auto switches in the starter panel are outside your logic, so you cannot expire them. Bring the auto position back as a digital input and alarm on it after a day. The rest of the interlock design follows the same patterns as PLC in HVAC control systems.
Meter the energy properly
Pulse outputs from kWh meters go to a discrete input with the filter set to match the pulse width, counted with a CTU and scaled by the meter constant. Modbus meters give you power, energy and power factor directly, which is easier and needs a comms watchdog so a dead meter does not read as zero consumption.
For thermal energy, kW = flow (l/s) x deltaT (K) x 4.19, using water properties. Handle the rollover: a 32 bit kWh register wraps, and the difference between two readings must account for it or your monthly report will show a negative building.
Commissioning checklist
- Point to point check every input and output, with a signature per point.
- Prove each safety and interlock: freezestat, high static, smoke, and the fan interlock on the heater.
- Run each sequence with the room at setpoint, above it and below it.
- Force the economizer through its enable and disable conditions with an OAT override, then remove the override.
- Stage every stage, and time the interstage delays with a watch.
- Fail each status input and confirm the alarm, then restore it.
- Verify every BACnet object reads and writes from the BAS, not just from your own laptop.
- Print the trend of a full occupancy cycle and attach it to the handover.
- Clear every force and override, then record the count as zero.
- Save the project, the point list and the sequence revision in the same folder as the O and M manual.
Field notes
The freezestat that was only in software. A retrofit had the low limit thermostat wired into a digital input and the coil pump started from logic. The first hard frost, the controller was in program mode for an edit and the coil split. A freeze protection device must break the fan circuit in hardware. Software sees it, software alarms on it, software does not get to be the only thing standing between a coil and a burst pipe.
Ten degrees of averaging error. A large AHU had one return air sensor in the corner of the plenum. The building looked warm on the graphic and cold in the offices. Stratification across the plenum was nearly ten degrees. Three averaging sensors in series solved a problem that six months of PID tuning had not.
The override that lasted fourteen months. A contractor put a chilled water valve to 100 percent at priority 8 to prove a coil during commissioning, then went home. It was found when the next year energy figures were queried. Overrides with no expiry and no summary screen are invisible.
Morning warmup that set the peak demand charge. Every unit in a building started at 05:00 and every electric reheat coil came on together. The demand peak on that one interval set the tariff for the month. Staggering the starts across twenty minutes cost nothing and saved more than the control upgrade.
Frequently asked questions
PLC or a native BAS controller for an HVAC job?
A PLC wins where you have machine-style interlocks, an existing plant standard, or unusual equipment. A native BAS controller wins on cost per point, built-in BACnet and standard graphics. Plenty of sites run a PLC on the central plant and BAS controllers on the terminal units.
How do I get BACnet out of a ControlLogix?
Through a gateway or a protocol module, since Logix speaks EtherNet/IP natively. Configure the object list on the gateway and keep the mapping table in the project folder. Protocol options are compared in PLC and SCADA communication protocols.
What loop tuning suits an air handler?
Slow. Supply air temperature loops are sluggish and noisy, so integral time is measured in minutes and derivative is usually zero. Tuning method and anti-windup are in implementing PID control.
Do I need ASHRAE Guideline 36?
You do not have to adopt it, and reading it is still worth a day. The sequences are specific enough to implement directly and they have already had the arguments you are about to have about economizer lockouts and reset schedules.
How many points should one controller carry?
Not a technical limit so much as an outage limit. Ask how much of the building goes dark when this controller fails, and split it when the answer is uncomfortable.
Next step
Take one air handler and rebuild its sequence properly, using the loop and interlock detail in PLC in HVAC control systems. Then get the trend and alarm layer working, starting with PLC trend chart settings and PLC alarm instructions, so the next person has the evidence instead of the argument.