A zero detector crossover sends a pulse to the Arduino, it must start counting x time and then a pulse is sent from the Arduino, once the timer reaches time x, it must stop counting and only start counting again when it receives the new pulse of the zero crossing detector, the idea is to do something like this: enter image description here What I don't know is how to keep the timer off all the time toff that appears in the image.

  • A zero detector crossover sends a pulse to the arduino... How does your code and wiring detect the zero cross-over now? Is the detector external and just sends a signal to Arduino? Wouldn't you just reset the timer any time you detected the cross-over to positive? Or doesn't the detector distinguish between a positive crossing and a negative one? Or are you really wanting to know how to do a cross-over detection for a sinusoidal signal?
    – lurker
    Commented Apr 17, 2021 at 1:40
  • @lurker what I get from the zero crossing detector is a train of pulses, which varies from 0 to 5v each time it passes through zero, but that's not the point, create an edge ISR when the signal varies, at that time it should start the counting, stop when it reaches the time x that I need and stay off until the next zero edge, in the examples that I have seen the timer restarts and continues counting, I need it to turn off or stop counting until the next zero crossing Commented Apr 17, 2021 at 2:43
  • 1
    Does this answer your question? Fan regulator control from Arduino
    – Juraj
    Commented Apr 17, 2021 at 6:25
  • 1
    You can trick the timer into doing one-shot, by setting the counter to a value higher than TOP. See hackaday.com/2015/03/24/…
    – Gerben
    Commented Apr 17, 2021 at 15:51

2 Answers 2


the way to turn off the Timer is to set the CS12, CS11 and CS10 prescale bits to 0, in this way the CLK signal is disconnected and the timer stops counting, when you want the timer to continue counting, they are set back to 1 the CS12, CS11 and CS10 bits according to the selected prescale.

byte savePrescale

savePrescale = TCCR1B & (0b111<<CS10);
TCCR1B &= ~(0b111<<CS10); // Stop Timer1 Clock
TCCR1B |= savePrescale;  // Restart Timer1 clock.

You can initiate a "One shot" timer at each zero-crossing.

The trick @Gerben mentioned in turn off Timer1 / Timer1 One-shot eventually links to code at https://github.com/bigjosh/TimerShot which does the one-shot functionality on Timer2 by idling the timer at TCNT2=0 with OCR2A=0, and using the TCNT2 space above 0 to operate an adjustable oneshot on OC2B.

This trick can be adapted to Timer1:

// The one shot pulses are output on Digital pin OC1B (Arduino Uno D10, Mega D12, Nano D3) 
// Modified by Dave Forrest 2020-01-11 for Timer 1
// Based on Josh Levine's Nov 23, 2015 work at https://github.com/bigjosh/TimerShot/blob/master/TimerShot.ino

#define OSP_SET_WIDTH(cycles) (OCR1B = 0xffff-(cycles-1))

// Setup the one-shot pulse generator and initialize with a pulse width that is (cycles) clock counts long

void osp_setup(uint16_t cycles) {

  TCCR1B =  0;      // Halt counter by setting clock select bits to 0 (No clock source).
              // This keeps anything from happeneing while we get set up

  TCNT1 = 0x00;     // Start counting at bottom. 
  OCR1A = 0;      // Set TOP to 0. This effectively keeps us from counting because the counter just keeps reseting back to 0.
          // We break out of this by manually setting the TCNT higher than 0, in which case it will count all the way up to MAX and then overflow back to 0 and get locked up again.
  OSP_SET_WIDTH(cycles);    // This also makes new OCR values get loaded from the buffer on every clock cycle. 

  TCCR1A = 0b11<<COM1B0  | 0b11<<WGM10;  // OC1B=Set on Match, clear on BOTTOM. Mode 15 Fast PWM.
  TCCR1B = (0b11<<WGM12)| (0b001<<CS10); // Start counting now. WGM 15=0b1111  to select Fast PWM mode 

  //DDRB |= _BV(2);     // Set pin to output (Note that OC1B = GPIO port PB2 = Arduino Uno Digital Pin 10)
  DDRB |= _BV(6);     // Set pin to output (Note that OC1B = GPIO port PB6 = Arduino Mega Digital Pin 12)
  //DDRD |= _BV(3);     // Set pin to output (Note that OC1B = GPIO port PD3 = Arduino Nano Digital Pin 3)

// Setup the one-shot pulse generator

void osp_setup() {

// Fire a one-shot pulse. Use the most recently set width. 

#define OSP_FIRE() (TCNT1 = OCR1B - 1)

// Test there is currently a pulse still in progress

#define OSP_INPROGRESS() (TCNT1>0)

// Fire a one-shot pulse with the specified width. 
// Order of operations in calculating m must avoid overflow of the uint16_t.
// TCNT2 starts one count lower than the match value becuase the chip will block any compare on the cycle after setting a TCNT. 

#define OSP_SET_AND_FIRE(cycles) {uint16_t m=0xffff-(cycles-1); OCR1B=m;TCNT1 =m-1;}

void setup()


void loop()
  // Step though 0-11 cycle long pulses for demo purposes 
  for (uint8_t o = 0; o < 101; o++) {
    while (OSP_INPROGRESS());         // This just shows how you would wait if necessary - not necessary in this application. 
    //_delay_us(1);      // Wait to let the audience clap

This code produced pulses with a resolution of 62.5ns, which is on the edge of what my test equipment can measure. Here's a 6.25us, 100 cycle pulse next to a 1 cycle pulse:

enter image description here

With Timer1's 16 bit range and the /1 prescaler you can do pulses from 62.5ns to 4us. With the /1024 prescaler, (TCCR1B|=(0b101 <<CS10);) it can do 64us up to 4.194sec. With /256 prescaler, (TCCR1B|=(0b100 <<CS10);) it can do 16us up to 1.05sec.

For a one shot triggered on a zero-crossing, you might try something like this with the above

void loop()
  int t1_us = 1000000UL/60 /8 ; // 1/8th of a 60Hz cycle

  if(needOneShot){  // Set needOneShot with an interrupt or sensor or something
    OSP_SET_AND_FIRE(t1_us/16);  // 16us ticks with the /256 prescaler 
     needOneShot = false; 

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.