slehmann36:
I have also seen the attachInterrupt() article from Arduino but as i understand it, it can only interrupt from a pin changing state (external interrupt). Can I interrupt it programmatically (internal interrupt)?
Or is there a better way to do what I have described?
You do not understand what interrupts are!
OK, not surprising, a terribly common "newbie" mistake.
An interrupt cannot be used to "programmatically" interrupt a loop. The very concept of an interrupt is to execute and return to wherever the code was executing at the time the interrupt was triggered, without affecting that code.
It is in fact the case that you can in the interrupt, set a "flag" - a variable which your loop will at some point read and take whatever action is necessary, but that is in most cases, an absurd complication when what you actually want is to "poll" or check within the loop, the device - such as a switch - that you wish to control the alternate action.
Note in general, that you do not - should not - use indefinite loops (such as "while") within your code. The loop() function in the standard sketch is all you need to perform repetitive actions (which is in fact, what the vast majority of programs do). What you do is to include in that loop, switches and counters which control repetitive actions.
As an example, study my multiple flashing code:
// Blink without "delay()" - multiple with on/ off switch
const int led1Pin = 13; // LED pin number
const int led2Pin = 2;
const int led3Pin = 5;
const int button1 = 10;
char led1State = LOW; // initialise the LED
char led2State = LOW;
char led3State = LOW;
char bstate1 = 0;
char doflash = LOW;
unsigned long count1 = 0; // will store last time LED was updated
unsigned long count2 = 0;
unsigned long count3 = 0;
unsigned long bcount1 = 0; // button debounce timer. Replicate as necessary.
// ----------------------------- toggle ------------------------------------------
char toggle(char *flip) { // Yes, it toggles the variable pointed to
if (*flip == LOW) {
*flip = HIGH;
}
else {
*flip = LOW;
}
return *flip;
}
// ----------------------------- timeout -----------------------------------------
// Have we completed the specified interval since last confirmed event?
// "marker" chooses which counter to check
boolean timeout(unsigned long *marker, unsigned long interval) {
if (millis() - *marker >= interval) {
*marker += interval; // move on ready for next interval
return true;
}
else return false;
}
// --------------------------- button read ---------------------------------------
// Deal with a button read; true if button pressed and debounced is a new event
// Uses reading of button input, debounce store, state store and debounce interval.
// Routines by Paul__B of Arduino Forum
boolean butndown(char button, unsigned long *marker, char *butnstate, unsigned long interval) {
switch (*butnstate) { // Odd states if was pressed, 2 or > if debounce in progress
case 0: // Button up so far,
if (button == HIGH) return false; // Nothing happening!
else {
*butnstate = 2; // record that is now pressed
*marker = millis(); // note when was pressed
return false; // and move on
}
case 1: // Button down so far,
if (button == LOW) return false; // Nothing happening!
else {
*butnstate = 3; // record that is now released
*marker = millis(); // note when was released
return false; // and move on
}
case 2: // Button was up, now down.
if (button == HIGH) {
*butnstate = 0; // no, not debounced; revert the state
return false; // False alarm!
}
else {
if (millis() - *marker >= interval) {
*butnstate = 1; // jackpot! update the state
return true; // because we have the desired event!
}
else
return false; // not done yet; just move on
}
case 3: // Button was down, now up.
if (button == LOW) {
*butnstate = 1; // no, not debounced; revert the state
return false; // False alarm!
}
else {
if (millis() - *marker >= interval) {
*butnstate = 0; // Debounced; update the state
return false; // but it is not the event we want
}
else
return false; // not done yet; just move on
}
default: // Error; recover anyway
{
*butnstate = 0;
return false; // Definitely false!
}
}
}
// -------------------------------------------------------------------------------
void setup() {
pinMode(led1Pin, OUTPUT);
pinMode(led2Pin, OUTPUT);
pinMode(led3Pin, OUTPUT);
pinMode(button1, INPUT);
digitalWrite(button1,HIGH); // internal pullup all versions
}
void loop() {
// Toggle switch if button debounced
if (butndown(digitalRead(button1), &bcount1, &bstate1, 10UL )) if (toggle(&doflash) == LOW) {
// Turn off LEDs only as and when doflash is switched off
led1State = LOW;
led2State = LOW;
led3State = LOW;
digitalWrite(led1Pin, led1State);
digitalWrite(led2Pin, led2State);
digitalWrite(led3Pin, led3State);
};
// flash if toggle is on
if (doflash == HIGH) {
// Act if the latter time (ms) has now passed on this particular counter,
if (timeout(&count1, 300UL )) {
toggle(&led1State);
digitalWrite(led1Pin, led1State);
}
if (timeout(&count2, 200UL )) {
toggle(&led2State);
digitalWrite(led2Pin, led2State);
}
if (timeout(&count3, 77UL )) {
toggle(&led3State);
digitalWrite(led3Pin, led3State);
}
}
}