Calling a library inside an interrupt

I have this code here that when the button is pressed the LED will blink for 3-10 seconds and then stay on for 15minutes. Now, what i want to do is, how can I call the tinyGPS.h to execute exactly after the 3-10 seconds of blinking time? i have created a function but i have no luck. i have tried to insert it in

#include "TinyGPS/TinyGPS.h"
int buttonPin = D0;    
int ledPin = D1; 
int held = 5;
int ledState = LOW;         
int buttonState;             
int lastButtonState = LOW;   
long lastDebounceTime = 0;  
long debounceDelay = 50;   

void setup() 
{
pinMode(buttonPin, INPUT);
pinMode(ledPin, OUTPUT);
digitalWrite(ledPin, ledState);
}

void loop() 
{
int reading = digitalRead(buttonPin);
if (reading != lastButtonState) 
    {
        lastDebounceTime = millis();
    } 

if ((millis() - lastDebounceTime) > debounceDelay) 
    {
        if (reading != buttonState) 
            {
                buttonState = reading;
                if (buttonState == HIGH) 
                    {
                        int cntr=10;
                        do
                        {
                            digitalWrite(ledPin, HIGH);   
                            delay(200);  
                            digitalWrite(ledPin, LOW);    
                            delay(200);                
                            cntr = cntr-1;
                        }       
                        while (cntr!=0);
                        digitalWrite(ledPin, HIGH);
                        delay(900000);
                        ledState = LOW;
                    }
            }
    }

 digitalWrite(ledPin, ledState);
 lastButtonState = reading;
 }

Here’s an idea. Haven’t tried it though.

#include "TinyGPS/TinyGPS.h"
int buttonPin = D0;
int ledPin = D1;
int held = 5;
int ledState = LOW;
int lastButtonState = LOW;
unsigned long lastDebounceTime = 0;
unsigned long debounceDelay = 50;
unsigned long ledMillis;

void setup()
{
	pinMode(buttonPin, INPUT);
	pinMode(ledPin, OUTPUT);
	digitalWrite(ledPin, ledState);
}

void loop()
{
	int reading = digitalRead(buttonPin);

	if (reading != lastButtonState)
	{
		if ((millis() - lastDebounceTime) > debounceDelay)
		{
			if (buttonState == HIGH) 
			{
				for(int cntr = 0; cntr < 10; cntr++)
				{
					digitalWrite(ledPin, HIGH);
					delay(200);
					digitalWrite(ledPin, LOW);
					delay(200);
				}
				digitalWrite(ledPin, HIGH);
				ledMillis = millis();
				ledState = LOW;
			}
		}

		lastDebounceTime = millis();
		lastButtonState = reading;
	}

	if( ledMillis && (millis() - ledMillis) > 900000 )
	{
		ledMillis = 0;
		digitalWrite(ledPin, ledState);
	}
}

hmmm I see you’ve changed the loop part. Just a question, how can i call the library embedded after the blinking loop?

I got interested in this thread because of the title “Calling a library inside an interrupt”, but then I realized, you don’t even use an interrupt.

But just for the curious driver by: “Don’t call libraries from within an ISR (interrupt service routine)!”

Keep ISRs short and avoid fn calls where possible inside them - and if you need to call, make sure the fn inner workings don’t interfere with other interrupts.

And for your problem, you might even like to give an interrupt approach a go. It may make your code a bit more readable, and for your use you can forget about debounce, too :wink:

1 Like

That’s true ScruffR. This is a bit simpler. I’m not sure what part of TinyGPS needs to be called and where though? After the LED blinks or after the long delay?

#include "TinyGPS/TinyGPS.h"
int buttonPin = D0;
int ledPin = D1;
int held = 5;
int ledState = LOW;
unsigned long ledMillis;
int ledCnt;

void buttonIsr()
{
	ledCnt = 20;
}

