Run timer once and turn off

Hi I am hoping I may get some guidance, I have been banging my head against the wall for a few days now trying to execute what I need. For my application I would like the arduino to wait for some integer from the serial buffer, when it receives that value it will start timer1 and generate two PWM signals with the integer provided specifying the delay between the pulses.

Once these signals have been generated (the timer has reached the TOP value, in this case ICR1) I would like to reset the timer and delay value and wait for another delay value from the serial buffer. How I tried to achieve this is by trying to stop the timer and reset the delay once it overflows the first time with using the interrupt service routine and the timerStop function.

I can receive the delay and let the timer run indefinitely generating the signals I require but I can't get it to stop after a single count of the timer from 0 to 0xFFFF. It doesn't fire the signal on the first count and counts to the top twice every single time, as seen by the serial message "Timer Top" being returned.

I know there are easier ways to do this without using timers but I am hoping to learn more about them and in the future I will specify the count to be greater than 1. Below is my current code and I would really appreciate any guidance with this, I don't fully understand why the timer runs twice each time.

// TIMER STUFF 
#define PRESCALE 64


float ledDelay = 0.0;
float ledPulseDelay = 0.0;
int trigEdge = 0;
int ledFixedPW = 0;
volatile int count = 0;

void setup() {
  Serial.begin(9600);
  Serial.println("Input LED Delay:");
  systemInit();

}

void systemInit() {
  // initialise pins
  DDRB = B01100000; // Pin 11(PB5) and 12(PB6) as output

}

void startPulses(int ledPulseDelay) {

  //clear all interrupt & initialise timer
  cli();
  TCCR1A = 0;
  TCCR1B = 0;
  // configure timer 1
  #if PRESCALE==8
      TCCR1B |= bit(CS11) | bit(WGM12)| bit(WGM13);     // clk / 8
  #elif PRESCALE==64
      TCCR1B |= bit(CS10) | bit(CS11) | bit(WGM12) | bit(WGM13);    // clk / 64
  #elif PRESCALE==256
      TCCR1B |= bit(CS12) | bit(WGM12) | bit(WGM13);                // clk / 256
  #elif PRESCALE==1024
      TCCR1B |= bit(CS10) | bit(CS12) | bit(WGM12) | bit(WGM13);    // clk / 1024
  #endif
  TCCR1A = (1 << COM1B0) | (1 << COM1B1)  // Set OC1B on Compare Match, clear
           // OC1B at BOTTOM (inverting mode)
           | (1 << COM1A0) | (1 << COM1A1)  // Set OC1A on Compare Match, set
           // OC1A at BOTTOM (inverting mode)
           | (1 << WGM11);                 // Fast PWM, top at ICR1
           
  // wave form parameters for timer 1
  ledFixedPW = 15000;
  trigEdge = (0xFFFF - ledFixedPW - ledPulseDelay);
  OCR1A = trigEdge;
  OCR1B = 0xFFFF - ledFixedPW;
  ICR1 = 0xFFFF;
  TIMSK1 = (1 << TOIE1);
  TIFR1 = (1 << TOV1);
  // enable global interrupts:
   sei();

}

//=============

void timerStop(){
  TCCR1A = 0;
  TCCR1B = 0;
  ledDelay = 0;
  count = 0;
  Serial.println("Timer Stopped");
}

//=============

void loop() {

  if (Serial.available() > 0){
    ledDelay = Serial.parseInt();  
    Serial.read();
    startPulses(ledDelay);
    }
}

//=============

ISR(TIMER1_OVF_vect)
{
   count ++;
   if (count > 0){
    timerStop();
   }
}

The way things like this are often done is to use a flag (one-shot) or a counter (multiple). Set the flag and run your code. With the flag having been set you can then test the flag and skip subsequent instances. At some point you can reset the flag and then are ready to do it again.

On a detailed review,

DDRB = B01100000; // Pin 11(PB5) and 12(PB6) as output

