Multi tasking structre for my arduino sketch

I have a digital scale project to measure both weight and height in a addition to keypad and a buzzer to enter the the some data
The point that my scale should work in 2 modes
the first mode is when we need to measure weight only when a person step on the load cell unit.
the second mode is when we need to measure weight and height and entering some data , so the person has to press any key to start that mode.
I was able to make the sketch to achieve the second mode but it wasn't possible to make a keypad buzz for every key press, nor I was able to achieve the first mode as both of them need restructuring my sketch to include machine states and I'm not sure what is the best restructuring to solve both problems
here is my code

#include <LiquidCrystal_I2C.h>
#include <Wire.h> 
#include <Keypad.h>
#include <ezBuzzer.h>
#include "HX711.h"

#define calibration_factor -7050.0 //This value is obtained using the SparkFun_HX711_Calibration sketch
#define LOADCELL_DOUT_PIN  11
#define LOADCELL_SCK_PIN  12
HX711 scale;
int trigPin = 12;    // TRIG pin
int echoPin = 11;    // ECHO pin
float duration_us, distance_cm;
LiquidCrystal_I2C lcd_1(0x27, 16, 2);
const int BUZZER_PIN = 10;
const int ROW_NUM    = 4; // four rows
const int COLUMN_NUM = 4; // four columns
char keys[ROW_NUM][COLUMN_NUM] = {
  {'1','2','3', 'A'},
  {'4','5','6', 'B'},
  {'7','8','9', 'C'},
  {'*','0','#', 'D'}
};
byte pin_rows[ROW_NUM] = {9, 8, 7, 6};      // connect to the row pinouts of the keypad
byte pin_column[COLUMN_NUM] = {5, 4, 3, 2}; // connect to the column pinouts of the keypad
Keypad customKeypad = Keypad(makeKeymap(keys), pin_rows, pin_column, ROW_NUM, COLUMN_NUM );
ezBuzzer buzzer(BUZZER_PIN); // create ezBuzzer object that attach to a pin;

void displayscreen(){   // screen saver 
  
   lcd_1.setCursor(4,0);
   lcd_1.print("*iScale*");
   lcd_1.setCursor(2 ,1);
   lcd_1.print("!Your Scale!");    
   lcd_1.scrollDisplayLeft(); 
   delay(200);  
   lcd_1.scrollDisplayRight();  
  
 }

void setup() {
  
  Serial.begin(4800);
  lcd_1.init();                      // initialize the lcd 
  lcd_1.init();
  // Print a message to the LCD.
  lcd_1.backlight();
  displayscreen();
  pinMode(trigPin, OUTPUT); // config trigger pin to output mode
  pinMode(echoPin, INPUT);  // config echo pin to input mode
  /*Serial.println("HX711 scale demo"); // load cell module to be activated later
  scale.begin(LOADCELL_DOUT_PIN, LOADCELL_SCK_PIN);
  scale.set_scale(calibration_factor); //This value is obtained by using the SparkFun_HX711_Calibration sketch
  scale.tare(); //Assuming there is no weight on the scale at start up, reset the scale to 0
  Serial.println("Readings:");*/
 }  

void Height(){                       // height measurement module 
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
  duration_us = pulseIn(echoPin, HIGH);
  distance_cm = 0.017 * duration_us;
  lcd_1.clear();
  lcd_1.setCursor(0, 1); 
  lcd_1.print("Height: ");
  lcd_1.print(distance_cm);
 }

Void weight(){    // weight measurement module to be activated later 

  Serial.print("Reading: ");
  Serial.print(scale.get_units(), 1); //scale.get_units() returns a float
  Serial.print(" lbs"); //You can change this to kg but you'll need to refactor the calibration_factor
  Serial.println();
  delay(1000);
  
}

void Beep() {
  buzzer.loop(); // MUST call the buzzer.loop() function in loop()
  char customKey = customKeypad.getKey();

  if (customKey) {
    Serial.print(customKey); // prints key to serial monitor
    buzzer.beep(100);  // generates a 100ms beep
  }
}


