Blinking Light Inside of a Hardware Interrupt Routine

Hey guys,

I’m using an arduino uno for a project and I’m having trouble implementing hardware interrupts. The basic purpose of the project is to add a strobing taillight to a motorcycle. The arduino will intercept the voltage going to the taillight when the brake lever is pressed. It will then trigger a mosfet which will pulse the 12v line for a set amount of time before going steady on (so drivers aren’t annoyed by a constantly blinking light when stopped at a traffic signal). I’ve got the circuitry and code working for this and I’ve pasted it below.

However, I’d like to trigger the strobe through a hardware interrupt rather than be constantly monitoring it inside the main program loop. The completed project will entail more than just the strobing, so I need a way to make sure whatever code is running, it stops as soon as the brake lever is pressed. The problems arises with my use of the millis() function to set the interval between flashes. Since that won’t work inside of an interrupt, I’m stuck. I’ve tried the delayMicrosecond() function with no success and have also tried calling a separate function from within the interrupt in hopes that it would exit the ISR and go immediately to the function.

Now for the question; has anyone successfully done any kind of time based function inside of an interrupt like I’m trying to do with the strobing light? Is there a better way to go about doing it? In my mind, ideally I would like the interrupt to set a trigger of sorts that ends the ISR and jumps to a certain section of code, but that may or may not even be possible.

Any help or guidance would be much appreciated! If you need more of an explanation just let me know.

Thanks

#define OptoPin 2
#define MosfetPin 4

int StrobeFreq = 100;     //sets the delay between strobe pulses 
int OnTime = 1000;        //This is the amount of time that the strobe will flash before going solid
long StartTime;
long CurrentTime;
int BrakeIndex = 0;

void setup()
{
	pinMode(OptoPin, INPUT);
        pinMode(MosfetPin, OUTPUT);
	digitalWrite(MosfetPin, LOW);
	pinMode(ProgSimLight, OUTPUT);
}

void loop()
{
	if(digitalRead(OptoPin) == LOW && BrakeIndex == 0)   //12v has been applied (the brake is on) and it already hasn't strobed this time (BrakeIndex)
	{
		StartTime = millis();
		BrakeIndex = 1;         //it has already strobed when the brake was hit this time, so don't do it again

		do
		{
			digitalWrite(MosfetPin, !digitalRead(MosfetPin));
			delay(StrobeFreq);
			CurrentTime = millis();
		}
		while (CurrentTime < StartTime + OnTime && digitalRead(OptoPin) != HIGH);  //it will loop as long as it hasn't hit the strobing time limit or the brake hasn't been released (the signal went high)

		if(digitalRead(OptoPin) == LOW)   //the brake is still on after the stobing has stopped
		{
			digitalWrite(MosfetPin, HIGH);
		}

		else    //the brake was let go during the strobing so we want to leave the brake light off
		{
			digitalWrite(MosfetPin, LOW);
			BrakeIndex = 0;      //the brake was let go, so reset the index so it will strobe the next time
		}
	}
	
	else if (digitalRead(OptoPin) == HIGH)  //normal condition (optocoupler is sending 5v to the arduino)
	{
		digitalWrite(MosfetPin, LOW);
		BrakeIndex = 0;          //the brake was let go, so reset the index so it will strobe the next time
	}
}

The completed project will entail more than just the strobing, so I need a way to make sure whatever code is running, it stops as soon as the brake lever is pressed.

You can't do that in an interrupt. You can note that the interrupt happened, and then, in loop(), you deal with the fact that the interrupt happened.

There is nothing in your code that attaches an interrupt handler or that implements a handler, so it's difficult to see how interrupts are helping/hurting you.

One simple solution that springs to mind is to use one of the hardware timers. They can be set up to strobe at (virtually) any frequency with any duty cycle. Just turn that on, connect the MOSFET to the output, and turn it off a second later (or whenever you want to).

Example code:

const byte LED = 10;  // Timer 1 "B" output: OC1B
const byte PEDAL_PIN = 2;

const int ON_TIME     = 1000;    // This is the amount of time that the strobe will flash before going solid
const int STROBE_FREQ = 100;     // sets the delay between strobe pulses in milliseconds 
const unsigned long countTo = (F_CPU / 1024) / (1000 / STROBE_FREQ); 

volatile unsigned long whenPressed;
volatile bool pressed;

void brakePedal ()
  {
  bitSet (TCCR1A, COM1B1);   // clear OC1B on compare
  whenPressed = millis ();
  pressed = true;
  }
  
void setup() 
 {
  pinMode (LED, OUTPUT);
  pinMode (PEDAL_PIN, INPUT_PULLUP);

  // Fast PWM top at OCR1A
  TCCR1A = bit (WGM10) | bit (WGM11); // fast PWM
  TCCR1B = bit (WGM12) | bit (WGM13) | bit (CS12) | bit (CS10);   // fast PWM, prescaler of 1024
  OCR1A = countTo - 1;                 // zero relative 
  OCR1B = (countTo / 4) - 1;           // 25% duty cycle
  
  attachInterrupt (0, brakePedal, FALLING);
  }  // end of setup

void loop()
  {
  // switch from strobing to steady after ON_TIME
  if (pressed && (millis () - whenPressed >= ON_TIME))
    {
    bitClear (TCCR1A, COM1B1);
    digitalWrite (LED, HIGH);  // turn light on fully
    }

  // if pedal up, make sure light is off
  if (digitalRead (PEDAL_PIN) == HIGH)
    {  
    bitClear (TCCR1A, COM1B1);
    digitalWrite (LED, LOW);  // turn light off
    pressed = false;
    }
  
  // do other stuff here
  
  }  // end of loop

That uses an interrupt to detect a brake pedal press (strictly speaking you could probably just look for that in the main loop, since it is not exactly going to be a transient thing). When found it simply switches the output of Timer 1 on, with Timer 1 constantly counting up to the desired interval.

After a second, we turn the timer output off and the light fully on. When the pedal is released we turn the timer output off, and the light off.

Nick,

Thank you for such a detailed reply! I've definitely got a lot to learn :wink: I had no idea you could use the clock frequency of the arduino in this way. From what I understand of the code you posted and the link you provided, this is exactly the implementation I was looking for. Now all I've got to do is spend some quality time reading up on the particulars of those hardware timers to make sure I understand what's going on. Thanks again!