Generating single timer interrupt

I have a lot of experience with interrupt programming with the 6502/6522 processor/VIA but have only just started looking at interrupt programming with the Arduino.

What I want to do is generate a single pin state change after a precise time. I have used the timer in an arduino loop() but this is not accurate enough for me so I want to use 3 timers in an ATMega to control 3 pins accurately with their own delays (which may or may not overlap)

The examples I have found online all generate repeating interrupts as the timer resets to zero and starts another cycle.

I don’t want this, I just want the interrupt to run once after it is started.

The 6522 had a register that would allow me to program a single interrupt as opposed to a repeating one. Is there any way of doing the same with the Arduino? The alternative would be to disable the timer interrupt in the interrupt handling routine but I’m not sure how best to do this.

Can anyone advise please?

This may be dumb, but what about this:

Define a boolean variable, didInterrupt, and initialize it to false.

ISR HANDLER FUNCTION
{
  IF didInterrupt is false THEN
  {
    Drive the pin high
    Set didInterrupt to true
  }
}

Another approach would be to, in loop(), remove the interrupt handler or stop the timer or whatever after the “interruptTriggered” variable is changed by the first ISR.

What you do is set the OCR value for your desired delay, set your pin high, enable OCIE interrupt for your timer, the ISR is called after the delay in the ISR,, set pin low, then disable OCIE for your timer

Interrupts: Gammon Forum : Electronics : Microprocessors : Interrupts

Timers: Gammon Forum : Electronics : Microprocessors : Timers and counters

Thanks all for the suggestions. The boolean flag solution is not suitable. The other methods are what I had thought I would do.

I was just wondering if there was a register value that would achieve the same thing automatically.

Thanks for the links Nick. They look useful

What I want to do is generate a single pin state change after a precise time.

I believe you can do this by setting the "output compare unit" of the timer to clear or set the pin state on match, and using the timer in "normal" mode. The timer will keep running, but doesn't reset the pin at BOTTOM the way that the PWM modes do.
You'll have to read the datasheet and do some experimenting to get this working, I guess. I don't think I've seen any libraries go by that support this mode of operation.

drpeej:
Thanks all for the suggestions. The boolean flag solution is not suitable. The other methods are what I had thought I would do.

I was just wondering if there was a register value that would achieve the same thing automatically.

Thanks for the links Nick. They look useful

Exactly what I said above is exactly what you want.

You can read the data sheet first. Everything you need to know is there. Do you need an example?

Almost. I don’t think you need to use the interrupt at all…

Almost. I don't think you need to use the interrupt at all...

I know I didnt really explain exactly what I was trying to do but I want to trigger 3 events of varying durations asynchronously.

I have done it in a loop comparing the event timings with micros() but it's got a bit lengthy and it's not as precise as I would like.

So I decided that I would handle it with interrupts where I can set the events off and let them look after themselves away from the main program loop.

I have done some initial tests this morning and I can now achieve what I want.

Thanks everyone.

this is a one shot 20ms pulse example

code is for MEGA

void setup() {
DDRB |= _BV(PB5); //set digital pin11 to output
PORTB |= _BV(PB5); //set it high
TCCR1A=0;
TCCR1B= _BV(CS11)|_BV(CS10);  //use clock div 64 to get 4us per count
OCR1A=TCNT1+5000; //5000*4=20ms
TIMSK1 |= _BV(OCIE1A); //enable interrupt
}

void loop() {
}

ISR(TIMER1_COMPA_vect){
PORTB &= ~_BV(PB5); //set pin low
TIMSK1 &= ~_BV(OCIE1A);   //disable interrupt
}

this is the pulse, generated asyncrhronously (you can do other things in loop)

If I use 4998, I get a 20.0005ms pulse. I think that is as accurate as you can get.