Running a process

I’m not sure if I’m even describing what I want to be able to do correctly. I want to be able to have an led object that I can call something like led1.blink(500) that starts an Led blinking then returns to the main loop. The led stays blinking until somewhere else in the program led1.off() is called. How would I do that?

What is your knowledge of C++?
Can you write a blink without delay yourself?
Can you make a function?

You would need to make a class.
The class may set up an interrupt timer to blink the LED (maybe not the best way as the blinking of a led is not time critical and can be organized in other ways).
Or you should include a call in your loop to update your led status.
Something like
led1.update_status();
The class should be initialized with the pin nr of the led and the blink time.

This project is certainly doable.
Geeks2geeks has good tutorials on making classes.

I know the basics of c++ and have written object code in other languages too. The only way I’ve so far figured out how to do it is using some type of timer or function that uses millis() to update the led state.

Well, try to write a class then, that puts a led on.
Later you may add the blinking...
My experience with classes was that it is not easy to get it right the first time. Compiler error messages can be confusing...
But once you made one class, it is quit easy to expand it. And make new classes as well.
Show your trial and if needed ask for help here...

unless you are running on FreeRTOS (like an ESP32) there is no notion of 'tasks', 'threads' or 'processes'. So you'll have to find a way to automagically wake up your function to blink the led. It can be manual, like you call often some sort of update() function that does the necessary work or you leverage timers.

deciding how you want this to happen will have consequences on how you structure your class

2 Likes

Look at a library like accelstepper. It controls stepper motors based on time elapsed (millis).

It relies on the main loop calling a run function frequently enough that it can do its work. You can use a similar pattern with your class.

1 Like

A possible example. You need to call the function in the loop() code. The rest of the code in the loop must take less time than the blink rate so that it can be checked in a timely manner.

/*
 * Blink
 *
 * Blink using a c++ class to toggle pin 
 * Each time the toggle member function is called a 
 *  check is done to see if it is time to toggle yet
 */
 
// Interface description - this must be first and would
//  normally be in a header file
class TogglePin {
  public:
    // constructors:
    TogglePin(byte inPinNumber);
    TogglePin(byte inPinNumber, unsigned long inDelayTime);

    // delay setter method:
    void setDelay(unsigned long inDelayTime);

    // doit method:
    void toggle(void);

   private:
    byte pinState;            // current pin state
    byte pinNumber;           // pin to use
    unsigned long delayTime;  // delay in ms
    unsigned long currentMs;  // current ms count
    unsigned long testMs;     // test ms 
};


int ledPin = 13;                // LED connected to digital pin 13
TogglePin blinkIt(ledPin);

void setup()                    // run once, when the sketch starts
{
  pinMode(ledPin, OUTPUT);      // sets the digital pin as output

}

void loop()                     // run over and over again
{
  blinkIt.toggle();
  
  // other interesting code here
}



// Implementation - this would normally be in a .cpp
//   file as part of a library
TogglePin::TogglePin(byte inPinNumber)
{
	pinState=HIGH;
	pinNumber=inPinNumber;
	delayTime=1000;
	testMs=millis();
}
TogglePin::TogglePin(byte inPinNumber, unsigned long inDelayTime)
{
	pinState=HIGH;
	pinNumber=inPinNumber;
	delayTime=inDelayTime;
	testMs=millis();
}
void TogglePin::setDelay(unsigned long inDelayTime)
{
	delayTime=inDelayTime;
}
void TogglePin::toggle(void)
{
	currentMs=millis();
	if((currentMs-testMs)>=delayTime) {
		//delay is up
		pinState^=1;                      //toggle state
		digitalWrite(pinNumber,pinState); // write new pin value
		testMs=currentMs;
	} 
}
1 Like

You don't need to make a class to have an LED blinking while you do other things.

As stated, the key is being able to allow some code that takes care of timing and turning on and off the LED to periodically get the attention of the processor.

This is why free-running loop code is something to aim for.

No C++ features required.

Interrupts can do it, but if you asking about using them, you probably should not be using them.

There will come a day for classes and all that stuff. I'm still waiting for that day. :expressionless:

There will come a day for interrupts. I've used them, but can usually do just fine without them.

