Execute section of code only once

I am attaching a toggle switch to an servo motor. I want the servo to rotate from 0 to 90 and back to 0 only once when the toggle is switched on. Right now the servo rotates continuously when switched on. I have tried working with a boolean statement but have not had much success. Any guidance would be appreciated, thank you.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <Servo.h>

Servo myServo;
// twelve servo objects can be created on most boards

int pos = 0;    // variable to store the servo position
int switchPin = 7;
int servoPin = 9;
int startPosition = 0;
int endPosition = 90; 
void setup() {
  myServo.attach(servoPin);
  pinMode(switchPin, INPUT_PULLUP);
}

void loop() {
  int buttonState = digitalRead(switchPin);

  if ( buttonState == HIGH) {

      for (pos = startPosition; pos <= endPosition; pos += 1) {

        myServo.write(pos);
        delay(0);
      }

      for (pos = endPosition;  pos >= startPosition; pos -= 1) {
        myServo.write(pos);
        delay(0);
      }
  }
  if (buttonState == LOW) {
    myServo.write(startPosition);
  }
}
is buttonstate working properly?
is the hardware dumb? It looks like like 32 could make it jitter forever.
perhaps that section should be read the position and if its not at the start, move there, else do nothing?
it also looks like that section is moot: you moved back to start position anyway, no need to keep doing that. Remove that if statement and block (32+) ?

other stuff... does it really accept degrees? Most code works in radians, but it could, I guess.
Last edited on
Not a bad suggestion. It seems to be working just fine despite that section. When it is off it is still. When it is on it is moving constantly, I need it to execute the rotation only one time. That is really what I am aiming at.
I get it.
it could be any of 4 things or more...
- the button isnt working as you think (or wrong button bug etc), so its always high (or low even). can you debug or output this value in any way? If you can't see the value, hard code it instead of getting it from the hardware, so that it sits at low for like 1000 iterations, goes high for 10, then low forever. Or make the button do something else like fire up a light.

- something odd with the motor. what does it do if you take out both write statements? It should sit there 'off'. Then you can play with just that, so if they hit the button, do nothing, whatever experiments to debug with.

- exteme / band issue. Maybe you tell it to go to the start position but its not quite getting there, so it keeps trying. What if you say myServo.write(startPosition+5); for low, and in the return loop for high as well?

- units ... try going 0-3 and back, unless you confirmed that its in degrees?

- hardware problems. Maybe you wired the motor to the power supply and it just spins, ignoring pins and inputs and anything else... maybe you have a bad board or connection or whatever... it happens.

- something bugged up in code you didn't post.

basically, it looks right but something clearly isnt.
Last edited on
Not tested but worth looking at the following:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <Servo.h>

Servo myServo;
int switchPin = 7;
int servoPin = 9;

const int startPosition = 0;
const int endPosition = 90; 

int buttonState = LOW;

void setup() 
{
  myServo.attach(servoPin);
  pinMode(switchPin, INPUT_PULLUP);
}

void loop()
 {
  buttonState = digitalRead(switchPin);

  if ( buttonState == HIGH) 
  {
      for (int pos = startPosition; pos <= endPosition; pos++) {
        myServo.write(pos);
        delay(0);
      }

      for (int pos = endPosition;  pos >= startPosition; pos--) {
        myServo.write(pos);
        delay(0);
      }

      buttonState = LOW;
      myServo.write(startPosition);
  }
}
The function loop is, presumably, executed within a loop. If true, that explains why the servo will not stop moving until the toggle switch is opened.

I suppose that is the idea behind the above.
Last edited on
With an Arduino there is no main()

The Arduino (or whatever) microcontroller responds in the loop() which 'circulates' continually, to the connected outputs from the peripherals which in this case is the button, and in turn, depending on the state of the button, sends the relevant output to the servo, and when that is complete 'resets' the button state.
Also the delay(0) step is dubious.
I have made those adjustments but still not achieving one rotation. The loop seems to be resetting the i value to zero each iteration of the for loop as long as the toggle is HIGH. Maybe the toggle switch is not ideal, and I need a button instead. Or there is a work around?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50


#include <Servo.h>

Servo myServo;
// twelve servo objects can be created on most boards

int pos = 0;    // variable to store the servo position
int switchPin = 7;
int servoPin = 9;
int startPosition = 0;
int endPosition = 90;
int loopNumber = 1;
int buttonState = LOW;
int i = 0; 
void setup() {
  myServo.attach(servoPin);
  pinMode(switchPin, INPUT_PULLUP);

}

void loop() {
 for (i = 0; i <= loopNumber; i++)
  {
    buttonState = digitalRead(switchPin);
    if ( buttonState == HIGH) {

      for (pos = startPosition; pos <= endPosition; pos += 1) {

        myServo.write(pos);
        delay(0);
      }

      for (pos = endPosition;  pos >= startPosition; pos -= 1) {
        myServo.write(pos);
        delay(0);
      }
    }
  }

  if (buttonState == LOW) {
    int offAngle = myServo.read();
    if (offAngle != startPosition) {
      for (pos = offAngle; pos >= startPosition; pos -= 1) {
        myServo.write(pos);
      }
    }
  }
  myServo.write(startPosition);
}
The loop seems to be resetting the i value to zero each iteration of the for loop as long as the toggle is HIGH. Maybe the toggle switch is not ideal, and I need a button instead. Or there is a work around?


Try something like this. Clearly I didn't test or even compile the program.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <Servo.h>

Servo servo;
int const switch_pin = 7, servo_pin = 9;

void setup() 
{
  servo.attach(servo_pin);
  pinMode(switch_pin, INPUT_PULLUP);
}

void loop() 
{
  // TODO(mbozzi): stop busy-waiting
  while (LOW == digitalRead(switch_pin)) /* do nothing */;

  servo.write(90); 
  delay(10000); // assume units of milliseconds
  servo.write(0);
  delay(10000);

  while (HIGH == digitalRead(switch_pin)) /* do nothing */;
  delay(100); // adjust or remove this delay as needed to accommodate contact bounce
}
Last edited on
Try something like this. Clearly I didn't test or even compile the program.


Got it working much appreciated!
A toggle switch turns power on or off and does not automatically return to the 'OFF' state. So if you flick the switch the cycle repeats until the switch is turned off.

A (tactile) button however does activate a single cycle.

The following code along with a correctly connected button and servo activates the single cycle from 0->90 then from 90->0 when the button is pressed.

Angle calibration will vary from servo to servo.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <Servo.h>

const int START{0};
const int END{180};

int pushButton{2};
int buttonState;

Servo myservo;

void setup() {
    
    Serial.begin(9600);
    pinMode(pushButton, INPUT);
    
    myservo.attach(9);
    myservo.write(START);
}


void loop() {
    
    buttonState = digitalRead(pushButton);
    
    if(buttonState == HIGH)
    {
        for (int pos = START; pos <= END; pos++)
        {
            myservo.write(pos);
            delay(15);
        }
        
        for (int pos = END; pos >= START; pos--) {
            myservo.write(pos);
            delay(15);
        }
    }
}
Topic archived. No new replies allowed.