Pressing the push button doesn't utilize the other part of the code

I'm currently making a home security system on tinkerCAD that, when it detects motion, tracks how far away the motion is, displays that information to the lcd, and then plays a tone on a buzzer and lights up an led. All of this works, except that the system needs to be able to switch from inches to cm, vice versa when the push button is pressed. Despite that, whenever I press the push button, it doesn't seem to work at all, and keeps displaying cm. I've spent a long time trying to find out what's wrong, and it's likely I've missed out on something simple, but I haven't come up with a solution.

Code (and the build of the system in case) below:

/*
  The circuit:
 * Push Button pin to digital pin 13
 * LED pin to digital pin 12
 * Buzzer pin to digital pin 11
 * PIR Sensor Signal pin to digital pin 10
 * UDS Trigger pin to digital pin 9
 * UDS Echo pin to digital pin 8
 * LCD RS pin to digital pin 7
 * LCD Enable pin to digital pin 6
 * LCD D4 pin to digital pin 5
 * LCD D5 pin to digital pin 4
 * LCD D6 pin to digital pin 3
 * LCD D7 pin to digital pin 2
 * LCD R/W pin to ground
 * LCD VSS pin to ground
 * LCD VCC pin to 5V
 * 10K resistor:
 * ends to +5V and ground
 * wiper to LCD VO pin (pin 3)
*/

#include <LiquidCrystal.h>

// Initializing variables.
// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(7, 6, 5, 4, 3, 2);
const int TrigPin = 9; 
const int EchoPin = 8; 
long duration = 0; // duration of echo pulse is between 296 and 59200 uS
int ledPin = 12; 
const int inputPin = 10; // choose the input pin (for PIR sensor)
int pirState = 0; // we start, assuming no motion detected
int val = 0; // variable for reading the pin status
int buzzerPin = 11;
int buttonPin = 13;
int buttonState = 0;

void setup() {
  pinMode(TrigPin, OUTPUT);
  pinMode(EchoPin, INPUT);
  pinMode(ledPin, OUTPUT); 
  pinMode(inputPin, INPUT); 
  pinMode(buttonPin, INPUT);
  // set up the LCD's number of columns and rows:
  lcd.begin(16, 2);
}

// Helper functions.
long durationToCentimeters(long microseconds){ 
  return microseconds/58;
}

float durationToInches(float microseconds){ 
  return microseconds/148;
}


void loop() {
  pirState = digitalRead(inputPin); 
  if(pirState == HIGH){
    digitalWrite(TrigPin, LOW);         // output short LOW pulse beforehand to ensure a clean HIGH pulse
    delay (2);
    digitalWrite(TrigPin, HIGH);        // the PING))) is triggered by a HIGH pulse of 10 microseconds
    delay (10);
    digitalWrite(TrigPin, LOW);

    duration = pulseIn(EchoPin, HIGH);  // The EchoPin reads the HIGH pulse signal from the PING)))
	
    buttonState = digitalRead(buttonPin); // Reads when the button is pushed.
    if(buttonState == HIGH){
      	lcd.setCursor(0, 0); // set the cursor to column 0, line 0
      	lcd.print("MOTION DETECTED!");
      	lcd.setCursor(0, 1); // set the cursor to column 0, line 1
    	lcd.print(durationToInches(duration));
      	lcd.print(" Inches");
      	digitalWrite(ledPin, HIGH);
      	tone(11,523,1000);
    }else{
      	lcd.setCursor(0, 0); // set the cursor to column 0, line 0
      	lcd.print("MOTION DETECTED!");
      	lcd.setCursor(0, 1); // set the cursor to column 0, line 1
    	lcd.print(durationToCentimeters(duration));
      	lcd.print(" cm");
      	digitalWrite(ledPin, HIGH);
      	tone(11,523,1000);	
    }
  }else{
    noTone(11);
    digitalWrite(ledPin, LOW);
    lcd.clear();
  }
}

