Home / Tutorials / Arduino Tutorial / Soil NPK Sensor with Arduino: Pinout, RS485 Wiring & Code

Soil NPK Sensor with Arduino: Pinout, RS485 Wiring & Code

pcbway

Plants need more than water to grow well. They also need nutrients in the soil, especially nitrogen, phosphorus, and potassium. These three nutrients are commonly shortened to NPK, which is why this type of soil nutrient probe is called an NPK sensor.

In this tutorial, you will learn how to connect a soil NPK sensor to an Arduino UNO using an RS485 transceiver module. We will look at the sensor pinout, Arduino wiring, Modbus registers, and Arduino code for reading nitrogen, phosphorus, and potassium values.

The commands used in this tutorial match the register map found in many common JXBS-3001-NPK-RS-style soil sensors and compatible modules. However, there are many similar-looking NPK probes on the market, so always compare the register addresses, baud rate, supply voltage, and wire colors with the documentation for your particular sensor.

What Does an NPK Sensor Measure?

soil NPK sensor

An NPK sensor reports the amount of nitrogen (N), phosphorus (P), and potassium (K) in soil. These are three of the primary nutrients required by plants.

  • Nitrogen supports leaf and stem growth.
  • Phosphorus helps with root development, flowering, and fruiting.
  • Potassium contributes to water regulation, stress resistance, and overall plant health.

This makes NPK readings useful for soil monitoring, automated irrigation systems, greenhouse projects, and experiments involving fertilizer application. However, inexpensive electronic NPK probes should not automatically be treated as replacements for laboratory soil analysis. Their readings can depend on the sensor design, soil conditions,  moisture, temperature, calibration, and even how the probe is inserted. For hobby and monitoring projects, they are particularly useful for comparing changes in the same soil over time.

NPK Sensor Pinout and Wire Colors

A common RS485 NPK sensor has four wires: two for power and two for RS485 communication.

NPK Sensor Pinout

For the common JXBS-3001-NPK-RS-style sensor, the wiring is typically:

Wire Color Function Description
Brown VCC Sensor power positive
Black GND Sensor power negative
Yellow or Gray RS485-A RS485 differential line A
Blue RS485-B RS485 differential line B

Important: do not rely on wire color alone. There are many NPK sensor clones that look almost identical but use different supply voltages, communication settings, or wiring conventions. Check the label or documentation supplied with your sensor before applying power.

The common JXBS-3001-NPK-RS documentation specifies a 12–24 V supply, while some compatible sensors support a wider input-voltage range. Therefore, I recommend powering the probe from an external supply that matches the specification printed on your unit rather than assuming that the Arduino 5 V pin is suitable.

Types of NPK Sensors

There are several ways to determine nutrient concentrations in soil. Depending on the application, NPK measurement systems may use optical, electrochemical, or electrical sensing methods.

Optical NPK Sensors

Optical systems analyze how light interacts with soil or a prepared soil sample. Different chemical compositions affect how the sample absorbs or reflects certain wavelengths. These systems can provide detailed measurements, but they tend to be more complicated and expensive than the low-cost probes normally used with Arduino projects.

Electrochemical NPK Sensors

Electrochemical sensors use electrodes or chemically sensitive elements that react to ions in the sample. Some systems can detect specific nutrient ions more directly, although they generally require careful calibration.

Low-Cost Probe-Type NPK Sensors

The low-cost NPK sensors commonly sold for Arduino, ESP32, PLC, and agricultural monitoring systems contain metal probes that are inserted directly into soil. Manufacturers often do not publish enough information about the internal measurement algorithm to determine exactly how every inexpensive probe derives its individual N, P, and K values. For this reason, I would treat the reported readings as sensor measurements that should be verified and calibrated rather than assuming they provide the same chemical analysis as a laboratory test.

The sensor used in this tutorial sends its readings digitally through RS485.

Why the NPK Sensor Uses RS485

RS485 is a serial communication standard commonly used in industrial equipment and remote sensors. Compared with ordinary TTL serial communication, RS485 is much better suited for longer cables and electrically noisy environments.

RS485 communication between devices

RS485 uses differential signaling. Instead of transmitting data on one wire referenced to ground, it uses a pair of wires normally labeled A and B. Electrical noise that affects both lines tends to be rejected by the receiver, making RS485 useful when the sensor is several meters away from the controller.

comparison of logic signals including RS485

