Timer or Push Button to trigger Motor

Hi everyone! My first post. If it is in the wrong spot, I'm sorry. I have an Area51 project for our train club where I launch a balloon with a controlled fan (like the old Johnny Astro) and bring it back down. It is my first code and it is probably not a great attempt, but it works. First I had the code on just a loop to test, then I put it on a button. The unit is running on a 10,000mA phone charging battery, which I found out will turn off in one minute if not used. So currently, I have a 15 second delay to keep the button from being pushed right away, but now I need an additional timer for say, 15 seconds, to repeat the program so that the battery remains active.

I am posting the code and hope that you will critique it. I hope that someone can also help me with a simple solution to the above problem. Thanks for your help.

/*
  

  Turns on and off and controls a motor attached to digital pin 9,
  when pressing a pushbutton attached to pin 2.

  The circuit:
  - DC Motor attached from pin 9 to ground through an N-Channel Mosfet
  - pushbutton attached to pin 2 from +5V
  - 10K resistor attached to pin 2 from ground

  

  created 2024
  by Don Whatley
  modified 30 Aug 2024
  by KEith Ratliff

  There is example code is in the public domain for fading LED and a momentary Switch.

  https://www.arduino.cc/en/Tutorial/BuiltInExamples/Button
*/

// constants won't change. They're used here to set pin numbers:
const int buttonPin = 2;  // the pin that the pushbutton is attached to
const int MOTORPin = 9;    // MOTOR connected to digital pin 9

// variables will change:
int buttonState = 0;  // current state of the button
int lastButtonState = 0;    // previous state of the button

void setup() {
// initialize the button pin as a input:
  pinMode(buttonPin, INPUT);
}

void loop() {

  // read the pushbutton input pin:
  buttonState = digitalRead(buttonPin);

 // compare the buttonState to its previous state
  if (buttonState != lastButtonState) {
    // if the state has changed, increment the counter
    if (buttonState == HIGH) {
     // if the current state is HIGH then the button went from off to on: 
     // Delay a little bit to avoid bouncing
    delay(50);
}
 

 // fade in from min to max in increments of 3 points:
      for (int fadeValue = 0 ; fadeValue <= 200; fadeValue += 3) {
        // sets the value (range from 0 to 200):
        analogWrite(MOTORPin, fadeValue);
        // wait for 60 milliseconds to see the dimming effect
        delay(60);
      }
      
      delay(10000);   // wait 10 seconds
      
      // fade out from max to min in increments of 3 points:
      for (int fadeValue = 200 ; fadeValue >= 0; fadeValue -= 3) {
        // sets the value (range from 0 to 200):
        analogWrite(MOTORPin, fadeValue);
        // wait for 60 milliseconds to see the dimming effect
        delay(60);
      
      }
      delay(15000);   // wait 15 seconds
  }
  }

  • Where is lastButtonState updated ?

  • Never ever use delay( . . . ) in your sketches (well unless you know why) as it stops program from executing during the wait time.

  • Look at the IDE example:

https://docs.arduino.cc/built-in-examples/digital/BlinkWithoutDelay/

  • With manual switches, look at when they change state, not their level.

  • Always show us a good schematic of your proposed circuit.
    Show us good images of your ‘actual’ wiring.
    Give links to components.

  • For readability, place { and } on separate lines by themselves, place each line of code on a separate line.

  • In the Arduino IDE, use Ctrl T or CMD T to format your code, then copy the complete sketch.

Try this sketch version:

//
//================================================^================================================
//
//  https://forum.arduino.cc/t/timer-or-push-button-to-trigger-motor/1298664/2
//
//
//
//  Version    YY/MM/DD    Comments
//  =======    ========    ========================================================================
//  1.00       24/09/04    Running code, we still need to add button switch action
//
//
//
//  Notes:
//


#define PRESSED                 HIGH    //+5V---[Switch]---Pin---[10k]---GND
#define RELEASED                LOW

#define ENABLED                 true
#define DISABLED                false

#define MOTORon                 HIGH
#define MOTORoff                LOW


