Function problems

So i have the following code:

void setup(){
pinMode(10, OUTPUT);
pinMode(11, OUTPUT);
}

void loop(){
function 1();
function 2();
}

void function 1(){
digitalWrite(10, HIGH);
delay(10000);
digitalWrite(10, LOW);
}

void function 2(){
digitalWrite(11, HIGH);
delay(10000);
digitalWrite(11, LOW);
}

Only AFTER function 1 is done will function 2 do its thing, but theres no delay in between then in void loop. How do i make them go at the same time?

The Arduino can only do one thing at a time, hence your problem

In the simple case that you posted you could put a digitalWrite() for both pins in the same function, but that is not a general solution. In order to make the Arduino appear to do more than one thing at a time you need to use a different strategy to do the timing so that doing one thing does not block the running of a second thing

See Using millis() for timing. A beginners guide, Several things at the same time and the BlinkWithoutDelay example in the IDE

look this over
change the LED pin values

const byte PinLeds [] = { 13, 12 };
const int  Nled       = sizeof(PinLeds);

unsigned long msecPeriod [Nled] = { 1000, 1500 };
unsigned long msecLst    [Nled];

// -----------------------------------------------------------------------------
void loop ()
{
    unsigned long msec = millis ();

    for (int n = 0; n < Nled; n++)  {
        if (msec - msecLst [n] >= msecPeriod [n])  {
            msecLst [n] = msec;

            digitalWrite (PinLeds [n], ! digitalRead (PinLeds [n]));
        }
    }
}

// -----------------------------------------------------------------------------
void setup ()
{
    Serial.begin (9600);
    for (int n = 0; n < Nled; n++)  {
        pinMode (PinLeds [n], OUTPUT);
    }
}

Another approach is to put the timing logic into the functions themselves so they can figure out when to update or just do nothing

void setup() {
  pinMode(10, OUTPUT);
  pinMode(11, OUTPUT);
  digitalWrite(10, HIGH);
  digitalWrite(11, HIGH);
}

void loop() {
  function1();
  function2();
}

void function1() {
  static unsigned long lastTime;
  const unsigned long waitTime = 10000ul;
  const byte pin = 10;

  if ( millis() - lastTime >= waitTime ) {
    digitalWrite( pin, !digitalRead(pin));
    lastTime += waitTime;
  }
}

void function2() {
  static unsigned long lastTime;
  const unsigned long waitTime = 7500ul;
  const byte pin = 11;

  if ( millis() - lastTime >= waitTime ) {
    digitalWrite( pin, !digitalRead(pin));
    lastTime += waitTime;
  }
}

1 Like

Add a delay() to the end of each function... and combine functions

void setup(){
  pinMode(10, OUTPUT);
  pinMode(11, OUTPUT);
}

void loop(){
  function(10);
  function(11);
}

void function(int aPin){
  digitalWrite(aPin, HIGH);
  delay(10000);
  digitalWrite(aPin, LOW);
  delay(10000); // <-- Add this
}

How did loop go before setup?

were you thinking the functions are invoked in the order they appear in the .ino file?

if you've ever wondered, here is the main() that is required in any C/C++ program

#include <Arduino.h>

// Declared weak in Arduino.h to allow user redefinitions.
int atexit(void (* /*func*/ )()) { return 0; }

// Weak empty variant initialization function.
// May be redefined by variant files.
void initVariant() __attribute__((weak));
void initVariant() { }

void setupUSB() __attribute__((weak));
void setupUSB() { }

int main(void)
{
	init();

	initVariant();

#if defined(USBCON)
	USBDevice.attach();
#endif
	
	setup();
    
	for (;;) {
		loop();
		if (serialEventRun) serialEventRun();
	}
        
	return 0;
}
1 Like

I typically follow the convention of putting setup() first, no matter it works wherever you put it in the *.ino file. That's where I look for it, and usually that means I don't have to. Look for it.

To me it's like the ingredients part of a recipe. A very good and almost always the first thing to read as one is, um, reading the code. That and other things that are also placed first.

