Multi tasking structre for my arduino sketch

I'm a bit confused... What's exactly the problem(s) on your code? I see here you cited three...
You wrote first:

then also:

and:

Those are completely different problems, to be addressed with different approaches.

Starting with the first one, let me say I don't see why you need a library for a beeper, especially if (as I think is this case) you use it just to give some kinda short audible feedback for keypresses, and not play a song or a melody (hope not...).
Use either an active beeper (i.e. it beeps a fixed tone while its pin is kept HIGH) or the internal tone() function (remember it'll interfere with PWM on pins 3 and 11, in case you use PWM with those pins).

For the second, you haven't provided the model of your sensor.
Based on your description, I fear it's a faulty HC-SR04 because I had a lot of problems with that model! They're often faulty, meaning they aren't reliable and many of them will get "stuck" with a value (in my case it was zeero!) until you turn it off, or use a workaround I found at the time. It's 5 or 6 years I switched to the HY-SRF05 that costs a few cents more, but I never had problems with that so I strongly suggest you to throw the SR04 away and use SRF05 (or, at least use another SR04 if you have another one, and hope it's not as fauly as the first one...).
If for any reason you can't do it at the moment, give this library a try (for english description and usage, open the README_EN.txt file). Even if the name refers to SRF05, it's the library I wrote years ago for myself to solve my problems with SR04, as it uses the workaround I found to "unlock" the sensor.

For the third issue, I think the problem is the pin conflict others have already said, so you should have already cleared it (just change the pin definitions, it's impossible you connected both devices to the same pins 11 and 12...).

PS: there's no actual need for "multitasking" here, first of all because Arduino can't do any "multitasking", secondly because you have two states only to define the measuring mode (weight onyl and weight and height), a boolean global variable does the job.

Just to add something I missed about the first issue (the beeper won't beep if the code is busy elsewhere): you currently handle the "keyboard beeps" inside the "Beep()" function, but you have keyboard inputs handled inside a "while()" code also, and in that case the "Beep()" won't be called so you just need to either add the same "buzzer.beep(100);" function call here (and in every place where you want to do so) or change the "Beep()" function to be more "general" and use it to check keypresses and play the beep for every key, something like this (not tested, and it's just a code snippet you need to integrate with your code) where I made "customKey" a global variable to avoid proliferation of the same variables with the same value, then get rid of the "ezBuzzer" library and use "tone()":

...
// Last key pressed
char customKey;

// The function checks if a key is pressed, generating the keyboard feedback tone 
// and returns true if a key has been pressed, storing its code in the 
// "customKey" global variable
bool KeyPressed() {
  bool KeyGood = false;
  customKey = 0;
  char key = customKeypad.getKey();
  if (key) {
    lastKeypressTime = millis(); // update the lastKeypressTime variable with the current time
    customKey = key;
    Serial.print(customKey); // prints key to serial monitor
    //buzzer.beep(100);  // generates a 100ms beep
    tone(BUZZER_PIN, 1000, 100);
    KeyGood = true;
  }
  return Keygood;
}


void loop(){
  if (KeyPressed()) 
  { //if there is any input, the key code is in "customKey"
    lcd_1.clear();
    lcd_1.setCursor(0,0);
...

the use the same approach For the phone input phase, I suggest you to

I tried this method
but it's the same problem beeping only on the first key press.

bool KeyPressed() {
  static unsigned long lastKeypressTime ;
  bool KeyGood = false;
  char customKey = 0;
  char key = customKeypad.getKey();
  if (key) {
    lastKeypressTime = millis(); // update the lastKeypressTime variable with the current time
    customKey = key;
    Serial.print(customKey); // prints key to serial monitor
    //buzzer.beep(100);  // generates a 100ms beep
    tone(BUZZER_PIN, 1000, 100);
    KeyGood = true;
  }
  return KeyGood;
}

and for the loop


  static unsigned long lastKeypressTime = 0; // initialize the lastKeypressTime variable
  char customKey = customKeypad.getKey();  // variable for the input key
  
  if (KeyPressed())  //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();
--------------------------------

@docdoc
regarding the ultrasonic sensor , yes my sensor happen to be the HC-SR04
I will try using your library and gonna give you feedback

Visualization/communication aid.  Especially communicating with your six-months-from-now self.

@docdoc
I think a good strategy is to modify the void loop () code so it can perform the same function while performing the same task without using the while loop, I've tried removing the first while loop but the code did not proceed.
So how to retain the code function but removing the while loop.

  1. When asking for help it lets other people see exactly what you have. For example is there a disconnect between your code and the hardware. That includes, how much decoupling you have, do you need voltage level shifters between various components of your system. Have you added pull up resistors to any I2C busses you might have? And lots lots more.

  2. So that you know what you have when you get to do another similar project next year, you have some where to start from.

  3. If you ever want to publish the project or make that definitive You Tube video.

  4. When a friend asks you to make them another one.

  5. But most of all so that you can see what you have got.

Thanks for the part of the schematic you have shown. However:-

I thought that was your major problem, so is it completely missing?

:roll_eyes:

Yes that is the problem with using software to create your schematic. Unless you have the skill to generate the components you need then it is some what useless posting what you have done.

Three ways to go:-

  1. Learn how to create symbols in Tinker Cad.

  2. Find another drawing package that has those symbols, but it is a bit of a waste of time.

  3. Use a universal symbol drawing tool for drawing your schematic, like this one:-

Schematic Generator

2 Likes

It's the best way to handle this kind of things, but requires you to study and implement a finite state machine, and I think it'd be a bit tough for you based on your current knowledges. And I suggest you to always keep the loop() function more compact as possible, by packing each "logical section" into separate functions, it helps you to achieve a better structured programming and make debugging easier.

You always better post the full code, not just snippets, because we can't either see how the things are handled or even test it separately.
On any "new" thing you must handle (e.g. a specific function, or a new device/sensor...), always start writing a small sketch to test with a single topic is always the best practice, and helps you to better understand some possible solutions. Please note this is the same thing I myself often do.

In this case, forget about ultrasonic sensor and LCD, and keep just the buzzer and the keypad: try writing a sketch to ask for user input like the phone number, followed by an "end" key (e.g. "#"), with a single beep each time the user enters a digit, and print to serial the current stored number, then when "#" is pressed, exit with the resulting entered number.
You could even do that using any online simulator like Wokwi and/or Tinkercad, just to avoid building and connecting "real" devices. I strongly recommend you to start using such simulators, for both code testing and getting schematics!

Ok, so once you have made such sketch, you could edit it to pack the logic as a function (e.g. a "bool EnterPhone()") that stores the entered number in a global buffer variable (e.g. "char PhoneNumber[20]") and returns "true" (or resetting the buffer to a null string and returning "false" if the user pressed an "exit" key like "*" or for input timeout). This means you can then on your "main" program call the function and just check the returned value.

Ok, in case you need help, post here the full code and we'll have a look at it. But do things one at a time and/or one step at a time. Solve the phone number input and tone first, then create another test sketch for the ultrasonic sensor, and lastly put everything together in your "main" code. And if something don't work properly, almost always is something related just to the way you combined those procedures, and not the single procedure.

@docdoc
You are correct, so let's solve the key press beep input at first.
here is the full sketch that didn't work

#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, distance1;
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:");*/
 }  
 
 bool KeyPressed() {
  static unsigned long lastKeypressTime ;
  bool KeyGood = false;
  char customKey = 0;
  char key = customKeypad.getKey();
  if (key) {
    lastKeypressTime = millis(); // update the lastKeypressTime variable with the current time
    customKey = key;
    Serial.print(customKey); // prints key to serial monitor
    //buzzer.beep(100);  // generates a 100ms beep
    tone(BUZZER_PIN, 1000, 100);
    KeyGood = true;
  }
  return KeyGood;
}

void Height(){                       // height measurement module 
  digitalWrite(trigPin, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
  duration_us = pulseIn(echoPin, HIGH);
  distance_cm = 0.017 * duration_us;
  distance1= 180 - distance_cm ;
  lcd_1.clear();
  lcd_1.setCursor(0, 1); 
  lcd_1.print("Height: ");
  lcd_1.print(distance1);
  Serial.print("Height: ");
  Serial.println(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 loop(){
  
  
  static unsigned long lastKeypressTime = 0; // initialize the lastKeypressTime variable
  char customKey = customKeypad.getKey();  // variable for the input key
  
  if (KeyPressed())  //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;
  // Height();
}

@docdoc
HERE I made a simulation on Wokwi where I made a sketch just to print to the serial printer and in the same time make a buzz on every key press and it worked fine .
here is the full code

#include <Keypad.h>
#include <LiquidCrystal.h>

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] = {10 ,9, 8, 7};      // connect to the row pinouts of the keypad
byte pin_column[COLUMN_NUM] = {6, 5, 4, 3}; // connect to the column pinouts of the keypad

Keypad customKeypad = Keypad(makeKeymap(keys), pin_rows, pin_column, ROW_NUM, COLUMN_NUM );
const int BUZZER_PIN = 12;




void setup () {
  pinMode(BUZZER_PIN, OUTPUT);

}

void loop () {
  char customKey = customKeypad.getKey();
  if (customKey) {
    tone(BUZZER_PIN, 750, 100); // make a beep sound
  }
  if (customKey) {
     if (customKey != NO_KEY) {
       Serial.print(customKey);
      }
     
    
  }
}

and here is the link

how do you find it ?

@docdoc
here is another modified code that worked but not as required.

#include <Keypad.h>
#include <LiquidCrystal.h>

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] = {10 ,9, 8, 7};      // connect to the row pinouts of the keypad
byte pin_column[COLUMN_NUM] = {6, 5, 4, 3}; // connect to the column pinouts of the keypad

Keypad customKeypad = Keypad(makeKeymap(keys), pin_rows, pin_column, ROW_NUM, COLUMN_NUM );
const int BUZZER_PIN = 12;




void setup () {
  pinMode(BUZZER_PIN, OUTPUT);

}

void loop () {
  char customKey = customKeypad.getKey();
  if (customKey) {
    tone(BUZZER_PIN, 750, 100); // make a beep sound
  }
  if (customKey) {
     if (customKey != NO_KEY) {
       //Serial.print(customKey);
       Serial.print("Enter your PhoneNo.: "); 
       class String PhoneString = "";                   
       char PhoneKey = customKeypad.getKey();
       if (PhoneKey) {              
         // Initialize if a key is pressed
          Serial.print(PhoneKey);
          PhoneString += PhoneKey; // Append the entered digit to the age string
          Serial.print(PhoneString);
           if (PhoneString.length() == 11) {              // If the age string has two digits, categorize the age
            
            Serial.print("Your Phone is: ");
            Serial.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();
           } 
        } 


      }
     
    
  }
}

it's almost the same as on my Arduino sketch but not giving the same result , I wonder how to correct it?

@Grumpy_Mike
Here is a hand drawn version .
This what I could do, I hope you find it useful.
My project schematic view.pdf (76.6 KB)

Thanks.
Now the HX711 is it a device or is it a board with that device on it?
If it is the spark fun board then a look at the schematic on the spark fun site shows no pull up resistors on the board. And your schematic shows no pull up resistor on pins A4 and A5. You need pull up resistors on these pins because the internal pull up resistors on the Nano & Uno are not strong enough to give a proper signal.

The actual value is not too critical but anywhere between 3K and 10K will do. I recommend using 4K7.

1 Like

It's not the sparkfun hx711 but I think it's a clone of it.
Is pull up residtor is the normal resistor??

So from your reply I understand that the hardware is connected properly.
So the problem in hand now is the buzzer in not beeping on each keyoress
I tried to modify the code but it didn't work either as you can see from the link here.
So could you please check the problem with the code.
Here the link to the wokwi simulation

here is a new faulty code

#include <Keypad.h>
#include <LiquidCrystal.h>

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] = {10 ,9, 8, 7};      // connect to the row pinouts of the keypad
byte pin_column[COLUMN_NUM] = {6, 5, 4, 3}; // connect to the column pinouts of the keypad

Keypad customKeypad = Keypad(makeKeymap(keys), pin_rows, pin_column, ROW_NUM, COLUMN_NUM );
const int BUZZER_PIN = 12;




void setup () {
  pinMode(BUZZER_PIN, OUTPUT);

}

void loop () {
  char customKey = customKeypad.getKey();
  if (customKey) {
    tone(BUZZER_PIN, 750, 100); // make a beep sound
  }
  if (customKey) {
     if (customKey != NO_KEY) {
       //Serial.print(customKey);
       Serial.print("Enter your PhoneNo.: "); 
       class String PhoneString = "";                   
       char PhoneKey = customKeypad.getKey();
       if (PhoneKey) {              
         // Initialize if a key is pressed
          Serial.print(PhoneKey);
          PhoneString += PhoneKey; // Append the entered digit to the age string
          Serial.print(PhoneString);
           if (PhoneString.length() == 11) {              // If the age string has two digits, categorize the age
            
            Serial.print("Your Phone is: ");
            Serial.print(PhoneString);
           //delay(1000); 
           // Convert the age string to an integer
            int Phone = PhoneString.toInt(); 
           //lastKeypressTime = 0;
           //if (millis() -lastKeypressTime > 10000) {  
            PhoneString = "";
            delay(1000);
             
           } 
        } 


      }
     
    
  }
}

How do you gather that? You have no pull resistors on the I2C lines.

@Grumpy_Mike
Sure I will add them when reconnecting the load cell
The problem I face now is with beep sound when pressing any key.

I'm afraid it doesn't.
First of all, to use Serial prints you need to call "Serial.begin(9600)" (or whatever speed you need) from the setup(), and here you haven't added it.
Second, the connections appear to be quite "strange", you overlapped many connections, and it looks like you "mixed" a couple of wires. Always make clean drawings, with clearly understandable ad identificable wirings, and possibly distinguishing the various types of wires with different colors (always red for +5V, black for GND, and for example yellow for digital outputs, green for inputs, blue for I2C, and so on), and set wire routes with specific curves to avoid overlapping. This will also help you post here your schematics instead of paper and pen.
You could obtain this (it's your project where I changed a bit of things...):
image
Don't you find it clearer and more understandable than yours?

This is my version (you can save it on your project library and start from here):

Next, about the digits input code I think you need to start from scratch instead of going around with the same approach you had before. Clean the code up and start with a simple digits inputs (to be shown over Serial, forget about the display for a moment), where you ask the user to enter a number followed by a terminating character like "#" or reset the entered digits with another key like "C". And remember you should add every digit to a string buffer, use a global variable to make things easier (and not a "String" local variable).

I mean, forget about timeouts or any other thing, and focus on the keyboard input only, then making a short beep on each keypress. Use the same Wokwi project I linked you (btw keep the LCD for next develop steps) and try to create code for this first task, and post it here again if you need help.

1 Like

I'm made some changes here,
but I didn't get the correct sequence which is,
you ask "Enter your phone NO."
then printing the numbers to the serial monitor.
while beeping at the same time
like here
KEY TO LCD Alex Copy - Wokwi ESP32, STM32, Arduino Simulator

you get only beeping with either entering the phone Number or asking
Enter your phone NO." .