The binary value says PB5(pin13) and PB6(you don't want to know) so probably you want

DDRB = B00011000; // Pin 11(PB3) and 12(PB4) as output

=========

#if PRESCALE==8
TCCR1B |= bit(CS11) | bit(WGM12)| bit(WGM13); // clk / 8
#elif PRESCALE==64
TCCR1B |= bit(CS10) | bit(CS11) | bit(WGM12) | bit(WGM13); // clk / 64
#elif PRESCALE==256
TCCR1B |= bit(CS12) | bit(WGM12) | bit(WGM13); // clk / 256
#elif PRESCALE==1024
TCCR1B |= bit(CS10) | bit(CS12) | bit(WGM12) | bit(WGM13); // clk / 1024
#endif

These are pre-compiler directives and will only be parsed and invoked at compilation. They should be at the top of your code as they will not be a part of the executable. If you want to change the prescaler at run-time, you do it differently.

Once you have determined and set your mode/prescaler, TCCR1A and TCCR1B, you can turn the timer ON/OFF by setting TCCR1B to your calculated value (ON) or zero (OFF), leave TCCR1A alone unless you plan to change the mode.

Clean that up first, post new code and we'll deal with the rest after.

Thank you very much for taking the time to assist me, it is very much appreciated.

Just from your comment I have already understood some more about the way timers are to be configured and I have made some updates but with regards to achieving my task I am still at a loss. I can still turn the timer on and achieve the signals I need but I can't get it to do so once per serial input. I have had friends tell me to toggle TCCR1B between 0 and my required configuration already, but I just can't seem to get the way I structure such code correctly and always end up with no signals being generated or two overflows before being turned off.

So in the setup I now configure my prescalers and edit the rest of the timer parameters in the startTimer function, and want to turn off the timer with stopTimer the first time it overflows. Using this with the code below I just keep resetting count and don't stop the timer. Would you mind explaining a bit further what you had in mind for stopping and starting TCCR1B? I have tried varying the way I toggle the TCCR1B bits but still am having no joy. Thanks again.

// TIMER STUFF 
#define PRESCALE 64


float ledDelay = 0.0;
float ledPulseDelay = 0.0;
int trigEdge = 0;
int ledFixedPW = 15000;
volatile int count = 0;

void setup() {
  Serial.begin(9600);
  Serial.println("Input LED Delay:");
  
  pinMode(11, OUTPUT);
  pinMode(12, OUTPUT);
  digitalWrite(11, LOW);
  digitalWrite(12, LOW);

  TCCR1A = 0;
  TCCR1B = 0;
  
  #if PRESCALE==8
      TCCR1B |= bit(CS11);     // clk / 8
  #elif PRESCALE==64
      TCCR1B |= bit(CS10) | bit(CS11);    // clk / 64
  #elif PRESCALE==256
      TCCR1B |= bit(CS12);                // clk / 256
  #elif PRESCALE==1024
      TCCR1B |= bit(CS10) | bit(CS12);    // clk / 1024
  #endif
}

void timerStart(int ledPulseDelay) {

  cli();
  
  TCCR1B |= bit(WGM12)| bit(WGM13);      
  TCCR1A = (1 << COM1B0) | (1 << COM1B1)  // Set OC1B on Compare Match, clear
           // OC1B at BOTTOM (inverting mode)
           | (1 << COM1A0) | (1 << COM1A1)  // Set OC1A on Compare Match, set
           // OC1A at BOTTOM (inverting mode)
           | (1 << WGM11);                 // Fast PWM, top at ICR1

  trigEdge = (0xFFFF - ledFixedPW - ledPulseDelay);
  OCR1A = trigEdge;
  OCR1B = 0xFFFF - ledFixedPW;
  ICR1 = 0xFFFF;
  TIMSK1 = (1 << TOIE1);
  TIFR1 = (1 << TOV1);

  sei();
  
   
 }

//=============

void timerStop(){
  TCCR1B |= bit(0 << WGM12)| bit(0 << WGM13);
  ledDelay = 0;
  count = 0;
}

//=============

void loop() {

  if (Serial.available() > 0){
    ledDelay = Serial.parseInt();  
    Serial.read();
    }

  if (ledDelay > 0){
    timerStart(ledDelay);
  }
  
  if (count > 0){
    Serial.println(count);
    timerStop();
  }
   
}

//=============

ISR(TIMER1_OVF_vect)
{
  count ++;
}

You really need to spend some time studying the timer behaviour (read the datasheet!).

Unless you plan on changing them, and your code doesn't, remove all the references to the control registers to setup. There is no need to have them in a function that is continually called in loop. Get rid of the ICR1 references. ICR in the input control register that counts pulses on T1 which in Arduinoese is pin 5. You're doing nothing with that and should leave it alone.

Please read about timers and PWM. Google 'Arduino PWM secrets' there's a really good article and it will take less time, and you'll understand more than if I simply repeat that here. Setting OCR1A will determine the frequency, setting OCR1B will determine the duty cycle. You have OCR1B set at MAX which in this case is meaningless.

I'll spend more time here with you once you've demonstrated that you've taken the initiative to bring yourself up to at least the novice level pertaining to the topic. Otherwise, try the forum on Tutorials. Timers and PWM are quite intense topics that require more than just hit and miss, if you care to understand.