Put in a Serial print of buttonState and see if it is ever high. Then read about pinMode INPUT_PULLUP and/or the use of a pullup resistor.

Steve

1 Like

I've tried a serial print of buttonState, it appears to always be at low (0) and doesn't change even when I press the button. I've also tried your suggestion of a pullup resistor by changing the pinMode(buttonPin, INPUT); to: pinMode(buttonPin, INPUT_PULLUP);. So far it hasn't worked, though please correct me if I didn't use it correctly.

A switch wired to ground, like that, will read HIGH when not pressed and LOW when pressed.

forum button wiring

I don't know how well TinkerCad models the switch, but if a real switch were wired like that it could short the input to ground.

Wire the switch one terminal to ground and the diagonal terminal to the input.

This shows the internal wiring.

1 Like

Would it be something like this?

3ed8f43c15b4388e95173514470d99ad

It still always prints out LOW despite being pressed though.

Did you change the above to pinMode(buttonPin, INPUT_PULLUP); ?

1 Like

Yes, I did.

I don't know how TinkerCad treats pin 13. On real Uno that is also the built-in LED pin. Try a different pin. The analog inputs are digital inputs, too, and have internal pullups.

1 Like

Tysm, apparently pin 13 doesn't function properly on tinkerCAD, so I moved it to pin 12 and it works fine. Only problem is that it only changes to the measurement if I press the button, and if I release it, goes back to the original, which is not what I want. If you have a solution for that I would greatly appreciate it.

Here is an example that toggles the state of a pin and the state if a bool variable (flag). It uses the method from the state change detection tutorial and my state change for active low (low when pressed) switch tutorial.

if you need help to figure out how to use it, post your latest version of your code.

// by C Goulding aka groundFungus

const byte  buttonPin = 2;    // the pin to which the pushbutton is attached
const byte ledPin = 13;       // the pin to which the LED is attached

bool buttonState = 0;         // current state of the button
bool lastButtonState = 0;     // previous state of the button

bool mode = false;

void setup()
{
   // initialize the button pin as a input with internal pullup enabled
   pinMode(buttonPin, INPUT_PULLUP);
   // initialize the LED as an output:
   pinMode(ledPin, OUTPUT);
   // initialize serial communication:
   Serial.begin(115200);
   Serial.println("Select mode with push button");
}

void loop()
{
   static unsigned long timer = 0;
   unsigned long interval = 50;  // check switch 20 times per second
   if (millis() - timer >= interval)
   {
      timer = millis();
      // read the pushbutton input pin:
      buttonState = digitalRead(buttonPin);
      // compare the new buttonState to its previous state
      if (buttonState != lastButtonState)
      {
         if (buttonState == LOW)
         {
            // if the current state is LOW then the button
            // went from off to on:
            digitalWrite(ledPin, !digitalRead(ledPin)); // toggle the output
            mode = !mode;
            if (mode == true)
            {
               Serial.println("Manual mode\n");
            }
            else
            {
               Serial.println("Scan mode\n");
            }
         }
      }
      // save the current state as the last state,
      //for next time through the loop
      lastButtonState = buttonState;
   }
}
1 Like

Here's the latest version of my code, don't want to mess it up just in case.

/*
  The circuit:
 * Push Button pin to digital pin 12
 * LED pin to digital pin 13
 * Buzzer pin to digital pin 11
 * PIR Sensor Signal pin to digital pin 10
 * UDS Trigger pin to digital pin 9
 * UDS Echo pin to digital pin 8
 * LCD RS pin to digital pin 7
 * LCD Enable pin to digital pin 6
 * LCD D4 pin to digital pin 5
 * LCD D5 pin to digital pin 4
 * LCD D6 pin to digital pin 3
 * LCD D7 pin to digital pin 2
 * LCD R/W pin to ground
 * LCD VSS pin to ground
 * LCD VCC pin to 5V
 * 10K resistor:
 * ends to +5V and ground
 * wiper to LCD VO pin (pin 3)
*/

#include <LiquidCrystal.h>

