How to start a device and keep it on with button press

So I am trying to have the arduino start with a press of a button and have it stay on. I also have a calibration function when the button is held down for at least 3 seconds. For some reason, the code goes straight to the calibration function without even touching the button. The button also doesn't affect anything when pressed.

//Tali Mosley
//This code serves to detect the heart of the user and buzz once the heart rate falls below a certain threshold
//First drafted: March 27, 2024
//Last Updated: April 20, 2024


#include <PulseSensorPlayground.h>
#include <ArduinoIoTCloud.h>
#include <Arduino_ConnectionHandler.h>
#include <cstring>
#include "string.h"
#include "thingProperties.h"


const int pulsePin = A0;
const int motorPin = 8;
const int buttonPin = 2;

int pulseValue = 0;
int threshold = 550;
float BPMthreshold = averageBPM * 0.15;

unsigned long lastDebounceTime = 0;
unsigned long debounceDelay = 50;

bool buttonPressed = false;
bool deviceOn = false;

int buttonState = LOW;            
//int lastButtonState = LOW;  

unsigned long buttonPressTime = 0;
unsigned long calibrationStartTime = 0;

bool isCalibrating = false;


PulseSensorPlayground pulseSensor;


void setup() {
  Serial.begin(9600);
  pinMode(motorPin, OUTPUT);
  pinMode(pulsePin, INPUT);
  pinMode(buttonPin, INPUT);

  pulseSensor.analogInput(pulsePin);
  pulseSensor.setThreshold(threshold);


  ArduinoCloud.addProperty(averageBPM, READWRITE, ON_CHANGE, onAverageBPMChange);
  ArduinoCloud.addProperty(BPM, READWRITE, 5 * SECONDS, onBPMChange);

  // Connect to Arduino IoT Cloud
  ArduinoCloud.begin(ArduinoIoTPreferredConnection);
  
  /*
     The following function allows you to obtain more information
     related to the state of network and IoT Cloud connection and errors
     the higher number the more granular information you’ll get.
     The default is 0 (only errors).
     Maximum is 4
 */
  setDebugMessageLevel(2);
  ArduinoCloud.printDebugInfo();
  
}

void loop() {
  updateButton();
  ArduinoCloud.update();
}


void updateButton(){
  int reading = digitalRead(buttonPin);

  // Button state change detection (HIGH to LOW or LOW to HIGH)
  if (reading != buttonState) {
    buttonState = reading;
    if (buttonState == HIGH){
      handleButtonPress();
    }
  }

  // Device is on and not in calibration mode
  if (deviceOn && !isCalibrating) {
    // Continuous pulse detection logic here
    BPM = pulseSensor.getBeatsPerMinute();
    if (BPM < BPMthreshold){
      onBPMChange();
    }

  }
  buttonState = reading;
}

void handleButtonPress() {
  unsigned long currentMillis = millis();
  unsigned long pressDuration = currentMillis - buttonPressTime;
  if (pressDuration >= 3000) { // Check for double press
    // Start Calibration
    startCalibration();
  } else {
    // Turn device on
    deviceOn = true;
  }
  buttonPressTime = currentMillis;
}

void startCalibration() {
    isCalibrating = true;
    int BPMlist[10];
    int sum = 0;
    int sampleCount = 10;

    Serial.println("Waiting for first heartbeat to start calibration...");

    // Wait for the first valid heartbeat
    int BPM = pulseSensor.getBeatsPerMinute();
    while (BPM == 0 || BPM < 60) {  
        BPM = pulseSensor.getBeatsPerMinute();
        delay(100);  // Short delay to keep looping until a heartbeat is detected
    }

    // Now start collecting data
    for (int i = 0; i < sampleCount; i++) {
        BPMlist[i] = BPM;  // Store the first detected BPM
        Serial.print("Sample ");
        Serial.print(i + 1);
        Serial.print(": ");
        Serial.println(BPMlist[i]);

        delay(1500);  // Delay between samples

        // Update BPM for next sample
        BPM = pulseSensor.getBeatsPerMinute();
        while (BPM == 0) {  // In case of momentary loss, wait for next valid BPM
            BPM = pulseSensor.getBeatsPerMinute();
            delay(100);
        }
    }

    // Calculate average from collected samples
    for (int i = 0; i < sampleCount; i++) {
        sum += BPMlist[i];
    }
    averageBPM = sum / sampleCount;

    Serial.print("Average BPM Calculated: ");
    Serial.println(averageBPM);

    isCalibrating = false;
}

//Function to buzz motor
void motorBuzz(){
  unsigned long motorOnTime = millis();
    while(BPM < BPMthreshold && (millis() - motorOnTime < 10000)) {  // Safety timeout of 10 seconds
        digitalWrite(motorPin, HIGH); 
        delay(1000);
        digitalWrite(motorPin, LOW);
        delay(250);
    }
    digitalWrite(motorPin, LOW);
    Serial.println("Motor pattern completed.");
}

void onAverageBPMChange(){
  float avgBPM = averageBPM;  // Assuming AverageBPM is a global variable updated elsewhere

  Serial.print("Updated Average BPM: ");
  Serial.println(avgBPM);

}

void onBPMChange(){
  float currentBPM = BPM;  // Assuming BPM is a global variable updated elsewhere

    if (averageBPM > 0) {  // Ensures averageBPM has been initialized
        if (currentBPM < BPMthreshold) {
            Serial.println("Alert: Current BPM is significantly lower than average.");
            motorBuzz();
            onTimesDipChange();
        }
    }else{
      startCalibration();
    }
    
}

void onTimesDipChange(){
  timesDip += 1;
}

Hi @nclegend28.

Do you have a "pull-down" resistor connected between pins 2 and ground on your Arduino board? If not, the pin will be in a "floating" state where it might be HIGH, LOW, or randomly switching between the two states. That could produce the behavior you encountered.

I have it as a pullup now.

Did that fix it?

It did not

Post an annotated schematic showing how you wired it, include all connections, power, ground, power sources etc. Frizzes and word problems do not work well with me.

From your schematic, I feel R1 and R2 as pulldowns are to small, I would use 10K. Also check you connections to Q1. The way you show it the motor cannot work, the gate needs to connect to pin D8, preferably with a series resister.

Ok, thank you for the insight on the resistors. For Q1 from what I was gaining from reading I've looked at what the connection was for an nMOSFET is and that's how it told me to connect it. 1 going to pin 8, 2 being the drain going to the motor, and 3 going to ground. And I did the electrical check and it said it worked.

Hi @nclegend28,
I based my comment on your diagram in post #7 which shows the gate connected to the motor. I did a cursory search for the BF244A and the diagrams I found all show pin 2 as the gate. Some diagrams for the BF245 show a pin layout to match the description of your connections but the device symbol in your schematic is wrong.

Motor to drain and source to ground is correct, and since it being quite possible that some manufacturer could have your pin layout, you are probably OK. The device symbol in your diagram, however, is still wrong and is what caused the initial confusion.

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