//                                            G P I O s
//================================================^================================================
//
const byte buttonPin          = 2;
const byte MOTORPin           = 9;
const byte heartbeatLED       = 13;

//                                        V A R I A B L E S
//================================================^================================================
//
bool balloonFlag              = DISABLED;

int fadeCounter;
int buttonState;
int lastButtonState           = RELEASED;

//timing stuff
unsigned long heartbeatTime;
unsigned long switchesTime;
unsigned long automaticTime;
unsigned long commonTime;
unsigned long machineTime;

unsigned long automaticInterval  = 30ul * 1000;  //30 seconds, should be less than the auto shut off time


//                                    S t a t e   M a c h i n e
//================================================^================================================
//the states in our machine
enum STATES : byte
{
  STARTUP, BALLOONup, WAITINGup, BALLOONdown, WAITINGdown
};

STATES mState = STARTUP;


//                                           s e t u p ( )
//================================================^================================================
void setup()
{
  Serial.begin(115200);

  pinMode(heartbeatLED, OUTPUT);
  pinMode(MOTORPin, OUTPUT);
  pinMode(buttonPin, INPUT);

  Serial.println("System Restart");

} //END of   setup()


//                                            l o o p ( )
//================================================^================================================
void loop()
{
  //========================================================================  T I M E R  heartbeatLED
  //is it time to toggle the heartbeat LED ?
  if (millis() - heartbeatTime >= 500ul)
  {
    //restart this TIMER
    heartbeatTime = millis();

    //toggle the heartbeat LED
    digitalWrite(heartbeatLED, digitalRead(heartbeatLED) == HIGH ? LOW : HIGH);
  }

  //========================================================================  T I M E R  switches
  //is it time to scan our switches ?
  if (millis() - switchesTime >= 50ul)
  {
    //restart this TIMER
    switchesTime = millis();

    checkSwitches();
  }

  //========================================================================  T I M E R  automatic
  //if the balloon is not moving, is it time to automatically move the balloon ?
  if (mState == STARTUP && millis() - automaticTime >= automaticInterval)
  {
    Serial.println("Balloon automatic operation started");

    //starting the balloon sequence automatically
    mState = BALLOONup;

    //motor speed starts out at 0
    fadeCounter = 0;

    //restart the TIMER
    commonTime = millis();
  }

  //========================================================================  T I M E R  machine
  //is it time to check our State Machine ?
  if (millis() - machineTime >= 10ul)
  {
    //restart this TIMER
    machineTime = millis();

    checkMachine();
  }

  //================================================
  //other non blocking code goes here
  //================================================


} //END of   loop()


//                                    c h e c k M a c h i n e ( )
//================================================^================================================
void checkMachine()
{
  //================================================
  //service the current "machine state"
  switch (mState)
  {
    //========================
    case STARTUP:
      {
        //do startup stuff
      }
      break;

    //========================   increase the speed from 0 to 200
    case BALLOONup:
      {
        //has the common TIMER expired ?
        if (millis() - commonTime >= 60ul)
        {
          //restart TIMER
          commonTime = millis();

          //increase motor speed
          analogWrite(MOTORPin, fadeCounter);

          fadeCounter = fadeCounter + 3;

          //have we reached maximum speed ?
          if (fadeCounter > 200)
          {
            Serial.println("Balloon is at maximum");

            //next State
            mState = WAITINGup;

            //restart the TIMER
            commonTime = millis();

            break;
          }
        }
      }
      break;

    //========================   wait here for 10 seconds
    case WAITINGup:
      {
        //has the common TIMER expired ?
        if (millis() - commonTime >= 10000ul)
        {
          Serial.println("Balloon is going down");

          fadeCounter = 200;

          //next State
          mState = BALLOONdown;

          //restart TIMER
          commonTime = millis();

          break;
        }
      }
      break;

    //========================   decrease the speed from 200 to 0
    case BALLOONdown:
      {
        //has the common TIMER expired ?
        if (millis() - commonTime >= 60ul)
        {
          //restart TIMER
          commonTime = millis();

          //decrease motor speed
          analogWrite(MOTORPin, fadeCounter);

          fadeCounter = fadeCounter - 3;

          //have we reached minimum speed ?
          if (fadeCounter < 0)
          {
            Serial.println("Balloon is at minimum");

            fadeCounter = 0;

            //stop motor
            analogWrite(MOTORPin, fadeCounter);

            //next State
            mState = WAITINGdown;

            //restart the TIMER
            commonTime = millis();

            break;
          }
        }
      }
      break;

    //========================   wait here for 15 seconds
    case WAITINGdown:
      {
        //has the common TIMER expired ?
        if (millis() - commonTime >= 15000ul)
        {
          Serial.println("Balloon sequence has ended");

          //restart the automatic TIMER
          automaticTime = millis();

          //next State
          mState = STARTUP;

          break;
        }
      }
      break;

  } //END of   switch/case

} //END of   checkMachine()