// Initializing variables.
// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(7, 6, 5, 4, 3, 2);
const int TrigPin = 9; 
const int EchoPin = 8; 
long duration = 0; // duration of echo pulse is between 296 and 59200 uS
int ledPin = 13; 
const int inputPin = 10; // choose the input pin (for PIR sensor)
int pirState = 0; // we start, assuming no motion detected
int val = 0; // variable for reading the pin status
int buzzerPin = 11;
int buttonPin = 12;
int buttonState = 0; // current state of the button
bool lastButtonState = 0; // previous state of the button
int clearCounter = 0;

void setup() {
  pinMode(TrigPin, OUTPUT);
  pinMode(EchoPin, INPUT);
  pinMode(ledPin, OUTPUT); 
  pinMode(inputPin, INPUT); 
  pinMode(buttonPin, INPUT_PULLUP);
  // set up the LCD's number of columns and rows:
  lcd.begin(16, 2);
  Serial.begin(9600);
}

// Helper functions.
long durationToCentimeters(long microseconds){ 
  return microseconds/58;
}

float durationToInches(float microseconds){ 
  return microseconds/148;
}


void loop() {
  pirState = digitalRead(inputPin); 
  if(pirState == HIGH){
    digitalWrite(TrigPin, LOW);         // output short LOW pulse beforehand to ensure a clean HIGH pulse
    delay (2);
    digitalWrite(TrigPin, HIGH);        // the PING))) is triggered by a HIGH pulse of 10 microseconds
    delay (10);
    digitalWrite(TrigPin, LOW);

    duration = pulseIn(EchoPin, HIGH);  // The EchoPin reads the HIGH pulse signal from the PING)))
	
    buttonState = digitalRead(buttonPin); // Reads when the button is pushed.
    if(buttonState == HIGH){
      	clearCounter = 0;
      	lcd.setCursor(0, 0); // set the cursor to column 0, line 0
      	lcd.print("MOTION DETECTED!");
      	lcd.setCursor(0, 1); // set the cursor to column 0, line 1
    	lcd.print(durationToInches(duration));
      	lcd.print(" Inches");
      	digitalWrite(ledPin, HIGH);
      	tone(11,523,1000);
    }else{
      	if(clearCounter == 0){
      		lcd.clear();
          	clearCounter++;
        }
      	lcd.setCursor(0, 0); // set the cursor to column 0, line 0
      	lcd.print("MOTION DETECTED!");
      	lcd.setCursor(0, 1); // set the cursor to column 0, line 1
    	lcd.print(durationToCentimeters(duration));
      	lcd.print(" cm");
      	digitalWrite(ledPin, HIGH);
      	tone(11,523,1000);	
      	Serial.println(buttonState);
    }
  }else{
    noTone(11);
    digitalWrite(ledPin, LOW);
    lcd.clear();
  }
}

Now that it is saved, here, you can give it a try. It is late where I am and I have to sleep. I will look at it tomorrow.

1 Like

Alright, thank you so much for helping out, have a good night!

Hello thedarkshadow214
I´ve made a low level flight about your code.
My recommendation study the IPO model to get a structured code.

  • INPUT: button and sensor
  • PROCESSING: action on input data
  • OUTPUT: generate output to LCD, if new are available

Have a nice day and enjoy coding in C++.

1 Like

Here is the code with the state change detection for the button switch added to select measurement mode.

Also you are printing to the LCD way more often than needed. You could slow that down as well using the blink without delay method.

/*
   The circuit:
   Push Button pin to digital pin 12
   LED pin to digital pin 13
   Buzzer pin to digital pin 11
   PIR Sensor Signal pin to digital pin 10
   UDS Trigger pin to digital pin 9
   UDS Echo pin to digital pin 8
   LCD RS pin to digital pin 7
   LCD Enable pin to digital pin 6
   LCD D4 pin to digital pin 5
   LCD D5 pin to digital pin 4
   LCD D6 pin to digital pin 3
   LCD D7 pin to digital pin 2
   LCD R/W pin to ground
   LCD VSS pin to ground
   LCD VCC pin to 5V
   10K resistor:
   ends to +5V and ground
   wiper to LCD VO pin (pin 3)
*/