The Arduino UNO cannot connect directly to the sensor's RS485 A and B lines because its UART operates with TTL logic levels. Therefore, we need an RS485-to-TTL transceiver, such as a MAX485 module.

MAX485 RS485 transceiver module

Parts Required

For this project, you need:

  • Arduino UNO or compatible board
  • MAX485 or compatible RS485-to-TTL transceiver module
  • RS485 soil NPK sensor
  • External DC power supply suitable for your sensor
  • Jumper wires
  • USB cable for programming the Arduino

The Arduino and MAX485 can operate from 5 V. The NPK probe may require a higher supply voltage, so check its specification before applying power. When using an external sensor supply, connect its ground to the Arduino/MAX485 ground so that the electronics share a common reference where required by your transceiver setup.

NPK Sensor Arduino Wiring Diagram

The complete communication path is:

NPK Sensor → MAX485 → Arduino UNO

The MAX485 converts the differential RS485 signal from the sensor into UART-level data that the Arduino can read. Connect the MAX485 to the Arduino as follows:

MAX485 Pin Arduino UNO Function
VCC 5V Module power
GND GND Ground
DI D11 Arduino TX → RS485 driver
RO D10 RS485 receiver → Arduino RX
DE D2 Driver enable
RE D3 Receiver enable

Then connect the RS485 side to the sensor:

Sensor MAX485 / Supply
RS485-A A
RS485-B B
Sensor VCC External sensor supply +
Sensor GND External supply - / common GND

NPK sensor Arduino RS485 wiring diagram

On many modules, the RS485 terminals are labeled simply A and B. Other boards may use labels such as A+, B-, RS485+, or RS485-. If the sensor is powered correctly but never responds, one troubleshooting step is to verify the A/B polarity against the sensor documentation. Reversed A and B lines are a common cause of RS485 communication failure.

How the Arduino Requests NPK Data

The common sensor used for this project communicates using Modbus RTU over RS485. Instead of continuously transmitting measurements, the sensor waits for a request from the Arduino. The Arduino specifies which register it wants to read, and the sensor returns the value stored in that register.

A Modbus RTU request contains:

  • Slave address
  • Function code
  • Starting register address
  • Number of registers
  • CRC error-checking value

For the register map used in this tutorial, the important registers are:

Measurement Register Format Unit
Nitrogen 0x001E 16-bit unsigned value mg/kg
Phosphorus 0x001F 16-bit unsigned value mg/kg
Potassium 0x0020 16-bit unsigned value mg/kg

The registers are consecutive. Therefore, instead of sending three separate Modbus commands, we can request all three registers in one transaction.

The request frame is:

01 03 00 1E 00 03 65 CD

Breaking this down:

Bytes Meaning
01 Sensor slave address
03 Read Holding Registers
00 1E Start at register 0x001E
00 03 Read three registers
65 CD Modbus CRC, low byte first

The sensor address is commonly 0x01 by default, but this can be changed on some sensors. Likewise, many units use 9600 baud, while some compatible sensors may be configured for 2400 or 4800 baud. If the code does not work with your sensor, the baud rate and slave address are two of the first parameters to check.

Arduino Code for Reading the NPK Sensor

The following Arduino sketch requests nitrogen, phosphorus, and potassium in a single Modbus transaction. Unlike simpler examples that read only the low data byte, this version combines both bytes of each register. This is important because a Modbus register is 16 bits wide and a nutrient reading can exceed 255 mg/kg. The code also verifies the CRC before accepting the measurement.

#include <SoftwareSerial.h>

#define DE_PIN 2
#define RE_PIN 3

// SoftwareSerial(RX, TX)
SoftwareSerial RS485Serial(10, 11);

// Read three registers beginning at 0x001E:
// Nitrogen, Phosphorus and Potassium
const byte npkRequest[] = {
  0x01,       // Slave address
  0x03,       // Read Holding Registers
  0x00, 0x1E, // Starting register
  0x00, 0x03, // Read 3 registers
  0x65, 0xCD  // CRC low, CRC high
};

void setup() {
  Serial.begin(9600);
  RS485Serial.begin(9600);

  pinMode(DE_PIN, OUTPUT);
  pinMode(RE_PIN, OUTPUT);

  receiveMode();

  Serial.println("NPK Sensor Reading Started");
}

