Working with interrupts

Hello,

I came from professional Python programming with GTK - very high level in relation to C and AVR. At the beginning I have some conceptual questions now.

To give a practical background to my abstract problem: I plan to program a chain oiler for my own. That's mean to pause for approx. 15 minutes, give an impulse for approx. 1 second, pause again and so on. To set up the exact time values I will implement an button to trigger some settings "dialog".

To react on the pressed button I would use the interrupt attachInterrupt(0, button_interrupt_rising, RISING). How I read there are the recommendation: "ISRs should very short. The best would be only to set a flag evaluated in the main loop." - That's contradicts the desire of interrupts, doesn't it?
Many parts of the system can go to sleep and will be awaked via interrupt. But with using flags the main loop is a busy waiting (for the total 15 minutes when usually nothing happens) to check the flags.

And if I ignore that recommendation and put my whole settings dialog into the ISR, I have the problem with further interrupts within the ISR for more button inputs to set the value.

I hope you can help me to clarify this issue "Let system sleep until heavy work triggered by button".

Bye Markus

The main use of interrupts is to detect with really short duration events.

Imagine you have a device sending really short pulses.
One way of reading them is to poll the corresponding input (checking its value whenever you can). However, it uses computing time and if your MCU is busy doing something else, you might miss the pulse.
Now here is where interrupts are useful: you detect the pulse using an interrupt, you set a flag in the ISR, and you treat that information in the main program when you want. The reason for that is when in an ISR, everything else (almost) pauses. The code is not being executed and can hang during an important task (communication that will fail, controlling an actuator but the interrupt comes in the middle of the command being send, etc.).
With the flag, you treat the information only when YOU want, making sure that it won't suspend anything critical.

That's a good practice but it's not mandatory in all case, of course.
In your case, you're not using interrupts to detect short events while doing something else.
Since everything is sleeping (no code executed) and your interrupt's role is to wake up the system, checking the value of a flag is not a good idea since it prevent the system from sleeping, indeed.

Do you really need interrupts at all?

What is creating the impulse that you want to detect?

If you just want to check something every 15 minutes polling should be more than adequate.

See Nick Gammon's interrupt tutorial

...R

OK. To get the system into sleep mode it sticks in delay(15*60000) the most time. Do you have an idea to abort this delay via ISR to handle the action in main code?

Delta_G:
let the loop repeat itself.

That's what I not want: busy waiting.

Delta_G:
delay isn't the same as sleep mode. [...] Delay just has the chip busy running nothing.

delay_micros() is busy waiting, delay() uses the hardware timer.
Separate sleep mode is the right hint. Thank you.
So I will activate directly sleep mode in main loop. Wake up via button interrupt or external Timer (TimerOne keeps system in sleep mode?) and check whether the 15min are over or to react on button.

delay_micros() is busy waiting, delay() uses the hardware timer.

?

AWOL:
?

? Indeed. Both are busy doing nothing.

Chickenmarkus:
OK. To get the system into sleep mode it sticks in delay(15*60000) the most time. Do you have an idea to abort this delay via ISR to handle the action in main code?

As @Delta_G has said that is not sleeping and I assumed you meant sleeping so it did not occur to me to give you this link to several things at a time which illustrates how to manage timing using millis() rather than delay(). It uses the same technique as BWoD.

...R

Henry_Best:
? Indeed. Both are busy doing nothing.

You're right. I understood this post that delay() only locks until interrupt of hardware timer and only delayMicroseconds() is busy due something like while (true). But if we see in code delay() uses while (true) too. It's only not working in ISRs because of millis() inside.

Summary what we've got until now:
I don't want to have full CPU load for 15 minutes while usually do nothing (busy waiting). This is the case with delay(), delayMicroseconds() and permanently checking over main loop (like several things at a time).
Instead I will send sleep the system directly like in this minimal (untested) code:

#define buttonPin 0
#define pause 900
volatile int interruptID = 0;

#include <TimerOne.h>
#include <avr/sleep.h>

void setup() {
    pinMode(buttonPin, INPUT);
    Timer1.initialize();
}


void isr_button() {
    interruptID = 1;
    sleep_disable();
}


void isr_timer() {
    interruptID = 2;
    sleep_disable();
}


void loop () {
    switch(interruptID) {
        case 1:
            // button is pushed
            break;
        case 2:
            // timer: time to do something
            break;
    }

    Timer1.setPeriod(pause*1000000);
    Timer1.attachInterrupt(isr_timer);

    set_sleep_mode(SLEEP_MODE_PWR_DOWN);   
    sleep_enable();
    attachInterrupt(0, isr_button, RISING);
    sleep_mode();
    detachInterrupt(0);

    Timer1.detachInterrupt();
}

The question is: Works Timer1 with sleep mode?

Chickenmarkus:
I don't want to have full CPU load for 15 minutes while usually do nothing (busy waiting).

You still seem a trifle confused here (and you seriously need to read the instructions on how to post, especially but not only, item 7).

"Sleep" mode is only used to conserve power. Not the same as a multi-tasking operating system where it passes control to another process. It is not used to invoke delays unless you also want to conserve power.

You have not indicated a requirement to conserve power, so unless that is what you require, "busy waiting" is exactly what you want to be doing.

That said, it is most certainly not in the slightest necessary that waiting prevents you from performing other tasks whilst waiting. You can interleave numerous other tasks in the waiting process limited only by code space and overall task complexity. If however, you only have the one task, then there is no reason not to "busy wait" - the processor is not sentient - it does not care and it will not wear out!

So - which is it? :astonished:

Sorry, I thought it was clear that I aim to conserve power if I do not want busy waiting for 15 minutes for only 1 second action within.
My final device will be something like DigiSpark driven by battery.

Sometimes it's absolute clear what I mean - for me.

After 5 years using busy waiting (if nothing else was to do) on graphical programmable calculater as only possibility for waiting it was a challenge to find alternatives for the last 10 years of PC programming without. So it's good to know busy waiting is exactly the right way again, 15 years later now - without the need of power saving

So is it possible to wake up the system from sleep mode by Timer1?

Per this section of the datasheet
10.1 Sleep Modes
it does not appear that Timer1 is an interrupt source to wake from sleep with.

Chickenmarkus:
So is it possible to wake up the system from sleep mode by Timer1?

It may all have been crystal clear to you. But prior to this question it was all very unclear to me.

...R

CrossRoads:
Per this section of the datasheet 10.1 Sleep Modes

Google didn't find anything with "datasheet 10.1 sleep modes". On which datasheet you took a look?

If Timer1 is not able to wake up the system then the watchdog timer have to do it every 8s for a few cycles to go sleep again.

Thank you all for your great help!

The datasheet of the MCU on the Arduino board you're using.

http://www.atmel.com/images/Atmel-8271-8-bit-AVR-Microcontroller-ATmega48A-48PA-88A-88PA-168A-168PA-328-328P_datasheet_Complete.pdf

Chickenmarkus:
Google didn't find anything with "datasheet 10.1 sleep modes". On which datasheet you took a look?

Did you seriously expect that it would ?

...R

Yes, I did. The datasheets are available online and linked by the product page. So Google will crawl it. There are a lot of literature in PDF format I found only by some headlines this way. :wink:

Now it's everything clear (for the moment). Thanks again to all.

Google didn't find anything with "datasheet 10.1 sleep modes"

Google must broken where you are.
Admittedly, (for me) it finds PIC datasheet before AVR, but find AVR datasheets it most assuredly does.

How about a more direct suggestion then:

Click on the PDF icon to the left of "ATmega48A/PA/88A/PA/168A/PA/328/P Complete"