---
title: "CoolPro — Modbus RTU Communications Protocol"
revision: "1.0.1"
publisher: AERL (Australian Energy Research Laboratories)
url: https://www.aerl.com.au/docs/coolpro-rs485-modbus-protocol
pdf: https://www.aerl.com.au/documents/protocols/AERL_COOLPRO_RS485_Modbus_Protocol_REV_101.pdf
description: "RS485 Modbus RTU communications protocol reference for the CoolPro CP30 cathodic protection controller — communication parameters, register map, and example transactions."
---

# CoolPro — Modbus RTU Communications Protocol

*Rev 1.0.1. Markdown copy of the AERL document at https://www.aerl.com.au/docs/coolpro-rs485-modbus-protocol; the PDF (https://www.aerl.com.au/documents/protocols/AERL_COOLPRO_RS485_Modbus_Protocol_REV_101.pdf) is the controlled version.*

RS485 / Modbus Communications

# CoolPro

Modbus RTU Communications Protocol

**Doc · CP-MODBUS-RTU**

Standard Modbus RTU

Physical RS485 · RJ45

Default baud 9600 bps

Frame 8·N·1

Default address 40

CRC CRC-16 (LSB first)

| | |
|---|---|
| Document | CP-MODBUS-RTU |
| Revision | 1.0.1 |
| Effective | 11 / 2026 |
| Product | CoolPro |
| Audience | Integrators |
| Format | A4 · 8 pages |
| Language | English (en-AU) |

## Chapter 01 Bus, Connection & Settings

The CoolPro provides access to real-time measurements and device information via the standard **Modbus RTU** protocol over RS485.

### Communication Parameters

| Parameter | Value |
|---|---|
| Baud rate | 9600 (default); configurable: 9600 / 19200 / 38400 / 57600 / 115200 |
| Data bits | 8 |
| Stop bits | 1 |
| Parity | None |
| Device address | 40 (default); configurable 1–247 |
| CRC | Modbus CRC-16 (transmitted LSB first) |

### Frame Timing

Modbus RTU frames are delimited by idle time on the bus: a frame is treated as complete once the bus has been silent for the inter-frame gap period.

The CoolPro uses a fixed inter-frame gap of approximately **8 ms**, independent of the configured baud rate. This is comfortably wider than the 3.5-character silent interval required by the Modbus specification at every supported baud rate, so a standard-compliant master will interoperate without adjustment.

### Physical Connection

The CoolPro uses an 8-pin RJ45 connector for its RS485 interface.

