<span>TDS</span>
(Total Dissolved Solids) is an indicator of the total amount of various inorganic and organic substances dissolved in water, usually expressed in milligrams per liter (mg/L) or parts per million (ppm). These substances include minerals such as calcium, magnesium, sodium, and potassium, as well as trace amounts of organic matter and heavy metals.
This article introduces how to measure the current TDS value of water based on Arduino.
Hardware Preparation
- Arduino Uno development board (or ESP8266)
- TDS water quality sensor (around 12 yuan)
- 0.96 OLED screen
Wiring Connections
Device Name | Sensor | Arduino |
---|---|---|
OLED Screen | SDA | A4 |
OLED Screen | SCL | A5 |
OLED Screen | VCC | 3.3V/5V |
OLED Screen | GND | GND |
TDS Sensor | Signal Line | A1 |
TDS Sensor | VCC | 5V |
TDS Sensor | GND | GND |
Sample Code
#include "U8glib.h"
// Sensor configuration
const int TDS_PIN = A1;
const float REF_VOLTAGE = 5.0; // ADC reference voltage (modify as needed)
const int ADC_RESOLUTION = 1024; // ADC bit resolution
const float TDS_FACTOR = 0.5; // Common coefficient according to national standards (needs on-site calibration)
// Display configuration
U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NONE|U8G_I2C_OPT_DEV_0);
// National standard water quality classification thresholds (GB/T 14848-2017)
const int TDS_GOOD = 300; // Class I water ≤300mg/L
const int TDS_FAIR = 1000; // Class III water ≤1000mg/L
// Chinese character dot matrix data (unchanged)
static const uint8_t PROGMEM dang[] = {0x01,0x00,0x21,0x08,0x11,0x08,0x09,0x10,0x09,0x20,0x01,0x00,0x7F,0xF8,0x00,0x08,
0x00,0x08,0x00,0x08,0x3F,0xF8,0x00,0x08,0x00,0x08,0x00,0x08,0x7F,0xF8,0x00,0x08,};
static const uint8_t PROGMEM qian[] = {0x10,0x10,0x08,0x10,0x08,0x20,0xFF,0xFE,0x00,0x00,0x3E,0x08,0x22,0x48,0x22,0x48,
0x3E,0x48,0x22,0x48,0x22,0x48,0x3E,0x48,0x22,0x08,0x22,0x08,0x2A,0x28,0x24,0x10,};
static const uint8_t PROGMEM deng[] = {0x20,0x40,0x3F,0x7E,0x48,0x90,0x85,0x08,0x01,0x00,0x3F,0xF8,0x01,0x00,0x01,0x00,
0xFF,0xFE,0x00,0x00,0x00,0x20,0x7F,0xFC,0x08,0x20,0x04,0x20,0x04,0xA0,0x00,0x40,};
static const uint8_t PROGMEM ji[] = {0x10,0x00,0x13,0xFC,0x20,0x84,0x20,0x88,0x48,0x88,0xF8,0x90,0x10,0x9C,0x20,0x84,
0x41,0x44,0xF9,0x44,0x41,0x28,0x01,0x28,0x1A,0x10,0xE2,0x28,0x44,0x44,0x01,0x82,};
static const uint8_t PROGMEM you[] = {0x08,0x90,0x08,0x88,0x08,0x88,0x10,0x80,0x17,0xFE,0x30,0xA0,0x30,0xA0,0x50,0xA0,
0x90,0xA0,0x10,0xA0,0x11,0x20,0x11,0x22,0x11,0x22,0x12,0x22,0x12,0x1E,0x14,0x00,};
static const uint8_t PROGMEM zhong[] = {0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x3F,0xF8,0x21,0x08,0x21,0x08,0x21,0x08,
0x21,0x08,0x21,0x08,0x3F,0xF8,0x21,0x08,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,};
static const uint8_t PROGMEM cha[] = {0x08,0x20,0x04,0x40,0x7F,0xFC,0x01,0x00,0x01,0x00,0x3F,0xF8,0x02,0x00,0x02,0x00,
0xFF,0xFE,0x04,0x00,0x08,0x00,0x17,0xF8,0x20,0x80,0x40,0x80,0x80,0x80,0x1F,0xFC,};
// Improved TDS reading (added average filtering)
float getTDSValue() {
const int samples = 10;
float avgVoltage = 0;
for(int i=0; i<samples; i++){
avgVoltage += analogRead(TDS_PIN) * (REF_VOLTAGE / ADC_RESOLUTION);
delay(10);
}
avgVoltage /= samples;
// According to the national standard formula: TDS(mg/L) = k * conductivity(μS/cm)
// Typical k value range 0.55-0.8, default 0.65 needs calibration
float tdsValue = avgVoltage * TDS_FACTOR * 1000;
return tdsValue;
}
// National standard water quality determination
const unsigned char* getWaterLevel(float tds) {
if (tds <= TDS_GOOD) return you; // Excellent (Class I)
else if (tds <= TDS_FAIR) return zhong; // Fair (Class III)
else return cha; // Poor (exceeds Class III)
}
void setup(){
Serial.begin(115200);
// Display initialization (unchanged)
if ( u8g.getMode() == U8G_MODE_R3G3B2 ) {
u8g.setColorIndex(255);
}
// ...other display mode settings
}
void loop(){
static float tds = 0;
tds = getTDSValue();
u8g.firstPage();
do {
draw(tds);
} while( u8g.nextPage() );
delay(500); // Extend sampling interval appropriately
}
// Optimize display interface
void draw(float tds) {
u8g.setFont(u8g_font_unifont);
// Display title
u8g.drawBitmapP( 0, 0, 2, 16, dang);
u8g.drawBitmapP( 16, 0, 2, 16, qian);
u8g.drawStr( 32, 12, "TDS");
// Display value (retain 1 decimal place)
u8g.setPrintPos(60, 12);
u8g.print(tds, 1);
u8g.drawStr( 100, 12, "mg/L"); // National standard unit
// Display water quality level
u8g.drawBitmapP( 16, 32, 2, 16, deng);
u8g.drawBitmapP( 32, 32, 2, 16, ji);
const unsigned char* level = getWaterLevel(tds);
u8g.drawBitmapP( 64, 32, 2, 16, level);
// Serial output for debugging information
Serial.print("TDS: ");
Serial.print(tds);
Serial.println(" mg/L");
}
Note: Due to the limited memory of Arduino, displaying Chinese characters is not as powerful as on ESP8266. Therefore, it can only use font software to extract the required text and place it in the code.
Effect Display


Note: The water quality level is classified according to the national standard water quality classification thresholds (GB/T 14848-2017). Class I water <span>≤300</span>
mg/L
Water Quality Classification (Industry Common)
- 0-9 mg/L: Purified water (e.g., distilled water).
- 10-60 mg/L: Spring water, mineralized water (contains natural minerals).
- 60-100 mg/L: Purified water (processed by activated carbon, ultrafiltration).
- 100-300 mg/L: Ordinary tap water.
- Above 300 mg/L: Possible contamination, further testing required.
For more exciting articles, please follow us