Monitoring Water Levels with the Ai-M61-32S
Project Solution
By reading the analog values from the IO interface and performing voltage conversion, the detected voltage values can be obtained. Further voltage - water level calibration enables serial printing and plotting of water level height, achieving real - time water level monitoring.
Voltage Conversion
Based on Ohm's Law, V = I / R, voltage is proportional to resistance. By obtaining the analog values corresponding to 3.3V and GND (measured as 3199 and 21), the actual voltage conversion formula is derived as Valtage = val * (3.3 / (3199-21)).
Code
#include <stdio.h> void setup() {
pinMode(19, INPUT);
Serial.begin(115200);
}
void loop() {
int val = analogRead(19); // analog value reading
float vlt = val * (3.3 / (3199-21)); // real voltage conversion Serial.println(vlt);
delay(200);
}
Hold down the IO2 button and short - press the EN button to enter download mode. After configuring the port, upload the project and reset to run the program.
Water Level Sensor
The water level sensor can detect water height (detection range: 0 - 40 mm) and can also be used as a raindrop sensor for weather monitoring, detecting rainfall and intensity. It is widely applied in automotive windshield wiper systems, intelligent lighting systems, washing machines, and smart sunroof systems.
Module Introduction
When powered on, the power indicator LED lights up. Operating voltage: DC 3.3V - 5V. Output type: analog signal.
The sensor features 10 exposed copper lines, with 5 power copper lines and 5 sensing copper lines arranged in an interlaced parallel pattern, with each power copper line having a sensing copper line in between.
Module Schematic
Pin Definition
- S (Signal) is the analog output;
- + (VCC) is the sensor power supply;
- - (GND) is the ground.
Working Principle
When there is water between parallel copper lines, different immersion heights result in varying currents. The resistance between copper lines changes with water level variations.
Resistance is inversely proportional to water height (the deeper the sensor is immersed, the better the conductivity, the lower the resistance, and the higher the current). Thus, the water level can be determined by measuring the sensor's output voltage via ADC.
Hardware Connection
S -> IO19, + -> 3V3, - -> GND.
After completing the hardware connection, open the serial port. At this point, the output voltage should be 0.
Water Level Calibration
Due to differences in water quality and conductivity, calibration is required. Dry the parallel copper lines on the PCB surface before each calibration. Place the sensor in water when the voltage reads 0 and record the water level and voltage. Collect multiple sets of data for averaging.
Calibration Data Collection
At a water level of 10 mm, the corresponding serial output voltage is 1.25 V.
Increase the water level and collect multiple voltage - water level data pairs. Assuming a linear relationship between voltage (V) and water level height (mm), fit the data using Excel to obtain the equation y = 41.774 x - 38.686.
Project Code
Add water level height definitions in the code:
#include <stdio.h>void setup() { pinMode(19, INPUT);
Serial.begin(115200); }void loop() { int val = analogRead(19); // analog sensor value
float vlt = val * (3.3 / (3199-21)); // real voltage conversion float wl = 41.774 * vlt - 38.686; // water level (mm) Serial.print(val); Serial.print(","); Serial.print(vlt); Serial.print(","); Serial.println(wl); delay(200);
}
Save the code, build the project, upload the firmware, and reset to run. Open the serial assistant, connect to the target serial port, and obtain real - time IO analog values, voltage (V), and water level (mm).
Digital Tube Display of Water Level
Based on the previous voltage reading and water level sensor - based voltage - water level height conversion, a 4 - bit common - anode digital tube displaying water level height is added.
Hardware Connection
Two 74HC595 - driven 4 - bit common - anode digital tubes are used, supporting a wide voltage input of 3.3V to 5V and requiring only 3 signal pins for driving.
- Water - sensor_ S -> IO19, Water - sensor_ + -> 3V3, Water - sensor_ - -> GND.
- 4Bit - segment_ SCLK -> IO23, 4Bit - segment_ RCLK -> IO24, 4Bit - segment_ DIO -> IO11.
Project Code
#include <stdio.h>
#include <stdio.h>
// Water level sensor pin
const int sensorPin = 19;
// 74HC595 pin configuration
const int latchPin = 24; // RCLK
const int clockPin = 23; // SCLK
const int dataPin = 11; // DIO
// Digital tube display data
unsigned char num[] = {
0xC0, // "0"
0xF9, // "1"
0xA4, // "2"
0xB0, // "3"
0x99, // "4"
0x92, // "5"
0x82, // "6"
0xF8, // "7"
0x80, // "8"
0x90 // "9"
};
// Initialization function
void setup() {
pinMode(latchPin, OUTPUT);
pinMode(clockPin, OUTPUT);
pinMode(dataPin, OUTPUT);
pinMode(sensorPin, INPUT);
// UART configuration
Serial.begin(115200);
}
// Main loop function
void loop() {
int count = 0;
int val = analogRead(sensorPin); // Read analog sensor value
float vlt = val * (3.3 / (3199 - 21)); // Convert to actual voltage
float wl = 41.774 * vlt - 38.686; // Convert voltage to water level (mm)
// Print data to serial port
Serial.print(val); // Analog value
Serial.print(", ");
Serial.print(vlt); // Voltage value
Serial.print(", ");
Serial.println(wl); // Water level value
// Print detailed data string
Serial.println((String)"Analog Value: " + val + ", Voltage: " + vlt + "V, Water Level: " + wl + "mm");
// Delay using a loop
while (count < 25) {
if (wl < 0) {
disp(0); // Display 0 if water level is negative
} else {
disp(wl); // Display water level
}
count++;
}
}
// Digital tube display function (dynamic scanning)
void disp(float n) {
int t = 5;
int yi = ((int)(n * 10)) % 10; // Decimal part
int ge = (int)n % 10; // Ones place
int shi = ((int)n / 10) % 10; // Tens place
int bai = ((int)n / 100) % 10; // Hundreds place
// Display hundreds place
if (bai > 0) {
shiftOut(dataPin, clockPin, MSBFIRST, num[bai]);
} else {
shiftOut(dataPin, clockPin, MSBFIRST, 0xFF);
}
shiftOut(dataPin, clockPin, MSBFIRST, 0b00001000);
digitalWrite(latchPin, HIGH);
delay(t);
digitalWrite(latchPin, LOW);
// Display tens place
if (shi > 0) {
shiftOut(dataPin, clockPin, MSBFIRST, num[shi]);
} else {
if (bai > 0) {
shiftOut(dataPin, clockPin, MSBFIRST, num[0]);
} else {
shiftOut(dataPin, clockPin, MSBFIRST, 0xFF);
}
}
shiftOut(dataPin, clockPin, MSBFIRST, 0b00
●Note that the shiftOut function needs to be defined.
●To avoid excessive dynamic refreshing of the digital tube due to significant fluctuations in each sampled value, a loop is added to extend the data refresh interval.
●Alternatively, take multiple samples and average them to reduce water level fluctuations and achieve a more stable digital tube display.