void loop() {
  uint16_t nitrogen;
  uint16_t phosphorus;
  uint16_t potassium;

  if (readNPK(nitrogen, phosphorus, potassium)) {

    Serial.print("Soil N: ");
    Serial.print(nitrogen);
    Serial.println(" mg/kg");

    Serial.print("Soil P: ");
    Serial.print(phosphorus);
    Serial.println(" mg/kg");

    Serial.print("Soil K: ");
    Serial.print(potassium);
    Serial.println(" mg/kg");

  } else {
    Serial.println("No valid NPK sensor response.");
  }

  Serial.println();
  delay(2000);
}

void transmitMode() {
  digitalWrite(RE_PIN, HIGH);
  digitalWrite(DE_PIN, HIGH);
}

void receiveMode() {
  digitalWrite(DE_PIN, LOW);
  digitalWrite(RE_PIN, LOW);
}

bool readNPK(uint16_t &nitrogen,
             uint16_t &phosphorus,
             uint16_t &potassium) {

  byte response[11];
  byte index = 0;

  // Remove any unread bytes from an earlier transaction
  while (RS485Serial.available()) {
    RS485Serial.read();
  }

  // Send Modbus request
  transmitMode();

  RS485Serial.write(npkRequest, sizeof(npkRequest));

  // SoftwareSerial write() is blocking on the UNO,
  // so transmission has completed when it returns.
  receiveMode();

  // Wait for the complete 11-byte response
  unsigned long startTime = millis();

  while ((millis() - startTime) < 500 &&
         index < sizeof(response)) {

    if (RS485Serial.available()) {
      response[index++] = RS485Serial.read();
    }
  }

  // Expected response length:
  // Address + Function + Byte count +
  // 6 data bytes + 2 CRC bytes = 11
  if (index != 11) {
    return false;
  }

  // Verify address, function and data length
  if (response[0] != 0x01 ||
      response[1] != 0x03 ||
      response[2] != 0x06) {
    return false;
  }

  // Verify Modbus CRC
  uint16_t receivedCRC =
      response[9] | ((uint16_t)response[10] << 8);

  uint16_t calculatedCRC =
      modbusCRC(response, 9);

  if (receivedCRC != calculatedCRC) {
    return false;
  }

  // Modbus sends each 16-bit register high byte first
  nitrogen =
      ((uint16_t)response[3] << 8) |
      response[4];

  phosphorus =
      ((uint16_t)response[5] << 8) |
      response[6];

  potassium =
      ((uint16_t)response[7] << 8) |
      response[8];

  return true;
}

uint16_t modbusCRC(const byte *data, byte length) {

  uint16_t crc = 0xFFFF;

  for (byte i = 0; i < length; i++) {

    crc ^= data[i];

    for (byte j = 0; j < 8; j++) {

      if (crc & 0x0001) {
        crc >>= 1;
        crc ^= 0xA001;
      } else {
        crc >>= 1;
      }
    }
  }

  return crc;
}

If your sensor uses a different baud rate, change:

RS485Serial.begin(9600);

to match the value specified in its documentation.

How the Arduino Code Works

The sketch uses SoftwareSerial so the Arduino can communicate with the MAX485 using pins D10 and D11 while keeping the hardware UART available for the Serial Monitor.

This line creates the RS485 serial port:

SoftwareSerial RS485Serial(10, 11);

D10 acts as RX and connects to the MAX485 RO pin. D11 acts as TX and connects to DI.

Switching the MAX485 Direction

RS485 is normally half-duplex, so the Arduino cannot transmit and receive through the MAX485 at the same time. The DE and RE pins control the direction:

void transmitMode() {
  digitalWrite(RE_PIN, HIGH);
  digitalWrite(DE_PIN, HIGH);
}

void receiveMode() {
  digitalWrite(DE_PIN, LOW);
  digitalWrite(RE_PIN, LOW);
}

The Arduino switches to transmit mode, sends the Modbus request, and then immediately switches back to receive mode.

Reading All Three Nutrients at Once

The request begins at register 0x001E and asks for three registers. The sensor therefore responds with six data bytes:

N high
N low
P high
P low
K high
K low

This lets us obtain all three readings with one RS485 transaction instead of making separate requests for N, P, and K.

Understanding the Modbus Response

A successful response should contain 11 bytes:

01 03 06 NH NL PH PL KH KL CRC_L CRC_H

Here:

  • 01 is the slave address.
  • 03 is the function code.
  • 06 means six data bytes follow.
  • NH NL> contain nitrogen.
  • PH PL contain phosphorus.
  • KH KL contain potassium.
  • The final two bytes contain the CRC.