![RJ45 connector viewed from the front, with the eight contacts numbered 1 through 8 from left to right](https://www.aerl.com.au/docs/_assets/assets/images/coolpro/aerl-coolpro-rj45-pinout.png)

*RJ45 connector viewed from the front — contacts numbered 1 to 8, left to right.*

| Pin | Signal |
|---|---|
| 3 | RS485-A (non-inverting) |
| 6 | RS485-B (inverting) |
| 8 | GND |

All other pins are unused.

### Chapter 01 · continued Network Topology

The Modbus network is a linear bus, with short stubs branching from ‘T’ connectors on the main backbone to each device. Terminate the bus at both ends with a **120 Ω** resistor between the RS485-A and RS485-B signals: at the master (many masters have a built-in or switchable terminator) and at the far end of the backbone.

![Modbus RS485 network topology: a master daisy-chained to multiple slave devices on a two-wire bus, each device exposing A, B and G terminals, with a 120 ohm termination resistor fitted across A and B at the far end of the backbone](https://www.aerl.com.au/docs/_assets/assets/images/coolpro/aerl-coolpro-modbus-topology.png)

*Linear two-wire RS485 bus — master daisy-chained to slave devices (A / B / G), with 120 Ω termination across A and B at the far end of the backbone (the master end is terminated at the master).*

## Chapter 02 Supported Function Codes

0x03 Read Holding Registers

Read one or more configuration registers.

Request [Device ID] [0x03] [Start Address High] [Start Address Low] [Quantity High] [Quantity Low] [CRC Low] [CRC High] Response [Device ID] [0x03] [Byte Count] [Data…] [CRC Low] [CRC High]

| Frame | Bytes | Notes |
|---|---|---|
| Request | 28 03 00 00 00 01 [CRC] | Read 1 register starting at 0 (device address) |
| Response | 28 03 02 00 28 [CRC] | Byte count = 2, value = 40 (0x0028) |
| Request | 28 03 00 00 00 03 [CRC] | Read 3 registers starting at 0 |
| Response | 28 03 06 00 28 00 00 00 00 [CRC] | Byte count = 6, three register values |

0x04 Read Input Registers

Read one or more input registers containing measurements or device information.

Request [Device ID] [0x04] [Start Address High] [Start Address Low] [Quantity High] [Quantity Low] [CRC Low] [CRC High] Response [Device ID] [0x04] [Byte Count] [Data…] [CRC Low] [CRC High]

| Frame | Bytes | Notes |
|---|---|---|
| Request | 28 04 00 00 00 01 [CRC] | Read 1 register starting at 0 (input voltage in mV) |
| Response | 28 04 02 5F B4 [CRC] | Byte count = 2, value = 24500 (0x5FB4 = 24.5 V) |
| Request | 28 04 00 00 00 04 [CRC] | Read 4 registers starting at 0 (Vin, Iin, Vout, Iout) |
| Response | 28 04 08 5F B4 0C B2 5D C0 0C 80 [CRC] | Vin = 24.5 V, Iin = 3.25 A, Vout = 24.0 V, Iout = 3.20 A |

0x06 Write Single Register

Write a configuration register (device address, baud rate, or reset trigger).

Request [Device ID] [0x06] [Register High] [Register Low] [Value High] [Value Low] [CRC Low] [CRC High] Response [Device ID] [0x06] [Register High] [Register Low] [Value High] [Value Low] [CRC Low] [CRC High]

| Frame | Bytes | Notes |
|---|---|---|
| Request | 28 06 00 00 00 2A [CRC] | Write device address = 42 |
| Response | 28 06 00 00 00 2A [CRC] | Echo confirms write |

## Chapter 03 Modbus Register Map

### Addressing

Register **reference numbers** (4xxxx for holding registers, 3xxxx for input registers) are a documentation convention only. The value placed on the wire is the zero-based **PDU address**, shown in the *Offset* column — that is, on-wire address = reference number − 40001 (holding) or − 30001 (input) = the offset.

- Holding register **40001** is addressed on the wire as 0x0000 (function 0x03 / 0x06).
- Input register **30001** is addressed on the wire as 0x0000 (function 0x04).

The function code — not the reference range — selects the address space, so the same on-wire address 0x0000 reads the device address under 0x03 and the input voltage under 0x04.

### Chapter 03 · continued Holding Registers (FC 0x03, 0x06)

Configuration registers (read / write). **All values are uint16.**

| Address | Offset | Description | Range | Notes |
|---|---|---|---|---|
| 40001 | 0 | Device Address | 1–247 | Takes effect after reset |
| 40002 | 1 | Baud Rate Index | 0–4 | 0 = 9600, 1 = 19200, 2 = 38400, 3 = 57600, 4 = 115200; takes effect after reset |
| 40003 | 2 | Reset Command | — | Write 0xAA55 to trigger a reset; always reads 0 |

> Reset register read-back
>
> Register 40003 is a write-only command trigger. A read always returns **0** regardless of the value last written — this is expected behaviour, not a fault. The written value initiates the reset and is never stored.

### Input Registers (FC 0x04) — Live Telemetry (Offsets 0–7)

**All values are uint16 with milliunit scaling.**

| Address | Offset | Description | Unit | Conversion |
|---|---|---|---|---|
| 30001 | 0 | Input Voltage | mV | voltage_v = value / 1000 |
| 30002 | 1 | Input Current | mA | current_a = value / 1000 |
| 30003 | 2 | Output Voltage | mV | voltage_v = value / 1000 |
| 30004 | 3 | Output Current | mA | current_a = value / 1000 |
| 30005 | 4 | Temperature | m°C | temp_c = value / 1000 |
| 30006 | 5 | Uptime (Low Word) | s | Low 16 bits of uptime |
| 30007 | 6 | Uptime (High Word) | s | High 16 bits of uptime |
| 30008 | 7 | Status Flags | — | Bit field (see below) |

### Status Flags Bit Field (Register 30008)

A 16-bit bit field. Each bit reports a specific system condition and can be set or cleared independently.

| Bit | Hex | Name | Description |
|---|---|---|---|
| 0 | 0x0001 | System Startup | Device is initialising (cleared once startup completes) |
| 1 | 0x0002 | Daily Reset | Daily reset has occurred (uptime counter reset) |
| 2 | 0x0004 | Input Measurement Fault | Fault communicating with the input measurement sensor |
| 3 | 0x0008 | Output Measurement Fault | Fault communicating with the output measurement sensor |
| 4 | 0x0010 | Calibration Invalid | Stored calibration data failed validation |
| 5 | 0x0020 | Calibration Missing | No calibration data stored |
| 6 | 0x0040 | Temperature Sensor Fault | Fault communicating with the temperature sensor |
| 7–15 | — | Reserved | Reserved for future use (currently 0) |

### Chapter 03 · continued Device Information Registers (Offsets 100–107)

| Address | Offset | Description | Type | Notes |
|---|---|---|---|---|
| 30101 | 100 | Serial Number Low | uint16 | Low 16 bits |
| 30102 | 101 | Serial Number High | uint16 | High 16 bits |
| 30103 | 102 | Hardware Revision | uint16 | e.g. 1, 2, 3 |
| 30104 | 103 | Firmware Major Version | uint16 | e.g. 1 |
| 30105 | 104 | Firmware Minor Version | uint16 | e.g. 0 |
| 30106 | 105 | Firmware Patch Version | uint16 | e.g. 0 |
| 30107 | 106 | Manufacture Date Low | uint16 | Unix timestamp low word |
| 30108 | 107 | Manufacture Date High | uint16 | Unix timestamp high word |

## Chapter 04 Data Encoding

#### 16-bit registers

- **Byte order:** big-endian (MSB first).
- **Example:** value 24500 (0x5FB4) is transmitted as [0x5F, 0xB4] .

#### Milliunit scaling

All measurements use **milliunits** so values carry as integers without floating point:

- **Voltage:** millivolts (mV) — divide by 1000 for volts.
- **Current:** milliamps (mA) — divide by 1000 for amps.
- **Temperature:** millidegrees Celsius (m°C) — divide by 1000 for °C.

For example, an input-voltage reading of 24500 is 24.5 V, and a temperature reading of 25800 is 25.8 °C.

#### 32-bit values

Uptime, serial number and manufacture date span two uint16 registers:

- **Split:** low word first, high word second.
- **Byte order:** big-endian within each register.

Example — value 70000 (0x00011170) is stored as:

| Register | Hex | Value |
|---|---|---|
| N (low) | 0x1170 | 4464 |
| N+1 (high) | 0x0001 | 1 |

Reconstruct: (high << 16) | low = 70000. All values are transmitted as integers; no floating-point encoding is used.

### Conversion Examples

| Quantity | Register value | Meaning |
|---|---|---|
| 24.5 V | 24500 | 24500 mV |
| 3.25 A | 3250 | 3250 mA |
| 25.8 °C | 25800 | 25800 m°C |
| Uptime 70000 s | offset 5 = 4464, offset 6 = 1 | Combined: 0x0001_1170 |

### Chapter 04 · continued CRC-16

Every frame ends with a 16-bit CRC computed over all preceding bytes using polynomial 0xA001 with an initial value of 0xFFFF, and transmitted **low byte first**.

| Frame (without CRC) | CRC-16 | On the wire (CRC appended, low byte first) |
|---|---|---|
| 28 04 00 00 00 01 | 0x3336 | 28 04 00 00 00 01 36 33 |
| 28 04 02 5F B4 | 0x71DD | 28 04 02 5F B4 DD 71 (response) |

## Chapter 05 Exception Codes

Standard Modbus exception responses:

| Code | Name | Description |
|---|---|---|
| 0x01 | Illegal Function | Function code not supported |
| 0x02 | Illegal Data Address | Register address invalid |
| 0x03 | Illegal Data Value | Value out of range |
| 0x04 | Slave Device Failure | Device cannot process the request |

Exception response [Device ID] [Function Code + 0x80] [Exception Code] [CRC Low] [CRC High]

## Chapter 06 Example Transactions

All requests are addressed to device ID 0x28 (40). CRC bytes are shown as [CRC]; worked CRC values are given in § Data encoding.

### Chapter 06 · continued Example Transactions — Telemetry & Identity

| Frame | Bytes | Notes |
|---|---|---|
| Read input voltage — FC 0x04, offset 0 | Read input voltage — FC 0x04, offset 0 | Read input voltage — FC 0x04, offset 0 |
| Request | 28 04 00 00 00 01 [CRC] | 8 bytes total |
| Response | 28 04 02 5F B4 [CRC] | 7 bytes; value 0x5FB4 = 24500 mV = 24.5 V |
| Read input current — FC 0x04, offset 1 | Read input current — FC 0x04, offset 1 | Read input current — FC 0x04, offset 1 |
| Request | 28 04 00 01 00 01 [CRC] | Read 1 register at offset 1 |
| Response | 28 04 02 0C B2 [CRC] | Value 0x0CB2 = 3250 mA = 3.25 A |
| Read temperature — FC 0x04, offset 4 | Read temperature — FC 0x04, offset 4 | Read temperature — FC 0x04, offset 4 |
| Request | 28 04 00 04 00 01 [CRC] | Read 1 register at offset 4 |
| Response | 28 04 02 64 C8 [CRC] | Value 0x64C8 = 25800 m°C = 25.8 °C |
| Read serial number — FC 0x04, offsets 100–101 (split low / high word) | Read serial number — FC 0x04, offsets 100–101 (split low / high word) | Read serial number — FC 0x04, offsets 100–101 (split low / high word) |
| Request | 28 04 00 64 00 02 [CRC] | Option 1 — read both registers at offset 100 |
| Response | 28 04 04 30 39 00 00 [CRC] | Byte count = 4; Low = 0x3039, High = 0x0000 |
| Request | 28 04 00 64 00 01 [CRC] | Option 2 — read offset 100 individually |
| Response | 28 04 02 30 39 [CRC] | Low word = 0x3039 = 12345 |
| Request | 28 04 00 65 00 01 [CRC] | Read offset 101 individually |
| Response | 28 04 02 00 00 [CRC] | High word = 0x0000. Reconstruct: serial = 12345 |

### Example Transactions — Configuration Writes

| Frame | Bytes | Notes |
|---|---|---|
| Read device address — FC 0x03, holding register 0 | Read device address — FC 0x03, holding register 0 | Read device address — FC 0x03, holding register 0 |
| Request | 28 03 00 00 00 01 [CRC] | Read 1 register at offset 0 |
| Response | 28 03 02 00 28 [CRC] | Value 0x0028 = 40 (device address) |
| Write device address — FC 0x06, holding register 0 | Write device address — FC 0x06, holding register 0 | Write device address — FC 0x06, holding register 0 |
| Request | 28 06 00 00 00 2A [CRC] | New device address = 42 (0x002A) |
| Response | 28 06 00 00 00 2A [CRC] | Echo. Changes take effect after a device reset |
| Trigger device reset — FC 0x06, holding register 2 | Trigger device reset — FC 0x06, holding register 2 | Trigger device reset — FC 0x06, holding register 2 |
| Request | 28 06 00 02 AA 55 [CRC] | Reset trigger value 0xAA55 |
| Response | 28 06 00 02 AA 55 [CRC] | Echo. Device resets immediately after sending the response |

## Chapter 07 Revision History

| Rev. | Date | Change |
|---|---|---|
| 1 | 2026-06-08 | Initial customer release |
| 1.0.1 | 2026-11-08 | Bus termination clarified (both ends: the master and the far end of the backbone). |
