1

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.

ocrdu
  • 1,795
  • 3
  • 12
  • 24

2 Answers2

3

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. ...

Dave X
  • 2,350
  • 15
  • 29
1

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() { osp_setup(1); }

// 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() { osp_setup();

}

void loop() { // Step though 0-11 cycle long pulses for demo purposes for (uint8_t o = 0; o < 101; o++) { OSP_SET_AND_FIRE(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; } ... }

Dave X
  • 2,350
  • 15
  • 29