We are working on a project where two motors will run (either simultaneous or after one another) for X seconds once a button is held. So when you press the button, the motors will run for X sec, then stop, and be ready to go for another X once the button is released and pressed again. The motors must also stop if the button is released prematurely, before X sec.
The Project is for a powder/water dispenser
What would be the best way to approach this?
The code here is where we are at right now…
Thank you <3
void setup() {
// put your setup code here, to run once:
pinMode(4,OUTPUT);
pinMode(8,OUTPUT);
pinMode(2,INPUT);
Serial.begin(115200);
if(digitalRead(2))
{
for(int i=0;i<1000;i++)
{
digitalWrite(4,HIGH);
delay(1);
}
digitalWrite(4,LOW);
for(int i=0;i<1000;i++)
{
digitalWrite(8,HIGH);
delay(1);
}
digitalWrite(8,LOW);
}
else
{
digitalWrite(4,LOW);
digitalWrite(8,LOW);
}
}
int i;
void loop() {
// put your main code here, to run repeatedly:
if(digitalRead(2))
{
for(int i=0;i<1000;i++)
{
digitalWrite(4,HIGH);
delay(1);
}
digitalWrite(4,LOW);
for(int i=0;i<1000;i++)
{
digitalWrite(8,HIGH);
delay(1);
}
digitalWrite(8,LOW);
}
else
{
digitalWrite(4,LOW);
digitalWrite(8,LOW);
}
}
A state machine approach might look something like this:
/*
* We are working on a project where two motors will run (either simultaneous or
* after one another) for X seconds once a button is held. So when you press the
* button, the motors will run for X sec, then stop, and be ready to go for another
* X once the button is released and pressed again. The motors must also stop if
* the button is released prematurely, before X sec.
*/
const uint32_t K_MAXIMUM_DURATION = 7000ul; //mS 7-sec 'X' as described in the above comment
const uint32_t K_PAUSE_DURATION = 2000ul; //mS 2-sec pause after motors stop before allowing them to start again
const uint32_t K_BTN_READ_TIME = 20ul; //mS 20mS button read period
const uint8_t pinButton = 2; //button input (wire so press grounds button; no-press is open circuit
const uint8_t pinMotor1 = 4; //motor 1
const uint8_t pinMotor2 = 8; //motor 2
const uint8_t pinLED = LED_BUILTIN; //"ready" light
uint8_t
lastButton;
//button press return values
typedef enum
{
NO_BUTTON=0, //no button state change
BTN_PRESSED, //button went from not-pressed to pressed
BTN_RELEASED //button went from pressed to not-pressed
}eButtonStates_t;
//motor control states
typedef enum
{
ST_INIT=0, //initialize motors to "off"
ST_IDLE, //waiting for button press
ST_RUNNING, //motors running; waiting for button release or timeout
ST_PAUSE //after-run pause before re-enabling
}eMotorStates_t;
void setup( void )
{
Serial.begin(115200); //debug/information messages
pinMode( pinMotor1, OUTPUT );
pinMode( pinMotor2, OUTPUT );
pinMode( pinLED, OUTPUT );
digitalWrite( pinLED, HIGH ); //turn on LED indicating "ready"
//
pinMode( pinButton, INPUT_PULLUP );
lastButton = digitalRead( pinButton );
}//setup
void loop( void )
{
MotorControl();
}//loop
uint8_t chkButton( void )
{
static uint32_t
timeButton = 0ul;
uint32_t
timeNow;
//read the button at periodic intervals (once every K_BTN_READ_TIME milliseconds)
timeNow = millis();
if( (timeNow - timeButton) < K_BTN_READ_TIME )
return NO_BUTTON; //if not time for a read just return "no button"
timeButton = timeNow;
uint8_t nowButton = digitalRead( pinButton ); //read the state of the button now
//different than last read?
if( nowButton != lastButton )
{
//this read wasn't the same as the last
lastButton = nowButton;
if( nowButton == LOW )
{
//if LOW now the button has been pressed
Serial.println( "Button pressed" );
return BTN_PRESSED;
}//if
else
{
//if HIGH now button has been released
Serial.println( "Button released" );
return BTN_RELEASED;
}//else
}//if
//if we get here, button has not changed state so return "no button"
return NO_BUTTON;
}//chkButton
void MotorControl( void )
{
static uint8_t
stateMotor = ST_INIT;
static uint32_t
timeMotor;
uint32_t timeNow;
uint8_t
btnCond;
timeNow = millis(); //get current millis count
btnCond = chkButton(); //and check the button
switch( stateMotor )
{
case ST_INIT:
//initial state; turn off the motors and proceed to idle
digitalWrite( pinMotor1, LOW );
digitalWrite( pinMotor2, LOW );
stateMotor = ST_IDLE;
break;
case ST_IDLE:
if( btnCond == BTN_PRESSED )
{
//if we detect button pressed, start motors
digitalWrite( pinMotor1, HIGH );
digitalWrite( pinMotor2, HIGH );
//turn OFF the LED to indicate system is busy
digitalWrite( pinLED, LOW );
//save this time so we can measure the run duration
timeMotor = timeNow;
Serial.println( "Motors running" );
stateMotor = ST_RUNNING;
}//if
break;
case ST_RUNNING:
if( (btnCond == BTN_RELEASED) || ((timeNow - timeMotor) >= K_MAXIMUM_DURATION) )
{
//button was released or we saw a time-out; turn off the motors
digitalWrite( pinMotor1, LOW );
digitalWrite( pinMotor2, LOW );
//save the time so we can measure the pause duration
timeMotor = timeNow;
Serial.println( "Motors halted" );
stateMotor = ST_PAUSE;
}//if
break;
case ST_PAUSE:
//pause after running the motors
if( timeNow - timeMotor >= K_PAUSE_DURATION )
{
//when pause is complete, turn on the LED indicating
//ready for the another dispense
Serial.println( "Ready" );
digitalWrite( pinLED, HIGH );
//and return to IDLE state
stateMotor = ST_IDLE;
}//if
break;
}//switch
}//MotorControl