void setup()
{
	pinMode(buttonPin, INPUT);
	pinMode(ledPin, OUTPUT);
	digitalWrite(ledPin, ledState);
	attachInterrupt(buttonPin, buttonIsr, RISING);
}

void loop()
{
	if(ledCnt)
	{
		digitalWrite(ledPin, !digitalRead(ledPin) );
                    delay(200);
		if(--ledCnt == 0)
		{
			ledMillis = millis();
			ledState = LOW;
		}
	}

	if( ledMillis && (millis() - ledMillis) > 900000 )
	{
		ledMillis = 0;
		digitalWrite(ledPin, ledState);
	}
}

Edit: Forgot to add a delay :slight_smile: zoom

I’ve tried your code, but I’am having an error of

the_user_app.cpp: In function ‘void setup()’:
the_user_app.cpp:18:44: error: invalid conversion from ‘int’ to ‘InterruptMode’ [-fpermissive]

In file included from …/inc/spark_utilities.h:33:0,
from …/inc/spark_wiring.h:33,
from …/inc/application.h:29,
from the_user_app.cpp:2:
…/inc/spark_wiring_interrupts.h:45:6: error: initializing argument 3 of ‘void attachInterrupt(uint16_t, voidFuncPtr, InterruptMode)’ [-fpermissive]
void attachInterrupt(uint16_t pin, voidFuncPtr handler, InterruptMode mode);

It’s not HIGH but RISING or FALLING, depending if you pull the signal down or up with the button and if you want to react to the press or release of the button.

Thanks ScruffR. I never remember those. It might be a rising edge with pullup too if it’s only a button connected to ground. It’s nice having that in 1 call.

Already working! thanks! now my problem is how can i call the embedded tinyGPS library after the “blinking loop”.

Why is it that, when I pressed the button it does blink and stay on for 15minutes, but when I press the button again it will blink again?

I’d say add all the code from the tinyGPS example, but call Spark.publish() when ledCnt hits 0.

The button will reset the ledCnt any time you press it. You need to check ledMillis I guess and not set ledCnt if it’s non-zero.

How can I change that? I dont need to reset every time the counter. thanks!

I think I’d do it like this:

void buttonIsr()
{
   if(ledCnt == 0 && ledMillis == 0)
       ledCnt = 20;
}

I’ve changed some because the output of “blink for 10 seconds and stay on for 15 minutes” doesnt show up. In my previous code, I know that I cant place a function to call after the blinking part because of the delay. @CuriousTech i really want to call the tinyGPS function after the blinking part. It’s like the blinking part is the trigger for the library then the steady on is for the tinyGPS to execute its thing.

int buttonPin = D0;
int ledPin = D1;
int held = 5;
int ledState = LOW;
unsigned long ledMillis;
int ledCnt;

void buttonIsr()
{
if(ledCnt == 0 && ledMillis == 0)
   ledCnt = 20;
}
void setup()
{
pinMode(buttonPin, INPUT);
pinMode(ledPin, OUTPUT);
digitalWrite(ledPin, ledState);
attachInterrupt(buttonPin, buttonIsr, RISING);
}

void loop()
{
if(ledCnt)
{
	digitalWrite(ledPin, !digitalRead(ledPin) );
                delay(200);
	if(--ledCnt == 0)
	{
		ledMillis = millis();
		
	}
}

if( ledMillis && (millis() - ledMillis) > 900000 )
{
	ledMillis = 0;
	digitalWrite(ledPin, ledState);
	ledState = HIGH;
}

}

You could add a call to a function that does the reading in main loop like so.

void loop()
{
     ...
     if(ledMillis)
     {
            readGPS();
     }
     ...
}

Then your readGPS() would service the serial data only during the time the LED is on. It takes at least 1 second to acquire all the sentences needed for a fix, and your GPS needs to be on for at least 6 seconds for a hot start, or 6x5 + a few for a cold start. If you just wait for a fix and shut off the LED, it may make for better feedback.