For example, suppose nitrogen is returned as:

00 20

The 16-bit hexadecimal value 0x0020 equals 32 decimal, so the reported nitrogen concentration is:

32 mg/kg

The Arduino combines the high and low bytes with:

nitrogen =
    ((uint16_t)response[3] << 8) |
    response[4];

The same operation is performed for phosphorus and potassium. This is preferable to reading only response[4]. Reading only the low byte would work for values from 0 to 255 but would produce incorrect results once the measurement exceeds 255.

Why the Code Checks the Modbus CRC

The last two bytes in a Modbus RTU frame contain a CRC, or cyclic redundancy check. The sensor calculates the CRC from the data it sends. The Arduino calculates the same value after receiving the frame. If the two values do not match, at least one byte may have been corrupted during communication.

This is particularly useful with:

  • long RS485 cables,
  • electrically noisy environments,
  • poor connections, or
  • incorrect timing.

Instead of printing a potentially incorrect nutrient measurement, the example sketch rejects the entire response.

How to Insert the NPK Sensor into Soil

The electrical connection is only one part of obtaining repeatable measurements. Probe placement also matters. Choose a location without stones or other hard objects that could damage the metal probes. Push the sensor vertically into the soil and avoid moving it from side to side while inserting it. Sideways movement can create an air gap around the electrodes and change their contact with the soil.

Try to maintain approximately the same:

  • insertion depth,
  • soil compaction,
  • soil moisture, and
  • measurement location

when comparing readings. For a more representative result, take several measurements within a small area and calculate their average instead of depending on a single reading.

NPK Sensor in Soil

Testing the NPK Sensor with Real Soil

Before using the sensor for fertilizer decisions or automated control, I recommend checking how repeatable its readings are. A useful first experiment is to insert the probe into the same soil and collect several measurements without deliberately changing the soil.

Reading Nitrogen (mg/kg) Phosphorus (mg/kg) Potassium (mg/kg)
1
2
3
4
5
Average

Another useful experiment is to compare readings from the same soil at different moisture levels. This is important because the electrical properties of soil change considerably as water content changes. If the reported NPK values also change significantly even though the soil itself has not changed, moisture is clearly influencing your sensor's output. If possible, the strongest calibration test would be to compare the sensor against a laboratory soil analysis or another known reference.

How Accurate Are Low-Cost NPK Sensors?

This is one area where I would be cautious. A low-cost RS485 NPK probe can be useful for projects, monitoring trends, and comparing soil conditions. However, that does not mean its output has the same accuracy or selectivity as a laboratory chemical analysis. Several factors can influence the readings:

  • soil moisture,
  • soil composition,
  • salinity,
  • temperature,
  • probe contact,
  • calibration, and
  • differences between sensor models.

For an Arduino project, I would initially use the measurements as relative values. For example, determine whether the measured value rises or falls after a controlled change rather than immediately assuming that the absolute number is laboratory-grade. If accurate nutrient concentration is important, compare the probe with a known soil test.

Calibrating the NPK Sensor

Some NPK sensors arrive factory-calibrated, but that does not guarantee that every sensor will produce accurate results in every soil type. A practical calibration approach is to:

  1. Obtain a reference soil measurement.
  2. Measure the same sample with the NPK sensor.
  3. Repeat the measurement several times.
  4. Calculate the difference between the reference and sensor readings.
  5. Apply a correction factor only after you have enough data to show a repeatable relationship.

Avoid calibrating from only one measurement. If possible, compare several samples covering low, medium, and high nutrient concentrations. Also keep soil moisture reasonably consistent during calibration.

Troubleshooting an NPK Sensor with Arduino

If the Serial Monitor shows no response, zeros, or obviously incorrect values, check the following.

No Response from the Sensor

  • Confirm that the probe is receiving its required supply voltage.
  • Verify the RS485 A and B connections.
  • Check that the sensor ground and controller ground are connected correctly for your setup.
  • Confirm the sensor slave address.
  • Try the baud rates listed in the sensor documentation.
  • Make sure DE and RE return to receive mode after transmission.

CRC Errors

CRC failures indicate that the received frame does not match the checksum included by the sensor.

Check:

  • loose wiring,
  • very long unshielded cables,
  • electrical noise,
  • incorrect baud rate, and
  • poor RS485 termination on long buses.

