Hi everyone. I have a project that uses two HC-12 transceiver. So in the first module I have HC-12(sender) and ultrasonic sensor. While the other one is the receiver with HC-12 and LCD. The idea is to use it to monitor water tank level wirelessly. The problem is, the receiver module with LCD show the level in percentage inaccurately. For instance I am refilling the water tank the LCD goes 20%, 24%, 27%, 30% , 34%, and so on instead of 20, 21, 22, 23... .WHY the percentage increases with gaps the same thing happen when the water lvl is decreasing.
My project is similar to this one https://www.youtube.com/watch?v=0XvcTOI3-1Y&t=892s you can watch in 14 minutes mark, his LCD shows what I meant to my problem.
Receiver Code
//---------------------------- LIVE WATER TANK INDICATOR WITH DR PUMP RUN PROTECTION USING ARDUINO AND HC- 12 TRANSCIEVER----------------
#include <SoftwareSerial.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <EEPROM.h> //DONT FORGET TO CHANGE THE IF CONDITION TO SUMP TANK
unsigned long previousMillis = 0; // Variable to store the last time the function was called
unsigned long delayTime = 5000; // Delay time in milliseconds
LiquidCrystal_I2C lcd(0x27, 20, 4);
SoftwareSerial HC12(7, 8);
#define BUTTON_MUTE 13
#define calibrateBtn 12
const int reset = 2;
const int Relaypin = 10;
const int red_led = 6;
const int yellow_led = 5;
const int green_led = 4;
const int pmp_On = 9;
const int pmp_Off = 11;
const int SpmpSensorPin = A0; // Upload again to updata Sump tank empty!
int data = 0;
int duration = 500;
int flag;
int addr = 0;
int addr2 = 1;
float MaxWaterLevel, EmptySpace, SonarReading, ActualReading, Temp;
int tankHeight;
int setHeight = 0;
int percentage = 0;
int caliBtnState = 0;
int buttonState = 1;
int previous_data = 0;
byte lastButtonState = 1; //Motingog sa pinaka una
byte buzState = LOW;
unsigned long previousTime = 0;
const unsigned long interval = 500;
bool ledState = false;
//++++++++++++++++++++++++++++++++++++++++++++++ TANK FRAME +++++++++++++++++++++++++++++++++++
byte FrameRight[8] = {
0b00011, 0b00011, 0b00011, 0b00011, 0b00011, 0b00011, 0b00011, 0b00011
};
byte FrameRightCorner[8] = {
0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00011, 0b00011
};
byte FrameLeft[8] = {
0b11000, 0b11000, 0b11000, 0b11000, 0b11000, 0b11000, 0b11000, 0b11000
};
byte FrameLeftCorner[8] = {
0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b11000, 0b11000
};
byte FrameTopp[8] = {
0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b11111, 0b11111
};
//+++++++++++++++++++++++++++++++++++++++++++++++++ FILL BYTES +++++++++++++++++++++++++++++++++
byte Fill0[8] = {
0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000
};
byte Fill1[8] = {
0b00000, 0b00000, 0b00000, 0b00000, 0b11111, 0b11111, 0b11111, 0b11111
};
byte Fill2[8] = {
0b11111, 0b11111, 0b11111, 0b11111, 0b11111, 0b11111, 0b11111, 0b11111
};
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
void RunHC12() {
while (HC12.available ()) {
data = HC12.read();
if ((data < 200) or (data >= 0)) {
previous_data = data;
}
if ((data > 201) or (data < 0)) {
data = previous_data;
}
}
}
void setup() {
Serial.begin(9600);
HC12.begin(9600);
lcd.init();
lcd.backlight();
digitalWrite(reset, HIGH);
pinMode(reset, OUTPUT);
pinMode(calibrateBtn, INPUT_PULLUP);
pinMode(red_led, OUTPUT);
pinMode(yellow_led, OUTPUT);
pinMode(green_led, OUTPUT);
pinMode(pmp_Off, OUTPUT);
pinMode(pmp_On, OUTPUT);
pinMode(BUTTON_MUTE, INPUT_PULLUP);
pinMode(Relaypin, OUTPUT); // Define the Relaypin as output pin
lcd.createChar(0, FrameRight);
lcd.createChar(1, FrameRightCorner);
lcd.createChar(2, FrameLeft);
lcd.createChar(3, FrameLeftCorner);
lcd.createChar(6, Fill0);
lcd.createChar(4, Fill1);
lcd.createChar(5, Fill2);
lcd.createChar(7, FrameTopp);
lcd.setCursor(0, 1);
lcd.print(F("AUTOMATED TANK LEVEL"));
lcd.setCursor(1, 2);
lcd.print(F("INDICATOR SYSTEM"));
delay(4000);
lcd.clear();
for (int i = 0; i <= 10; i++) {
lcd.setCursor(2, 0);
lcd.print(F("Set tank height?"));
lcd.setCursor(0, 1);
lcd.print(F("(Y) Press'Set'"));
lcd.setCursor(0, 2);
lcd.print(F("(N) Ignore"));
lcd.setCursor(0, 3);
lcd.print(F("Expired in:"));
lcd.print(10 - i);
lcd.print(" sec ");
caliBtnState = digitalRead(calibrateBtn);
if (caliBtnState == LOW) {
lcd.clear();
tankHeight = HC12.read();
EEPROM.write(addr, tankHeight);
break;
}
delay(1000);
}
tankHeight = EEPROM.read(addr);
lcd.clear();
lcd.setCursor(0, 1);
lcd.print(F("Tank height:"));
lcd.print((String)tankHeight + "cm ");
delay(3000);
lcd.clear();
MaxWaterLevel = 0.50 * tankHeight;
EmptySpace = tankHeight - MaxWaterLevel;
}
void loop() {
int SpmpsensorValue = analogRead(SpmpSensorPin); // Read the analog sensor value
int scaledValue = map(SpmpsensorValue, 0, 1023, 0, 255); // Map the value to a new range
float multiValueSpmp = scaledValue * 5.0; // Scale the value to get the actual voltage value
Serial.println(percentage);
Temp = data - EmptySpace;
ActualReading = MaxWaterLevel - Temp;
percentage = ActualReading / MaxWaterLevel * 100;
/*if (tankHeight == 153 || tankHeight == 255) {
lcd.setCursor(2, 0);
lcd.print(F("Please try again"));
delay(3000);
digitalWrite(reset, LOW);
}*/
if (multiValueSpmp >= 200) {
lastButtonState = HIGH;
FrameRightDisplay();
RunHC12();
lcd.setCursor(8, 1);
lcd.print("Level: ");
lcd.setCursor(8, 2);
lcd.print((String)percentage + "% ");
if (percentage == 200 ) {
percentage = 21;
Level1();
}
if (percentage <= 20 || tankHeight == 153) {
Level1();
lcd.setCursor(13, 3);
lcd.print("PMP:ON ");
digitalWrite(Relaypin, HIGH);
digitalWrite(pmp_On, HIGH);
digitalWrite(pmp_Off, LOW);
digitalWrite(red_led, HIGH);
digitalWrite(yellow_led, LOW);
digitalWrite(green_led, LOW);
flag = 1;
EEPROM.write(addr2, flag);
flag = EEPROM.read(addr2);
}
else if (percentage > 20 && percentage <= 100) {
flag = EEPROM.read(addr2);
if (percentage > 20 && percentage <= 100 && flag == 1) {
digitalWrite(Relaypin, HIGH);
lcd.setCursor(13, 3);
lcd.print("PMP:ON");
digitalWrite(pmp_Off, LOW);
digitalWrite(pmp_On, HIGH);
if (percentage <= 20) {
Level1();
digitalWrite(red_led, HIGH);
digitalWrite(yellow_led, LOW);
digitalWrite(green_led, LOW);
}
else if (percentage > 20 && percentage <= 25) {
Level2();
digitalWrite(red_led, HIGH);
digitalWrite(yellow_led, LOW);
digitalWrite(green_led, LOW);
}
else if (percentage > 25 && percentage <= 50) {
Level3();
digitalWrite(red_led, HIGH);
digitalWrite(yellow_led, LOW);
digitalWrite(green_led, LOW);
}
else if (percentage > 50 && percentage <= 75) {
Level4();
digitalWrite(red_led, LOW);
digitalWrite(yellow_led, HIGH);
digitalWrite(green_led, LOW);
}
else if (percentage > 75 && percentage <= 95) {
Level5();
digitalWrite(red_led, LOW);
digitalWrite(yellow_led, LOW);
digitalWrite(green_led, HIGH);
}
else if (percentage == 100) {
Level6();
lcd.setCursor(13, 3);
lcd.print("PMP:OFF");
digitalWrite(pmp_Off, HIGH);
digitalWrite(pmp_On, LOW);
digitalWrite(red_led, LOW);
digitalWrite(yellow_led, LOW);
digitalWrite(green_led, HIGH);
}
}
else if (percentage > 20 && percentage <= 100 && flag == 0 ) {
digitalWrite(Relaypin, LOW); //relayyyyy pin hereee
lcd.setCursor(11, 3);
lcd.print(" PMP:OFF");
digitalWrite(pmp_On, LOW);
digitalWrite(pmp_Off, HIGH);
if (percentage <= 10) {
Level1();
digitalWrite(red_led, HIGH);
digitalWrite(yellow_led, LOW);
digitalWrite(green_led, LOW);
}
else if (percentage > 20 && percentage <= 25) {
Level2();
digitalWrite(red_led, HIGH);
digitalWrite(yellow_led, LOW);
digitalWrite(green_led, LOW);
}
else if (percentage > 25 && percentage <= 50) {
Level3();
digitalWrite(red_led, HIGH);
digitalWrite(yellow_led, LOW);
digitalWrite(green_led, LOW);
}
else if (percentage > 50 && percentage <= 75) {
Level4();
digitalWrite(red_led, LOW);
digitalWrite(yellow_led, HIGH);
digitalWrite(green_led, LOW);
}
else if (percentage > 75 && percentage <= 95) {
Level5();
digitalWrite(red_led, LOW);
digitalWrite(yellow_led, LOW);
digitalWrite(green_led, HIGH);
}
else if ( percentage == 100) {
Level6();
lcd.setCursor(13, 3);
lcd.print("PMP:OFF");
digitalWrite(pmp_Off, HIGH);
digitalWrite(pmp_On, LOW);
digitalWrite(red_led, LOW);
digitalWrite(yellow_led, LOW);
digitalWrite(green_led, HIGH);
}
}
}
else if (percentage > 100) {
delay (200);
lcd.setCursor(13, 3);
lcd.print("PMP:OFF");
digitalWrite(Relaypin, LOW);
digitalWrite(pmp_Off, HIGH);
digitalWrite(pmp_On, LOW);
digitalWrite(red_led, LOW);
digitalWrite(yellow_led, LOW);
digitalWrite(green_led, HIGH);
flag = 0;
EEPROM.write(addr2, flag) ;
flag = EEPROM.read(addr2);
Level6();
}
} else if (multiValueSpmp <= 200) {
flag = EEPROM.read(addr2);
if (flag == 1) {
lcd.clear();
RunHC12();
digitalWrite(Relaypin, LOW);
digitalWrite(pmp_On, LOW);
digitalWrite(red_led, LOW);
digitalWrite(yellow_led, LOW);
digitalWrite(green_led, LOW);
//Sumpt Tank Empty Message Goes HEREEEEE
lcd.setCursor(4, 1);
lcd.print(F("Source Empty"));
lcd.setCursor(3, 2);
lcd.print("Water Lvl: ");
lcd.setCursor(14, 2);
lcd.print((String)percentage + "% ");
unsigned long currentTime = millis();
if (currentTime - previousTime >= interval) {
previousTime = currentTime;
if (ledState) {
ledState = false;
digitalWrite(pmp_Off, HIGH);
} else {
ledState = true;
digitalWrite(pmp_Off, LOW);
}
}
//PUT THE ALARM TONE HERE WITH MUTE BUTTON
while (lastButtonState != LOW) {
RunHC12();
buttonState = digitalRead(BUTTON_MUTE);
lcd.setCursor(3, 2);
lcd.print("Water Lvl: ");
lcd.setCursor(14, 2);
lcd.print((String)percentage + "% ");
if (buttonState == LOW) {
noTone(3);
lastButtonState = buttonState;
} else if (buttonState == HIGH) {
alarm();
}
}
delay(1000);
lcd.clear();
}
else if (flag == 0) {
RunHC12();
FrameRightDisplay();
digitalWrite(pmp_On, LOW);
lcd.setCursor(8, 1);
lcd.print("Level: ");
lcd.setCursor(8, 2);
lcd.print((String)percentage + "% ");
lcd.setCursor(11, 3);
lcd.print("ST:EMPTY ");
unsigned long currentTime = millis();
if (currentTime - previousTime >= interval) {
previousTime = currentTime;
if (ledState) {
ledState = false;
digitalWrite(pmp_Off, LOW);
} else {
ledState = true;
digitalWrite(pmp_Off, HIGH);
}
}
if (percentage <= 20) {
Level1();
digitalWrite(red_led, HIGH);
digitalWrite(yellow_led, LOW);
digitalWrite(green_led, LOW);
} else if (percentage > 20 && percentage <= 25) {
Level2();
digitalWrite(red_led, HIGH);
digitalWrite(yellow_led, LOW);
digitalWrite(green_led, LOW);
} else if (percentage > 25 && percentage <= 50) {
Level3();
digitalWrite(red_led, LOW);
digitalWrite(yellow_led, HIGH );
digitalWrite(green_led, LOW);
} else if (percentage > 50 && percentage <= 75) {
Level4();
digitalWrite(red_led, LOW);
digitalWrite(yellow_led, HIGH);
digitalWrite(green_led, LOW);
} else if (percentage > 75 && percentage <= 100) {
Level5();
digitalWrite(red_led, LOW);
digitalWrite(yellow_led, LOW);
digitalWrite(green_led, HIGH);
} else if (percentage > 100) {
Level6();
digitalWrite(red_led, LOW);
digitalWrite(yellow_led, LOW);
digitalWrite(green_led, HIGH);
}
}
}
}
void alarm() {
tone(3, 1400, duration);
delay(1000);
tone(3, 800, duration);
delay(1000);
}
//+++++++++++++++++++++++++++++++++++++++ FRAME ++++++++++++++++++++++++++++++++++++++
void FrameRightDisplay() {
lcd.setCursor(1, 0); lcd.write(byte(7)); lcd.write(byte(7)); lcd.write(byte(7)); lcd.write(byte(7)); lcd.write(byte(7)); lcd.write(byte(7));
lcd.setCursor(3, 0); lcd.write(byte(4)); lcd.write(byte(4));
lcd.setCursor(0, 3); lcd.write(byte(0)); lcd.setCursor(0, 2); lcd.write(byte(0)); lcd.setCursor(0, 1); lcd.write(byte(0));
lcd.setCursor(0, 0); lcd.write(byte(1));
lcd.setCursor(7, 3); lcd.write(byte(2)); lcd.setCursor(7, 2); lcd.write(byte(2)); lcd.setCursor(7, 1); lcd.write(byte(2));
lcd.setCursor(7, 0); lcd.write(byte(3));
}
//++++++++++++++++++++++++++++++++++++++++++ PROGRESS BAR ++++++++++++++++++++++++++++++
void Level1() {
lcd.setCursor(1, 3); lcd.write(byte(4)); lcd.write(byte(4)); lcd.write(byte(4)); lcd.write(byte(4)); lcd.write(byte(4)); lcd.write(byte(4));
}
void Level2() {
lcd.setCursor(1, 3); lcd.write(byte(5)); lcd.write(byte(5)); lcd.write(byte(5)); lcd.write(byte(5)); lcd.write(byte(5)); lcd.write(byte(5));
lcd.setCursor(1, 2); lcd.write(byte(6)); lcd.write(byte(6)); lcd.write(byte(6)); lcd.write(byte(6)); lcd.write(byte(6)); lcd.write(byte(6));
lcd.setCursor(1, 1); lcd.write(byte(6)); lcd.write(byte(6)); lcd.write(byte(6)); lcd.write(byte(6)); lcd.write(byte(6)); lcd.write(byte(6));
}
void Level3() {
lcd.setCursor(1, 2); lcd.write(byte(4)); lcd.write(byte(4)); lcd.write(byte(4)); lcd.write(byte(4)); lcd.write(byte(4)); lcd.write(byte(4));
lcd.setCursor(1, 3); lcd.write(byte(5)); lcd.write(byte(5)); lcd.write(byte(5)); lcd.write(byte(5)); lcd.write(byte(5)); lcd.write(byte(5));
}
void Level4() {
lcd.setCursor(1, 3); lcd.write(byte(5)); lcd.write(byte(5)); lcd.write(byte(5)); lcd.write(byte(5)); lcd.write(byte(5)); lcd.write(byte(5));
lcd.setCursor(1, 2); lcd.write(byte(5)); lcd.write(byte(5)); lcd.write(byte(5)); lcd.write(byte(5)); lcd.write(byte(5)); lcd.write(byte(5));
lcd.setCursor(1, 1); lcd.write(byte(6)); lcd.write(byte(6)); lcd.write(byte(6)); lcd.write(byte(6)); lcd.write(byte(6)); lcd.write(byte(6));
}
void Level5() {
lcd.setCursor(1, 1); lcd.write(byte(4)); lcd.write(byte(4)); lcd.write(byte(4)); lcd.write(byte(4)); lcd.write(byte(4)); lcd.write(byte(4));
lcd.setCursor(1, 3); lcd.write(byte(5)); lcd.write(byte(5)); lcd.write(byte(5)); lcd.write(byte(5)); lcd.write(byte(5)); lcd.write(byte(5));
lcd.setCursor(1, 2); lcd.write(byte(5)); lcd.write(byte(5)); lcd.write(byte(5)); lcd.write(byte(5)); lcd.write(byte(5)); lcd.write(byte(5));
}
void Level6() {
lcd.setCursor(1, 1); lcd.write(byte(5)); lcd.write(byte(5)); lcd.write(byte(5)); lcd.write(byte(5)); lcd.write(byte(5)); lcd.write(byte(5));
lcd.setCursor(1, 3); lcd.write(byte(5)); lcd.write(byte(5)); lcd.write(byte(5)); lcd.write(byte(5)); lcd.write(byte(5)); lcd.write(byte(5));
lcd.setCursor(1, 2); lcd.write(byte(5)); lcd.write(byte(5)); lcd.write(byte(5)); lcd.write(byte(5)); lcd.write(byte(5)); lcd.write(byte(5));
}
Sender Code
#include <SoftwareSerial.h>
SoftwareSerial HC12(5, 4);
const int trigPin = 3; // define the trigger pin
const int echoPin = 2; // define the echo pin
int power = 6;
long scaledDist2 = 0;
int Time = 0;
const int numReadings = 10; // number of readings to average
int readings[numReadings]; // array to store the readings
int index = 0; // index of the current reading
int total = 0; // total of all the readings
int average = 0; // average of the readings
int scaledDist1 = 0; // scaled distance measurement
void setup() {
HC12.begin(9600);
Serial.begin(9600); // initialize serial communication
pinMode(trigPin, OUTPUT); // set the trigger pin as an output
pinMode(echoPin, INPUT); // set the echo pin as an input
pinMode(power, OUTPUT);
digitalWrite(power, 1);
}
void loop() {
Time++;
// trigger the ultrasonic sensor
digitalWrite(trigPin, LOW);
delayMicroseconds(10);
digitalWrite(trigPin, HIGH);
delayMicroseconds(20);
digitalWrite(trigPin, LOW);
// measure the echo pulse duration
long duration = pulseIn(echoPin, HIGH);
// convert the duration to distance in cm
long distance = duration / 29 / 2;
// add the distance measurement to the readings array
total = total - readings[index];
readings[index] = distance;
total = total + readings[index];
// increment the index
index = index + 1;
// wrap around the index if necessary
if (index >= numReadings) {
index = 0;
}
average = total / numReadings;
scaledDist1 = constrain(average, 0, 300);
//Serial.println(scaledDist1);
if(Time == 100){
HC12.write(scaledDist1);
Time = 0;
}
Serial.println(scaledDist1);
if(scaledDist1 != scaledDist2){
HC12.write(scaledDist1);
scaledDist2 = scaledDist1;
}
delay(200);
}