void loop(){
  
  
  static unsigned long lastKeypressTime = 0; // initialize the lastKeypressTime variable
  char customKey = customKeypad.getKey();  // variable for the input key
  Beep();
  if (customKey)  //if there is any input
   { 
    lcd_1.clear();
    lastKeypressTime = millis(); // update the lastKeypressTime variable with the current time
    lcd_1.setCursor(0,0);
    lcd_1.print("Enter your PhoneNo.:");
    Serial.print("Enter your PhoneNo.: "); 
    class String PhoneString = "";                   // Initialize an empty string to hold the user's age
    while (millis() - lastKeypressTime <= 10000) {  // Wait for the user to enter their Phone (up to 10 seconds)
    char PhoneKey = customKeypad.getKey();
      if (PhoneKey) {              
        // Initialize if a key is pressed
         lastKeypressTime = millis();
         Serial.print(PhoneKey);
         PhoneString += PhoneKey; // Append the entered digit to the age string
         lcd_1.setCursor(2,1);
         lcd_1.print(PhoneString);
         //PhoneString += PhoneKey;
          if (PhoneString.length() == 11) {              // If the age string has two digits, categorize the age
           // Print the user's age and age group
           lcd_1.clear();
           lcd_1.setCursor(1,0);
           lcd_1.print("Your Phone is: ");
           lcd_1.setCursor(2,1);
           lcd_1.print(PhoneString);
           //delay(1000); 
           // Convert the age string to an integer
           int Phone = PhoneString.toInt(); 
           //lastKeypressTime = 0;
           //if (millis() -lastKeypressTime > 10000) {  
            PhoneString = "";
           delay(1000);
            Age3();
          } 
      }
    }
  }
}


int Age3() {
  int iAge;
  lcd_1.clear();
  lcd_1.print("Enter Your Age :");
  lcd_1.setCursor(4, 1);
  char Key = NO_KEY;
  while (Key == NO_KEY) {
    Key = customKeypad.getKey();
    if (Key > '0' && Key <= '9')  iAge = Key - '0';
    else Key = NO_KEY;
  }
  Serial.print(Key);
  lcd_1.print(Key);
  Key = NO_KEY;
  while (Key == NO_KEY) {
    Key = customKeypad.getKey();
    if (Key >= '0' && Key <= '9')  iAge = iAge * 10 + Key - '0';
    else Key = NO_KEY;
  }

  Serial.print(Key);
  lcd_1.println(Key);

  lcd_1.clear();
  lcd_1.setCursor(1, 0);
  lcd_1.print("Your Age is: ");
  lcd_1.setCursor(8, 1);
  lcd_1.print(iAge);
  delay(1000);
  Gender();
  return iAge;
}

int Gender() {
  class String iGender;
  lcd_1.clear();
  lcd_1.print("Choose Gender:");
  delay(100); 
  lcd_1.setCursor(0, 1);
  lcd_1.print("*=Male #=Female");
  delay(500); 
  lcd_1.clear();
  lcd_1.setCursor(0, 0);
  lcd_1.print("Choose Gender:");
  lcd_1.setCursor(4, 1);
  char Key = NO_KEY;
  while (Key == NO_KEY) {
    Key = customKeypad.getKey();
    if (Key == '*')  iGender == "Male";
    else if (Key =='#')  iGender == "Female";
    else Key = NO_KEY;
  }
  Serial.print(Key);
  lcd_1.print(Key);
  Key = NO_KEY;
  while (Key == NO_KEY) {
    Key = customKeypad.getKey();
    if (Key == '*')  iGender = "Male";
    else if (Key == '#')  iGender = "Female";
    else Key = NO_KEY;
  }
  Serial.print(Key);
  lcd_1.println(Key);
  lcd_1.clear();
  lcd_1.setCursor(1, 0);
  lcd_1.print("Your are a ");
  lcd_1.setCursor(8, 1);
  lcd_1.print(iGender);
  delay(1000); 
  Receipt();
 //return iGender;
 // Height();
}

int Receipt() {
  class String iReceipt;
  lcd_1.clear();
  lcd_1.print("Print Receipt ?");
  delay(100); 
  lcd_1.setCursor(0, 1);
  lcd_1.print("*=Yes #=No");
  delay(500); 
  lcd_1.clear();
  lcd_1.setCursor(0, 0);
  lcd_1.print("Print Receipt ?");
  lcd_1.setCursor(4, 1);
  char Key = NO_KEY;
  while (Key == NO_KEY) {
    Key = customKeypad.getKey();
    if (Key == '*')  iReceipt == "Print Receipt";
    else if (Key =='#')  iReceipt == "Not to Print Receipt";
    else Key = NO_KEY;
  }
  Serial.print(Key);
  lcd_1.print(Key);
  Key = NO_KEY;
  while (Key == NO_KEY) {
    Key = customKeypad.getKey();
    if (Key == '*')  iReceipt = "Print a Receipt";
    else if (Key == '#')  iReceipt = "Not to Print ";
    else Key = NO_KEY;
  }
  Serial.print(Key);
  lcd_1.println(Key);
  lcd_1.clear();
  lcd_1.setCursor(1, 0);
  lcd_1.print("You choosed ");
  lcd_1.setCursor(0, 1);
  lcd_1.print(iReceipt);
  delay(1000); 
  Height();
  delay(5000); 
  lcd_1.clear();
  lcd_1.setCursor(4, 1);
  lcd_1.print("Thank You");
  delay(1000); 
  lcd_1.clear();
  displayscreen();
 //return iReceipt;
 
}