Sensor Responds but Values Look Wrong

First confirm that your sensor actually uses:

0x001E = Nitrogen
0x001F = Phosphorus
0x0020 = Potassium

A physically similar sensor may use an entirely different register map. Also confirm that the returned values are 16-bit integers and whether the manufacturer applies any scaling factor.

Values Change When the Soil Gets Wetter

Do not immediately assume that the nutrient concentration has changed. Changing soil moisture also changes the electrical environment around the probe. Repeat measurements under controlled moisture conditions before concluding small differences.

Using Multiple NPK Sensors on One RS485 Bus

One advantage of RS485 is that several sensors can share the same A and B communication wires. However, every sensor on the bus must have a unique Modbus slave address.

For example:

Sensor 1: address 0x01
Sensor 2: address 0x02
Sensor 3: address 0x03

The Arduino then sends the same register request to a different slave address depending on which sensor it wants to read. If two sensors have the same address and reply simultaneously, their responses will collide, and the Arduino will receive corrupted data. Long RS485 networks may also require suitable termination resistors and careful cable routing.

Using an NPK + pH + Moisture Sensor

Some soil sensors combine several measurements in the same probe. A multi-parameter sensor may provide:

  • nitrogen,
  • phosphorus,
  • potassium,
  • soil moisture,
  • temperature,
  • electrical conductivity, and
  • pH.

These sensors often use the same RS485/Modbus communication method but assign each measurement to a different register. Do not assume that the register map from the three-parameter NPK probe will work with a 5-in-1 or 7-in-1 sensor. Get the complete Modbus register table for your exact sensor and modify the request accordingly.

Using the NPK Sensor with ESP32

The same RS485 NPK probe can also be connected to an ESP32. The ESP32 is particularly convenient because it has additional hardware UARTs, so you do not need to rely on SoftwareSerial. You can also use its Wi-Fi capability to send the readings to a dashboard, database, or web application. I have a separate guide showing how to do this: How to Use an NPK Soil Sensor with ESP32

Frequently Asked Questions

What is an NPK sensor?

An NPK sensor reports nitrogen, phosphorus, and potassium levels in soil. These readings can be used for soil monitoring, plant experiments, greenhouse systems, and fertilizer-related projects.

How do I connect an NPK sensor to Arduino?

Most low-cost digital NPK probes use RS485. Connect the sensor's A and B lines to an RS485 transceiver such as the MAX485, then connect the MAX485's TTL serial pins to the Arduino.

Can an Arduino connect directly to an RS485 NPK sensor?

No. The Arduino UNO uses TTL-level UART communication, while the sensor uses differential RS485 signaling. You need an RS485 transceiver between them.

What is the NPK sensor pinout?

For many common JXBS-3001-style sensors, brown is power positive, black is ground, yellow or gray is RS485-A, and blue is RS485-B. Always check your sensor documentation because clones may use different wire colors.

Which Modbus registers contain NPK data?

For the sensor register map used in this tutorial:

0x001E = Nitrogen
0x001F = Phosphorus
0x0020 = Potassium

These are 16-bit register values reported in mg/kg.

What baud rate does an NPK sensor use?

The common sensor used by this example normally communicates at 9600 baud. However, compatible sensors may use 2400, 4800, or another configured rate. Check the documentation supplied with your sensor.

Can I use an Arduino Nano or Mega?

Yes. An Arduino Nano can use essentially the same approach as the UNO. An Arduino Mega is even more convenient because it provides additional hardware serial ports. This lets you communicate with the RS485 transceiver without using SoftwareSerial.

Why does my NPK sensor not respond?

The most common causes are incorrect supply voltage, reversed A/B lines, the wrong baud rate, an incorrect Modbus address, the wrong register map, or improper switching of the RS485 transceiver between transmit and receive modes.

Can I connect several NPK sensors to one Arduino?

Yes. RS485 supports multiple devices on one bus. Each sensor must have a different Modbus slave address.

How accurate are cheap NPK sensors?

Treat inexpensive soil NPK sensors as practical monitoring devices rather than laboratory instruments. Their readings can be affected by sensor quality, moisture, soil composition, temperature, calibration, and probe placement. For important agricultural decisions, compare the sensor against a reference soil test.

Do I need to calibrate an NPK sensor?

Calibration is recommended if you need meaningful absolute measurements. Compare the sensor against known soil test results under controlled conditions and collect several samples before applying any correction factor.