#include <LiquidCrystal.h>

// Initializing variables.
// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(7, 6, 5, 4, 3, 2);
const int TrigPin = 9;
const int EchoPin = 8;
long duration = 0; // duration of echo pulse is between 296 and 59200 uS
int ledPin = 13;
const int inputPin = 10; // choose the input pin (for PIR sensor)
int pirState = 0; // we start, assuming no motion detected
int val = 0; // variable for reading the pin status
int buzzerPin = 11;
int buttonPin = 12;
int clearCounter = 0;

// *********** deleted global buttonState and lastbuttonState
// *********** made them local to the checkButton function
bool mode = false; // ******* measurement mode 

void setup()
{
   pinMode(TrigPin, OUTPUT);
   pinMode(EchoPin, INPUT);
   pinMode(ledPin, OUTPUT);
   pinMode(inputPin, INPUT);
   pinMode(buttonPin, INPUT_PULLUP);
   // set up the LCD's number of columns and rows:
   lcd.begin(16, 2);
   Serial.begin(9600);
   Serial.println("program started"); // ******* added
}

// Helper functions.
long durationToCentimeters(long microseconds)
{
   return microseconds / 58;
}

float durationToInches(float microseconds)
{
   return microseconds / 148;
}


void loop()
{
   pirState = digitalRead(inputPin);

   checkButton();  // ******* added

   if (pirState == HIGH)
   {
      digitalWrite(TrigPin, LOW);         // output short LOW pulse beforehand to ensure a clean HIGH pulse
      delay (2);
      digitalWrite(TrigPin, HIGH);        // the PING))) is triggered by a HIGH pulse of 10 microseconds
      delay (10);
      digitalWrite(TrigPin, LOW);

      // ************* added a timeout to the pulseIn
      duration = pulseIn(EchoPin, HIGH, 20000);  // The EchoPin reads the HIGH pulse signal from the PING)))

      //buttonState = digitalRead(buttonPin); // Reads when the button is pushed.
      if (mode == HIGH) // changed to check mode instead of buttonState
      {
         clearCounter = 0;
         lcd.setCursor(0, 0); // set the cursor to column 0, line 0
         lcd.print("MOTION DETECTED!");
         lcd.setCursor(0, 1); // set the cursor to column 0, line 1
         lcd.print(durationToInches(duration));
         lcd.print(" Inches");
         digitalWrite(ledPin, HIGH);
         tone(11, 523, 1000);
         Serial.println("inch mode"); // ****** added
      }
      else
      {
         if (clearCounter == 0)
         {
            lcd.clear();
            clearCounter++;
         }
         lcd.setCursor(0, 0); // set the cursor to column 0, line 0
         lcd.print("MOTION DETECTED!");
         lcd.setCursor(0, 1); // set the cursor to column 0, line 1
         lcd.print(durationToCentimeters(duration));
         lcd.print(" cm");
         digitalWrite(ledPin, HIGH);
         tone(11, 523, 1000);
         Serial.println("cm mode");  // ****** added
      }
   }
   else
   {
      noTone(11);
      digitalWrite(ledPin, LOW);
      lcd.clear();
   }
}

void checkButton() // check state of button switch
{
   static unsigned long timer = 0;
   unsigned long interval = 20;
   if (millis() - timer >= interval)
   {
      timer = millis();
      static bool lastButtonState = HIGH;
      bool buttonState = digitalRead(buttonPin);
      if (buttonState != lastButtonState)
      {
         if (buttonState == LOW)
         {
            mode = !mode;
         }
      }
      lastButtonState = buttonState;
   }
}

1 Like

Thank you so much, the code works perfectly and everything runs smoothly, I'm so thankful for you helping me over the course of these 2 days, you're a wonderful person.

Thank you for the recommendation, it did help a bit.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.