The stuff up top, including setup(), informs understanding of the rest of the sketch. It can be the source of clues about the loop() to come, as well as clues about the programmer's level of incompetence.

Placing it elsewhere is srsly swimming upstream, the kind of thing for which there is no good reason. Like using red wire for GND and black wire for Vcc.

Conventions come into being for reasons.

a7

3 Likes

If this is AVR/SAMD21 board you can use my multitasking library Taskfun to run the two functions in parallel Task2Blink - Wokwi ESP32, STM32, Arduino Simulator

#include <Taskfun.h>

void function1(int){
  digitalWrite(10, HIGH);
  delay(10000);
  digitalWrite(10, LOW);
}

void function2(int){
  digitalWrite(11, HIGH);
  delay(10000);
  digitalWrite(11, LOW);
}

void setup(){
  pinMode(10, OUTPUT);
  pinMode(11, OUTPUT);
  setupTasks();
  runTask(function1, 0);
  runTask(function2, 0);
}

void loop() {
}

Hello rllybro0112

In general - arrays and structs are your friends.
Don't duplicate code in your sketch. Write code once - use it multiple times.

Consider

#define ProjectName "BlinkALed"
//variables
// -----------------------------------------------
// Only manage the flashing objects here!
constexpr uint8_t  LedPins[] {9, 10, 11};
constexpr uint32_t FlashTimes[] {2000, 3000, 4000};
// -----------------------------------------------
//structures
struct BLINKALED
{
  uint8_t ledPin;
  uint32_t intervalMillis;
  uint32_t previousMillis;
  void init(uint8_t ledPin_ , uint32_t intervalMillis_)
  {
    Serial.println(__func__);
    ledPin = ledPin_;
    pinMode(ledPin, OUTPUT);
    intervalMillis = intervalMillis_;
  }
  void run(uint32_t currentMillis)
  {
    if (currentMillis - previousMillis >= intervalMillis)
    {
      previousMillis = currentMillis;
      digitalWrite(ledPin, digitalRead(ledPin) ? LOW : HIGH);
    }
  }
};
BLINKALED blinkALeds[sizeof(LedPins)];
//support
void heartBeat(int LedPin, uint32_t currentMillis)
{
  static bool setUp = false;
  if (!setUp) pinMode (LedPin, OUTPUT), setUp = !setUp;
  digitalWrite(LedPin, (currentMillis / 500) % 2);
}
void setup()
{
  Serial.begin(115200);
  Serial.println(ProjectName);
  int member = 0;
  for (auto &blinkALed : blinkALeds)
  {
    blinkALed.init(LedPins[member], FlashTimes[member]);
    member++;
  }
}
void loop()
{
  uint32_t currentMillis = millis();
  heartBeat(LED_BUILTIN, currentMillis);
  for (auto &blinkALed : blinkALeds) blinkALed.run(currentMillis);
}

Have a nice day and enjoy coding in C++.

when posting code on this forum, i try to put the most meaningful code near the top so that it might appear early in the truncated window showing the code in the post. in this case, there was no need to scroll down to see loop().

in standard C/C++ development (not Arduino) function symbols must be known before being used, so i typically put main() at the bottom and order functions so that a() is defined before b() where it is called from, otherwise a prototype declaration is required void a(); is needed before b().

Why not use a constructor?

Answer is very simple:

I don´t like classes !

1 Like

But in C++ struct is a class, the only difference is the default access modifier, in struct it's public in class it's private. The rest is the same. So when you create your struct you first implicitly call a constructor that you don't use.

That may be, but somehow I'm not interested at all. The main thing is that the sketch runs.

1 Like

It's just amusing that you say "enjoy coding in C++" but you don't like classes :slight_smile:

Because some methods, such as:

can't be called at init time, so the structure must have an init() method, which will be called after board initialization finished.

2 Likes

Makes sense, thanks!

CPP isn´t coding in CLASS definitions only.
Sorry for my usefull abstraction of C++.

In this example, the init() calls Serial.print() so you can't use a constructor. A constructor could be called before the rest of the Arduino enivornment/hardware has been initialized and the Serial call could fail. That is why many classes have the .begin() function.

1 Like