1 Like

have a read of how-to-get-the-best-out-of-this-forum
e.g.

  1. what Arduino are you using
  2. upload a schematic of the wiring show power supplies etc
  3. upload a printout of the serial monitor output
1 Like

Ok, I I'm using Arduino nano
As I'm beginner I have not the schematic for my project as I'm not using any simulator

No answer to your actual question, but there is danger in not looking for a zero time being returned, which means your pulseln() did not see the end of your pulse and returns ZERO! The default time-out is one second. so you might actually set it to some value reasonable to your project.

1 Like

Quite sure that that will not compile.

That makes no sense at all.
You don't need to be simulating anything to have a schematic.

You DO need to have a schematic BEFORE you can make anything.

This is a very common mistake made by beginners. My students at University had to be told over and over to draw a schematic in the electronics labs I used to run. Eventually whenever they asked for help, I would refuse to come and see them until they could show me a schematic. Not surprisingly they eventually got it, and were very grateful.

I have been doing electronics for 60 years and I can't make a circuit without drawing a schematic. What makes you think you are better than me?

2 Likes

@Grumpy_Mike
I did my best to get the schematic, this drawing is exactly like my project
except for
1-using Arduino uno instead on Arduino Nano but with exactly the same pin connections
2- not having the load cell amplifier HX711 connected to the Arduino board
both those components I didn't find them on Tinker cad,


And I apologize for any mistake as I'm completely new to electronics.

The problem now is how to make a keypad buzz in case the main loop is blocking beeping function of the buzzer, as you can see from my sketch.

#include <LiquidCrystal_I2C.h>
#include <Wire.h> 
#include <Keypad.h>
#include <ezBuzzer.h>
#include "HX711.h"

#define calibration_factor -7050.0 //This value is obtained using the SparkFun_HX711_Calibration sketch
#define LOADCELL_DOUT_PIN  11
#define LOADCELL_SCK_PIN  12
HX711 scale;
int trigPin = 12;    // TRIG pin
int echoPin = 11;    // ECHO pin
float duration_us, distance_cm;
LiquidCrystal_I2C lcd_1(0x27, 16, 2);
const int BUZZER_PIN = 10;
const int ROW_NUM    = 4; // four rows
const int COLUMN_NUM = 4; // four columns
char keys[ROW_NUM][COLUMN_NUM] = {
  {'1','2','3', 'A'},
  {'4','5','6', 'B'},
  {'7','8','9', 'C'},
  {'*','0','#', 'D'}
};
byte pin_rows[ROW_NUM] = {9, 8, 7, 6};      // connect to the row pinouts of the keypad
byte pin_column[COLUMN_NUM] = {5, 4, 3, 2}; // connect to the column pinouts of the keypad
Keypad customKeypad = Keypad(makeKeymap(keys), pin_rows, pin_column, ROW_NUM, COLUMN_NUM );
ezBuzzer buzzer(BUZZER_PIN); // create ezBuzzer object that attach to a pin;

void displayscreen(){   // screen saver 
  
   lcd_1.setCursor(4,0);
   lcd_1.print("*iScale*");
   lcd_1.setCursor(2 ,1);
   lcd_1.print("!Your Scale!");    
   lcd_1.scrollDisplayLeft(); 
   delay(200);  
   lcd_1.scrollDisplayRight();  
  
 }

void setup() {
  
  Serial.begin(4800);
  lcd_1.init();                      // initialize the lcd 
  lcd_1.init();
  // Print a message to the LCD.
  lcd_1.backlight();
  displayscreen();
  pinMode(trigPin, OUTPUT); // config trigger pin to output mode
  pinMode(echoPin, INPUT);  // config echo pin to input mode
  /*Serial.println("HX711 scale demo"); // load cell module to be activated later
  scale.begin(LOADCELL_DOUT_PIN, LOADCELL_SCK_PIN);
  scale.set_scale(calibration_factor); //This value is obtained by using the SparkFun_HX711_Calibration sketch
  scale.tare(); //Assuming there is no weight on the scale at start up, reset the scale to 0
  Serial.println("Readings:");*/
 }  

