In this tutorial, we will learn how to interface Arduino with a TDS sensor to measure water quality. TDS sensors measure the concentration of total dissolved solids in a solution, which measures water purity.
Water is more important for life, and the quality of drinking water matters. Pure water contains minerals, while distilled water is devoid of any elements. The taste of water, whether bitter or sweet, is influenced by added minerals and impurities. Total Dissolved Solids (TDS) in water define its taste and composition.
The higher the TDS level, the more impurities are present in the water. By the end of this tutorial, you will have a better understanding of how TDS sensors work and how to interface with them using an Arduino. Checkout our recent post Arduino Flow Sensor Tutorial: How to Measure Liquid Flow
Required Material
- Arduino Nano or UNO
- TDS sensor
- Jumper wires
- USB cable
- Breadboard
What is a TDS sensor
A TDS meter measures total dissolved solids such as salts, minerals, and metals in water. As these solids increase, water conductivity increases, helping the calculation of total dissolved solids in ppm (mg/L).
However, while this acts as a good indicator for monitoring water quality, it’s important to note that it doesn’t detect water impurities.
TDS meters are good for monitoring water quality in different locations like pools, aquariums, hydroponics, and water purifiers.
TDS chart
TDS sensor for Arduino
TDS Sensor Specs
- Wide Voltage Input: Accepts 3.3~5V power input.
- Good Compatibility Output: Offers 0~2.3V analog signal output
- Waterproof Probe: Provides improved durability.
- Ease of Use: Arduino compatible, allows easy plug-and-play.
TDS Meter:
-
- Input Voltage: DC 3.3 ~ 5V
- Output Voltage: 0 ~ 2.3V
- Working Current: 3 ~ 6mA
- TDS Measurement Range: 0 ~ 1000ppm
- TDS Measurement Accuracy: ±10% F.S. (25 ℃)
- Module Interface: XH2.54-3P
- Electrode Interface: XH2.54-2P
- Â TDS Probe:
-
- Number of Needles: 2
- Total Length: 60cm
- Connection Interface: XH2.54-2P
- Color: White
- Waterproof Probe for added durability
TDS Sensor Pinout
Interfacing TDS Sensor With Arduino
We will interface the TDS sensor with Arduino and display the TDS value on an OLED Display. TDS sensor fullforms Total Dissolved Solids, and it is a measure of the dissolved minerals in water.
Circuit Connection:
TDS Sensor Pin | Arduino Pin |
---|---|
GND | GND |
VCC | 3.3V |
Data | A0 (or any other Arduino analog pin) |
Example Arduino TDS Sensor Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
#define TdsSensorPin A0 #define VREF 5.0 // analog reference voltage(Volt) of the ADC #define SCOUNT 30 // sum of sample point int analogBuffer[SCOUNT]; // store the analog value in the array, read from ADC int analogBufferTemp[SCOUNT]; int analogBufferIndex = 0,copyIndex = 0; float averageVoltage = 0,tdsValue = 0,temperature = 25; void setup() { Serial.begin(115200); pinMode(TdsSensorPin,INPUT); } void loop() { static unsigned long analogSampleTimepoint = millis(); if(millis()-analogSampleTimepoint > 40U) //every 40 milliseconds,read the analog value from the ADC { analogSampleTimepoint = millis(); analogBuffer[analogBufferIndex] = analogRead(TdsSensorPin); //read the analog value and store into the buffer analogBufferIndex++; if(analogBufferIndex == SCOUNT) analogBufferIndex = 0; } static unsigned long printTimepoint = millis(); if(millis()-printTimepoint > 800U) { printTimepoint = millis(); for(copyIndex=0;copyIndex<SCOUNT;copyIndex++) analogBufferTemp[copyIndex]= analogBuffer[copyIndex]; averageVoltage = getMedianNum(analogBufferTemp,SCOUNT) * (float)VREF/ 1024.0; // read the analog value more stable by the median filtering algorithm, and convert to voltage value float compensationCoefficient=1.0+0.02*(temperature-25.0); //temperature compensation formula: fFinalResult(25^C) = fFinalResult(current)/(1.0+0.02*(fTP-25.0)); float compensationVolatge=averageVoltage/compensationCoefficient; //temperature compensation tdsValue=(133.42*compensationVolatge*compensationVolatge*compensationVolatge - 255.86*compensationVolatge*compensationVolatge + 857.39*compensationVolatge)*0.5; //convert voltage value to tds value //Serial.print("voltage:"); //Serial.print(averageVoltage,2); //Serial.print("V "); Serial.print("TDS Value:"); Serial.print(tdsValue,0); Serial.println("ppm"); } } int getMedianNum(int bArray[], int iFilterLen) { int bTab[iFilterLen]; for (byte i = 0; i<iFilterLen; i++) bTab[i] = bArray[i]; int i, j, bTemp; for (j = 0; j < iFilterLen - 1; j++) { for (i = 0; i < iFilterLen - j - 1; i++) { if (bTab[i] > bTab[i + 1]) { bTemp = bTab[i]; bTab[i] = bTab[i + 1]; bTab[i + 1] = bTemp; } } } if ((iFilterLen & 1) > 0) bTemp = bTab[(iFilterLen - 1) / 2]; else bTemp = (bTab[iFilterLen / 2] + bTab[iFilterLen / 2 - 1]) / 2; return bTemp; } |
Test Summary
- Code Upload: Code successfully uploaded.
- Open serial monitor at 115200 baud rate.
- Setup: Place the TDS probe in water for measurement.
Result: Monitor displays TDS value.
Calibrate TDS Measurement Accuracy with Arduino
In the basic tutorial, measuring TDS in liquids is easy but can have errors due to differences in probes and control boards, and lack of temperature balance.
For accuracy, calibrate before measuring. Adding a temp sensor helps. TDS is usually half the EC value:
TDS = EC / 2
It’s the same diagram as the basic. For calibration, use a known solution like 1413us/cm buffer (around 707 ppm as TDS). Use a TDS pen if no buffer.
Download and install the DFRobot Gravity TDS Sensor Library for Arduino.
Sample Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
/*************************************************** DFRobot Gravity: Analog TDS Sensor/Meter <https://www.dfrobot.com/wiki/index.php/Gravity:_Analog_TDS_Sensor_/_Meter_For_Arduino_SKU:_SEN0244> *************************************************** This sample code shows how to read the tds value and calibrate it with the standard buffer solution. 707ppm(1413us/cm)@25^c standard buffer solution is recommended. Created 2018-1-3 By Jason <jason.ling@dfrobot.com@dfrobot.com> GNU Lesser General Public License. See <http://www.gnu.org/licenses/> for details. All above must be included in any redistribution. ****************************************************/ /***********Notice and Trouble shooting*************** 1. This code is tested on Arduino Uno with Arduino IDE 1.0.5 r2 and 1.8.2. 2. Calibration CMD: enter -> enter the calibration mode cal:tds value -> calibrate with the known tds value(25^c). e.g.cal:707 exit -> save the parameters and exit the calibration mode ****************************************************/ #include <EEPROM.h> #include "GravityTDS.h" #define TdsSensorPin A0 GravityTDS gravityTds; float temperature = 25,tdsValue = 0; void setup() { Serial.begin(115200); gravityTds.setPin(TdsSensorPin); gravityTds.setAref(5.0); //reference voltage on ADC, default 5.0V on Arduino UNO gravityTds.setAdcRange(1024); //1024 for 10bit ADC;4096 for 12bit ADC gravityTds.begin(); //initialization } void loop() { //temperature = readTemperature(); //add your temperature sensor and read it gravityTds.setTemperature(temperature); // set the temperature and execute temperature compensation gravityTds.update(); //sample and calculate tdsValue = gravityTds.getTdsValue(); // then get the value Serial.print(tdsValue,0); Serial.println("ppm"); delay(1000); } |
Calibrating the TDS Meter:
- Upload the above sample code onto your Arduino and open the serial monitor.
- First Clean and dry the TDS probe with blotting paper.
- Insert the probe into an available electrical conductivity or TDS value buffer solution, stir gently, and wait for stable readings.
- Use a TDS pen to measure
- the water TDS value.
- Enter the “enter” command to start calibration mode.
Enter the “cal:tds value” command. For example, use “cal:120” for a 120ppm buffer solution.
Input “exit“ to save and exit calibration mode.
Now the TDS sensor is ready for use in your application.
Monitor Water Quality Using Arduino and TDS Sensor & OLED
Arduino | OLED Display | TDS Sensor |
---|---|---|
GND | GND | GND |
5V | VCC | VCC |
A4 (SDA) | SDA | – |
A5 (SCL) | SCL | – |
A0 | – | Signal (Analog) |
Source Code Monitor Water Quality Using Arduino and TDS Sensor
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 |
#include <Wire.h> #include <Adafruit_GFX.h> #include <Adafruit_SSD1306.h> #define OLED_RESET 1 Adafruit_SSD1306 display(128, 64, &Wire, OLED_RESET); #define TdsSensorPin A0 #define VREF 5.0 // Analog reference voltage(Volt) of the ADC #define SCOUNT 30 // Sum of sample points // Store the analog values in arrays read from ADC int analogBuffer[SCOUNT]; int analogBufferTemp[SCOUNT]; int analogBufferIndex = 0, copyIndex = 0; float averageVoltage = 0, tdsValue = 0, temperature = 25; void setup() { Serial.begin(115200); pinMode(TdsSensorPin, INPUT); Wire.begin(); display.begin(SSD1306_SWITCHCAPVCC, 0x3C); display.clearDisplay(); } void loop() { static unsigned long analogSampleTimepoint = millis(); // Read the analog value from the ADC every 40 milliseconds if (millis() - analogSampleTimepoint > 40U) { analogSampleTimepoint = millis(); analogBuffer[analogBufferIndex] = analogRead(TdsSensorPin); analogBufferIndex++; if (analogBufferIndex == SCOUNT) analogBufferIndex = 0; } static unsigned long printTimepoint = millis(); // Print TDS value every 800 milliseconds if (millis() - printTimepoint > 800U) { printTimepoint = millis(); // Copy analog buffer for processing for (copyIndex = 0; copyIndex < SCOUNT; copyIndex++) analogBufferTemp[copyIndex] = analogBuffer[copyIndex]; // Obtain a more stable analog value by median filtering algorithm averageVoltage = getMedianNum(analogBufferTemp, SCOUNT) * (float)VREF / 1024.0; // Temperature compensation formula float compensationCoefficient = 1.0 + 0.02 * (temperature - 25.0); float compensationVoltage = averageVoltage / compensationCoefficient; // Convert voltage value to TDS value tdsValue = (133.42 * compensationVoltage * compensationVoltage * compensationVoltage - 255.86 * compensationVoltage * compensationVoltage + 857.39 * compensationVoltage) * 0.5; // Print TDS value via Serial Serial.print("TDS Value:"); Serial.print(tdsValue, 0); Serial.println("ppm"); // Display TDS value on OLED display.clearDisplay(); display.setTextSize(2); display.setTextColor(WHITE); display.setCursor(0, 0); display.print("TDS Value:"); display.display(); display.setTextSize(2); display.setTextColor(WHITE); display.setCursor(30, 30); display.print(tdsValue, 0); display.setCursor(80, 28); display.print("ppm"); display.display(); // Display "Water Quality" below ppm value display.setTextSize(1); // Changing text size to fit below ppm display.setTextColor(WHITE); display.setCursor(30, 50); // Adjust the cursor position as needed display.print("Water Quality"); display.display(); } } // Median filter function int getMedianNum(int bArray[], int iFilterLen) { int bTab[iFilterLen]; for (byte i = 0; i < iFilterLen; i++) bTab[i] = bArray[i]; int i, j, bTemp; for (j = 0; j < iFilterLen - 1; j++) { for (i = 0; i < iFilterLen - j - 1; i++) { if (bTab[i] > bTab[i + 1]) { bTemp = bTab[i]; bTab[i] = bTab[i + 1]; bTab[i + 1] = bTemp; } } } if ((iFilterLen & 1) > 0) bTemp = bTab[(iFilterLen - 1) / 2]; else bTemp = (bTab[iFilterLen / 2] + bTab[iFilterLen / 2 - 1]) / 2; return bTemp; } |
If the probe isn’t in the water, it displays around 0. Dip it in liquids to check their TDS. Try tap water and add salt to see higher values
I tested distilled water—it measured 90-95 ppm. Then, I tried tap water, which showed 250+ ppm.
After adding salt to the distilled water, it spiked to 1300 ppm.