//                                   c h e c k S w i t c h e s ( )
//================================================^================================================
void checkSwitches()
{
  byte state;

  //========================================================================  buttonPin
  state = digitalRead(buttonPin);

  //================================================
  //has this switch changed state ?
  if (lastButtonState != state)
  {
    //update to the new state
    lastButtonState = state;

    //========================
    //if the balloon is stopped, has the switch been pressed ?
    if (mState == STARTUP && state == PRESSED)
    {
      Serial.println("Balloon is going up");

      fadeCounter = 0;

      //restart the TIMER
      commonTime = millis();

      //start the sequence for going up
      mState = BALLOONup;
    }

  } //END of this switch

  //========================================================================  nextSwitch

} //END of   checkSwitches()



You need a "dummy" load to draw the minimum current that will keep the charger from shutting off. Do you have some resistors in the 100 to 220Ω range and an NPN transistor like 2n2222, 2n4401, 2n3904 or a spare N channel logic level MOSFET?

LarryD,
Thank you for that. It is a lot more advanced than my first code (which was my very first attempt at code). I will try this today. Is the total time after ramp down 30 seconds? I guess I will test.
Here is the schematic and wiring. Thanks


7199cd0c99c0706827905691fbac658a354ee2ad

Sorry,
The motor is on a separate power supply and this mosfet is fed through pin 9 and ground.
Here is a link to the test. https://youtube.com/shorts/uQcEIwoFI90?feature=share

  • If that is your YouTube video the MOSFET looks it can be controlled by the 5v Arduino, good.

  • You should add the MOSFET and fan circuit to your drawing.

  • The sketch offered you in post number 2 (two) should be close to what you ask for, it can be easily change to accommodate your needs.

  • The heartbeat LED toggles ON every 1 second.
    For testing, you can time things by counting the number of toggles.

  • Use the Serial Monitor set to 115200 with timing enabled.
    You should see the progression printed on the serial monitor.

  • As mentioned, the power bank needs a minimum load current. @JCA34F

  • A second MOSFET controlling current to a 100 ohm resistor can be operated once per 45 to 55 seconds (ON for a second) . This will keep the power bank from turning OFF.

Thanks again. The code works great. There is a 45 second lag after the motor shuts off (15 seconds motor idle + 30 second delay) and that is fine. I don't think I will need to add a second mosfet to keep the battery enabled, but I can see where that would be beneficial in some cases. I have also been using the old bootloader and didn't in this case. What is the difference?
What is the serial.println for? Is that for a small OLED? That sounds cool. Someone suggested I add Close encounters of a third kind music tones.
This project started from an old Johnny Astro I use to own and I decided to add it to our Area 51 Train Layout for the kids so they could push a button to control the balloon. The fan has to ramp up and ramp down to keep pressure on the balloon so that it stays in the column. The frisbee was an afterthought to keep the balloon above the fan.
Thanks again for your help. I need to learn this stuff.

  • This will not affect your sketch.



  • These numbers affect your fan timing, play with them to see how they change things.


  • You should be aware this sketch version allows things to happen at the same time.
    The sketch does not use delay( . . . ) hence it is non blocking.
    Always write your sketch in a non blocking fashion.

  • If you do not ask questions, you will not learn anything.

  • Google Arduino IDE serial monitor.

  • Read up on its function.