void Height(){                       // height measurement module 
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
  duration_us = pulseIn(echoPin, HIGH);
  distance_cm = 0.017 * duration_us;
  lcd_1.clear();
  lcd_1.setCursor(0, 1); 
  lcd_1.print("Height: ");
  lcd_1.print(distance_cm);
 }

Void weight(){    // weight measurement module to be activated later 

  Serial.print("Reading: ");
  Serial.print(scale.get_units(), 1); //scale.get_units() returns a float
  Serial.print(" lbs"); //You can change this to kg but you'll need to refactor the calibration_factor
  Serial.println();
  delay(1000);
  
}

void Beep() {
  buzzer.loop(); // MUST call the buzzer.loop() function in loop()
  char customKey = customKeypad.getKey();

  if (customKey) {
    Serial.print(customKey); // prints key to serial monitor
    buzzer.beep(100);  // generates a 100ms beep
  }
}


void loop(){
  
  
  static unsigned long lastKeypressTime = 0; // initialize the lastKeypressTime variable
  char customKey = customKeypad.getKey();  // variable for the input key
  Beep();
  if (customKey)  //if there is any input
   { 
    lcd_1.clear();
    lastKeypressTime = millis(); // update the lastKeypressTime variable with the current time
    lcd_1.setCursor(0,0);
    lcd_1.print("Enter your PhoneNo.:");
    Serial.print("Enter your PhoneNo.: "); 
    class String PhoneString = "";                   // Initialize an empty string to hold the user's age
    while (millis() - lastKeypressTime <= 10000) {  // Wait for the user to enter their Phone (up to 10 seconds)
    char PhoneKey = customKeypad.getKey();
      if (PhoneKey) {              
        // Initialize if a key is pressed
         lastKeypressTime = millis();
         Serial.print(PhoneKey);
         PhoneString += PhoneKey; // Append the entered digit to the age string
         lcd_1.setCursor(2,1);
         lcd_1.print(PhoneString);
         //PhoneString += PhoneKey;
          if (PhoneString.length() == 11) {              // If the age string has two digits, categorize the age
           // Print the user's age and age group
           lcd_1.clear();
           lcd_1.setCursor(1,0);
           lcd_1.print("Your Phone is: ");
           lcd_1.setCursor(2,1);
           lcd_1.print(PhoneString);
           //delay(1000); 
           // Convert the age string to an integer
           int Phone = PhoneString.toInt(); 
           //lastKeypressTime = 0;
           //if (millis() -lastKeypressTime > 10000) {  
            PhoneString = "";
           delay(1000);
            Age3();
          } 
      }
    }
  }
}


int Age3() {
  int iAge;
  lcd_1.clear();
  lcd_1.print("Enter Your Age :");
  lcd_1.setCursor(4, 1);
  char Key = NO_KEY;
  while (Key == NO_KEY) {
    Key = customKeypad.getKey();
    if (Key > '0' && Key <= '9')  iAge = Key - '0';
    else Key = NO_KEY;
  }
  Serial.print(Key);
  lcd_1.print(Key);
  Key = NO_KEY;
  while (Key == NO_KEY) {
    Key = customKeypad.getKey();
    if (Key >= '0' && Key <= '9')  iAge = iAge * 10 + Key - '0';
    else Key = NO_KEY;
  }

  Serial.print(Key);
  lcd_1.println(Key);

  lcd_1.clear();
  lcd_1.setCursor(1, 0);
  lcd_1.print("Your Age is: ");
  lcd_1.setCursor(8, 1);
  lcd_1.print(iAge);
  delay(1000);
  Gender();
  return iAge;
}

int Gender() {
  class String iGender;
  lcd_1.clear();
  lcd_1.print("Choose Gender:");
  delay(100); 
  lcd_1.setCursor(0, 1);
  lcd_1.print("*=Male #=Female");
  delay(500); 
  lcd_1.clear();
  lcd_1.setCursor(0, 0);
  lcd_1.print("Choose Gender:");
  lcd_1.setCursor(4, 1);
  char Key = NO_KEY;
  while (Key == NO_KEY) {
    Key = customKeypad.getKey();
    if (Key == '*')  iGender == "Male";
    else if (Key =='#')  iGender == "Female";
    else Key = NO_KEY;
  }
  Serial.print(Key);
  lcd_1.print(Key);
  Key = NO_KEY;
  while (Key == NO_KEY) {
    Key = customKeypad.getKey();
    if (Key == '*')  iGender = "Male";
    else if (Key == '#')  iGender = "Female";
    else Key = NO_KEY;
  }
  Serial.print(Key);
  lcd_1.println(Key);
  lcd_1.clear();
  lcd_1.setCursor(1, 0);
  lcd_1.print("Your are a ");
  lcd_1.setCursor(8, 1);
  lcd_1.print(iGender);
  delay(1000); 
  Receipt();
 //return iGender;
 // Height();
}

