Arduino Forum

Using Arduino => Introductory Tutorials => Topic started by: tomascus on Apr 06, 2019, 03:37 am

Title: Doing multiple things at once with structs
Post by: tomascus on Apr 06, 2019, 03:37 am
Hi guys, apologies if this is the wrong place to post.

I just wanted to demonstrate a program which performs actions on a button, two LEDs and three servos without any blocking.

I know that there are already many tutorials out there but I don't think many have covered the use of structs as these come in handy for those not comfortable with using classes and also eliminates the need to have extra pointless variables specific to each LED etc.

What this code does:
- Toggle LEDs at different ON and OFF times
- Turn the servos between a minimum angle and maximum angle at different rates
- Poll and debounce a button

Please feel free to ask questions or add any critique, thanks.

Code: [Select]

#include <Servo.h>

#define NO_OF_BUTTONS 1
#define NO_OF_LEDS 2
#define NO_OF_SERVOS 3

#define DEBOUNCE_DELAY 50

const int servo0_pin = 3;
const int servo1_pin = 5;
const int servo2_pin = 6;

Servo myServo[NO_OF_SERVOS];

struct servo {
  int servo_no; /* corresponds to myServo array value */
  int min_angle;
  int max_angle;
  int move_rate; /* delay in ms in which to inc/dec position */
  int increment;
  int cur_pos;
  unsigned long prev_millis;
};

/* create an array of servo structs and set parameters */
struct servo servos[NO_OF_SERVOS] = {
/* servo_no, min_angle, max_angle, move_rate, increment */
    {0, 0, 180, 30, 3},
    {1, 0, 135, 40, 1},
    {2, 0, 45, 55, 2}
};

struct button {
  int pin;
  int reading;
  int last_state;
  int button_state;
  unsigned long last_debounce_time;
};

struct button buttons[NO_OF_BUTTONS] = { 11 }; /* Pin number */

struct led {
  int pin;
  int on_time;
  int off_time;
  int state;
  unsigned long prev_millis_low;
  unsigned long prev_millis_high;
};

/* create an array of led structs and set parameters */
struct led leds[NO_OF_LEDS] = {
/* pin, on_time, off_time */
  {13, 250, 250},
  {12, 500, 1000}
};

void setup()
{
  Serial.begin(9600);

  pinMode(leds[0].pin, OUTPUT);
  pinMode(leds[1].pin, OUTPUT);

  myServo[0].attach(servo0_pin);
  myServo[1].attach(servo1_pin);
  myServo[2].attach(servo2_pin);
}

/*
 * update_led(struct led *pled) function.
 * Flash LEDs at different rates with configured on times and
 * off times.
 */
void update_led(struct led *pled)
{
  switch (pled->state) {
  case LOW:
    if (millis() - pled->prev_millis_low >= pled->off_time) {
      digitalWrite(pled->pin, HIGH);
      pled->state = HIGH;
      pled->prev_millis_high = millis();
    }
    break;
  case HIGH:
    if (millis() - pled->prev_millis_high >= pled->on_time) {
      digitalWrite(pled->pin, LOW);
      pled->state = LOW;
      pled->prev_millis_low = millis();
    }
    break;
  }
}

/*
 * update_servo(struct servo *pservo) function.
 * Rotate servos at different rates and differing max angles
 * as configured.
 */
void update_servo(struct servo *pservo)
{
  if (millis() - pservo->prev_millis >= pservo->move_rate) {
    pservo->prev_millis = millis();
    (pservo->cur_pos) += pservo->increment;
    myServo[pservo->servo_no].write(pservo->cur_pos);
    if (pservo->cur_pos >= pservo->max_angle ||
        pservo->cur_pos <= pservo->min_angle)
      pservo->increment = -(pservo->increment);
  }
}

/*
 * poll_button(struct button *pbutton) function.
 * Simple button debouncing and reading while being polled in the
 *  loop() func.
 * Code copied from Arduino website.
 */
void poll_button(struct button *pbutton)
{
  pbutton->reading = digitalRead(pbutton->pin);

  if (pbutton->reading != pbutton->last_state)
    pbutton->last_debounce_time = millis();

  if ((millis() - pbutton->last_debounce_time) > DEBOUNCE_DELAY) {
    if (pbutton->reading != pbutton->button_state) {
      pbutton->button_state = pbutton->reading;
      if (pbutton->button_state == HIGH)
        Serial.println("Button pressed");
    }
  }

  pbutton->last_state = pbutton->reading;
}

/* Main loop which updates all items */
void loop()
{
  for (int i = 0; i < NO_OF_LEDS; i++)
    update_led(&leds[i]);

  for (int i = 0; i < NO_OF_BUTTONS; i++)
    poll_button(&buttons[i]); 

  for (int i = 0; i < NO_OF_SERVOS; i++)
    update_servo(&servos[i]);
}


EDIT: changed title
Title: Re: Doing multiple things at once with structs
Post by: oswe on Jun 20, 2019, 07:22 pm
Good writing. One question . if u define a new struct u dont need to provide all arguments? I mean in this part u only assign 3 arguments being that it has 5.

struct led leds[NO_OF_LEDS] = {
/* pin, on_time, off_time */
Title: Re: Doing multiple things at once with structs
Post by: lastchancename on Jun 21, 2019, 05:11 am
Nice example - maybe a bit over the heads of some early learners - but well worthwhile.
Just curious - Why didn't you put the pins inside the servo struct[] array ?
Title: Re: Doing multiple things at once with structs
Post by: GolamMostafa on Jun 22, 2019, 09:02 am
Code: [Select]
[quote author=tomascus link=msg=4126025 date=1554514630]
I just wanted to demonstrate a program which performs actions on a button, two LEDs and three servos without any blocking.

/* Main loop which updates all items */
void loop()
{
  for (int i = 0; i < NO_OF_LEDS; i++)
    update_led(&leds[i]);

  for (int i = 0; i < NO_OF_BUTTONS; i++)
    poll_button(&buttons[i]); 

  for (int i = 0; i < NO_OF_SERVOS; i++)
    update_servo(&servos[i]);
}


You have said 'without any blocking'--codes of the loop() function indicate that you are unable to check the states of the buttons until the 'update_led()' business is over. Is it not some kind of 'blocking'?
Title: Re: Doing multiple things at once with structs
Post by: AWOL on Jun 22, 2019, 11:10 am
You have said 'without any blocking'--codes of the loop() function indicate that you are unable to check the states of the buttons until the 'update_led()' business is over. Is it not some kind of 'blocking'?

Only for very large numbers of LEDs.
Which is not the case.