Most of the fancy stuff that gets into my code sneaks in through my use of libraries, which I truly appreciate having available, but I still like to do things for myself or at least have a good understanding of how a library is providing the features it does.

$0.02.

a7

1 Like

Ok I’m getting the idea. What I was looking for was an easy way to achieve a kind of pseudo multitasking. And I understand that my problem is how I’ve written my code so far. It’s written to accomplish one thing at a time and it’s not returning to the main loop. Example: it turns on an actuator for X seconds but the action is enclosed in a for statement so it stays there without returning to the main loop. Using an interrupt may be the best way to do it.

I think you should start from "blink without delay" IDE example

no, in your case it is not the best solution. You need to learn how to solve such problems without interrupts

State machines might be something interesting for you to look at

consider
of course instead of just toggling the LED, some sub-function can be called that does much more

listing updated with sub-function call

struct Flasher {
    const byte     Pin;
    unsigned long  period;
    bool           enable;
    void           (*func) (Flasher *);
    const char    *desc;
    unsigned long  msecLst;
};

void flash (Flasher *f)
{
    Serial.println (f->desc);
    digitalWrite (f->Pin, ! digitalRead (f->Pin));
}

Flasher flashers [] = {
    { 10,  200, 1, flash, "t1" },
    { 11,  300, 1, flash, "t2" },
    { 12,  600, 1, flash, "t3" },
    { 13,  800, 1, flash, "t4" },
};
#define N_Flashers  (sizeof(flashers)/sizeof(Flasher))

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

    Flasher *f = &flashers [0];
    for (unsigned n = 0; n < N_Flashers; n++, f++)  {
        if (! f->enable)
            continue;

        if (msec - f->msecLst > f->period)  {
            f->msecLst = msec;
            f->func (f);
        }
    }
}

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

    for (unsigned n = 0; n < N_Flashers; n++)
        pinMode (flashers [n].Pin, OUTPUT);
}
1 Like

Or more concise / C++ / type respectful

struct Flasher {
    const byte     pin;
    unsigned long  period;
    bool           enabled;
    unsigned long  msecLast;
};

Flasher flashers [] = {
    { 10,  200, true, 0},
    { 11,  300, true, 0},
    { 12,  600, true, 0},
    { 13,  800, true, 0},
};

// -----------------------------------------------------------------------------
void setup () {
    for (auto & f : flashers) pinMode (f.pin, OUTPUT);
}

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

    for (auto & f : flashers)  {
        if (! f.enabled)  continue;
        if (msec - f.msecLast >= f.period)  {
            f.msecLast = msec;
            digitalWrite (f.pin, digitalRead(f.pin) == HIGH ? LOW : HIGH);
        }
    }
}

This WOKWI project I've been working on may be useful to you.

Hi, @dvok64
Welcome to the forum.

What is your project?

Thanks.. Tom... :smiley: :+1: :coffee: :australia:

Why not just

 Flasher = flashers;

a7

No. That function you spoke of could start a process and return, and when called again advance the process and/or finish it, and tell you, the caller, back in the loop().

Because it can remember where it was, when it started and so forth.

FSMs or finite state machines have been mentioned.

Google and settle in, it's a bit tricky or even hard until the aha! moment when it will be the way you do most things going forward.

 Arduino blink without delay

and

Arduino two things at once

and

Arduino finite state machine

and

Arduino traffic lights finite state machine

There are literally dozens of tutorials exposing this essential programming technique, you are very likely to find one that matches your current level of programming.

Some might argue you need to know way more C++ first, I don't think so - the concepts are perfectly amenable to expression with the simplest of C programming.

About the only even semi-advanced feature that comes in very handy is the switch/case statement, and if you don't know it, the best place to discover its utility is in learning (wait for it…) about finite state machinery.

a7

because i struggled with something earlier in the day, a ptr to a string in a table and knew this would work

1 Like

I know you can blink a led without a class.

But OP wants to call it like led1.blink(200); a class seems the best way to do so.

Anyway, all the others alread gave him the flasher. So I guess the problem is fixed by now.

Sry, I see. A class or modern struct would be the full ticket.

a7