int Receipt() {
  class String iReceipt;
  lcd_1.clear();
  lcd_1.print("Print Receipt ?");
  delay(100); 
  lcd_1.setCursor(0, 1);
  lcd_1.print("*=Yes #=No");
  delay(500); 
  lcd_1.clear();
  lcd_1.setCursor(0, 0);
  lcd_1.print("Print Receipt ?");
  lcd_1.setCursor(4, 1);
  char Key = NO_KEY;
  while (Key == NO_KEY) {
    Key = customKeypad.getKey();
    if (Key == '*')  iReceipt == "Print Receipt";
    else if (Key =='#')  iReceipt == "Not to Print Receipt";
    else Key = NO_KEY;
  }
  Serial.print(Key);
  lcd_1.print(Key);
  Key = NO_KEY;
  while (Key == NO_KEY) {
    Key = customKeypad.getKey();
    if (Key == '*')  iReceipt = "Print a Receipt";
    else if (Key == '#')  iReceipt = "Not to Print ";
    else Key = NO_KEY;
  }
  Serial.print(Key);
  lcd_1.println(Key);
  lcd_1.clear();
  lcd_1.setCursor(1, 0);
  lcd_1.print("You choosed ");
  lcd_1.setCursor(0, 1);
  lcd_1.print(iReceipt);
  delay(1000); 
  Height();
  delay(5000); 
  lcd_1.clear();
  lcd_1.setCursor(4, 1);
  lcd_1.print("Thank You");
  delay(1000); 
  lcd_1.clear();
  displayscreen();
 //return iReceipt;
 
}

@sterretje
I corrected it to lowercase v in the Arduino web editor .

@Paul_KD7HB
So how to modify the code solve this problem.
I suggest to add a 1 second delay after this line

duration_us = pulseIn(echoPin, HIGH);

Would this solve the problem.

@drmina2023

There is a pin conflict here. (pins 11 and 12).
I don't know exactly what kind of error can occur with this conflict during program execution.

#define LOADCELL_DOUT_PIN 11
#define LOADCELL_SCK_PIN 12
HX711 scale;
int trigPin = 12; // TRIG pin
int echoPin = 11; // ECHO pin

You solve it by testing for ZERO duration_us and then doing something other than proceeding on with that part of the code. What do you want to happen when NOTHING is detected?

Would connecting the load cell amplifier to A2 and A3 instead of pins 12 ,11 solve the problem

@Paul_KD7HB
In case nothing detected an alert should appear first on the screen at first and in case for a longer period with nothing detected it should exit this part and return to the start of the loop section.

Ok, does it work that way when you test it?

No, at all it gives me a constant value on yhe lcd without any relation to any object in front of the sensor.

Yes. I think.

OK, go back to the basics using your current connections:

  1. Only test your load cell and use Serial prints to print the data; remover LCD stuff and keypad.
  2. Get your your display working based on examples.
  3. Integrate these two.

If you don't manage one of the first two, disconnect everything and start from scratch, one component at a time.

@sterretje
I already did that , and every component works fine on its own.
I already removed the load cell connection and now I'm testing the project with ultrasonic sensor only.
I think there a problem in the height module code itself but I'm not sure what it's .

void Height(){                       // height measurement module 
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
  duration_us = pulseIn(echoPin, HIGH);
  distance_cm = 0.017 * duration_us;
  lcd_1.clear();
  lcd_1.setCursor(0, 1); 
  lcd_1.print("Height: ");
  lcd_1.print(distance_cm);
 }

it's the same code I used before with only the ultrasonic sensor connected and It gave already readings on the serial monitor.
but when connected to the project it only one value on the lcd

I can see consulting schematics, for example, to know how to wire up an LCD character display, or a weight sensor module or what-have-you, but I don't see why you need to draw a schematic for every circuit you build. I can certainly see making a list for keeping track of which Arduino pin is doing what (and of course having the information from this list in your code), but what is the drawn schematic for?

So add some serial debug statements in that function.

void loop()
{
  Height();
}

void Height(){                       // height measurement module 
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
  duration_us = pulseIn(echoPin, HIGH);
  distance_cm = 0.017 * duration_us;
  lcd_1.clear();
  lcd_1.setCursor(0, 1); 
  lcd_1.print("Height: ");
  lcd_1.print(distance_cm);
  Serial.print("Height: ");
  Serial.println(distance_cm);
 }

I assume that you have fixed the wiring mistakes that were mentioned earlier.