Example Code for Arduino-Residual Chlorine Monitoring

This project shows how to connect the RS485 residual chlorine sensor to an Arduino development board, establish communication via ModBus-RTU protocol, and realize real-time monitoring of residual chlorine data changes. Users will learn RS485 to UART conversion, ModBus-RTU data reading, and serial port data display.

Hardware Preparation

Software Preparation

Wiring Diagram

If the power of the RS485 device is small and the required current is less than 12V-160mA, the RS485 to UART signal conversion module does not require a 12V external power supply, making wiring more convenient.

Other Preparation Work

  1. Ensure the sensor's probe protective cap has remaining protective liquid; if white crystals form around the cap, pour them back into the protective liquid.
  2. If the sensor hasn't been used for over 3 days, polish the electrode metal ring with 1000+ grit fine sandpaper before use.
  3. Confirm the RS485 adapter module's wiring matches the sensor's A/B lines (Yellow line = 485-A, Blue line = 485-B).

Sample Code

#include <SoftwareSerial.h>
SoftwareSerial mySerial(2, 3);                                         //TX,RX
uint8_t Com[8] = { 0x01, 0x03, 0x00, 0x00, 0x00, 0x01, 0x84, 0x0A };   //Residual Chlorine
float CI2;

void setup() {
  Serial.begin(9600);
  mySerial.begin(4800);
}
void loop() {
  Residual_Chlorine();
  Serial.print("Residual Chlorine = ");
  Serial.print(CI2, 1);
  Serial.println(" mg/L");
  delay(1000);
}

void Residual_Chlorine(void) {
  uint8_t Data[12] = { 0 };
  uint8_t ch = 0;
  bool flag = 1;
  long timeStart = millis();
  long timeStart1 = 0;
  while (flag) {

    if ((millis() - timeStart1) > 100) {
      while (mySerial.available() > 0) {
        mySerial.read();
      }
      mySerial.write(Com, 8);
      timeStart1 = millis();
    }

    if ((millis() - timeStart) > 1000) {
      Serial.println("Time out");
      return -1;
    }

    if (readN(&ch, 1) == 1) {
      if (ch == 0x01) {
        Data[0] = ch;
        if (readN(&ch, 1) == 1) {
          if (ch == 0x03) {
            Data[1] = ch;
            if (readN(&ch, 1) == 1) {
              if (ch == 0x02) {
                Data[2] = ch;
                if (readN(&Data[3], 4) == 4) {
                  if (CRC16_2(Data, 5) == (Data[5] * 256 + Data[6])) {
                    CI2 = (Data[3] * 256 + Data[4]) / 100.0;
                    flag = 0;
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}


uint8_t readN(uint8_t *buf, size_t len) {
  size_t offset = 0, left = len;
  int16_t Tineout = 500;
  uint8_t *buffer = buf;
  long curr = millis();
  while (left) {
    if (mySerial.available()) {
      buffer[offset] = mySerial.read();
      offset++;
      left--;
    }
    if (millis() - curr > Tineout) {
      break;
    }
  }
  return offset;
}

unsigned int CRC16_2(unsigned char *buf, int len) {
  unsigned int crc = 0xFFFF;
  for (int pos = 0; pos < len; pos++) {
    crc ^= (unsigned int)buf[pos];
    for (int i = 8; i != 0; i--) {
      if ((crc & 0x0001) != 0) {
        crc >>= 1;
        crc ^= 0xA001;
      } else {
        crc >>= 1;
      }
    }
  }

  crc = ((crc & 0x00ff) << 8) | ((crc & 0xff00) >> 8);
  return crc;
}

Result

The serial monitor displays the Residual Chlorine value collected by the sensor.(It is normal for residual chlorine levels in tap water to be low in some cities, making it impossible to measure residual chlorine data.)

Additional Information

  • The sensor is factory-calibrated and ready to use without secondary calibration.
  • If the serial monitor shows "Time out", check the wiring, device address, and baud rate settings.

Was this article helpful?

TOP