user87134: I have a 32.768 kHz signal at the ATmega328P input.
I need to get 2 signals from this signal: 1Hz and 32Hz.
How well will it work?
How to do this with a ATmega328P Timer/Counter?
What gain will the Timer/Counter give compared to my solution?
void setup() {
   pinMode(S32768Hz_PIN, INPUT_PULLUP); // 32.768 kHz signal
   attachInterrupt(digitalPinToInterrupt(S32768Hz_PIN), s32768Isr, FALLING); // Pin 3
}

volatile bool s32768IsrWasCalled = false;  // ISR flag 32768Hz
void s32768Isr() {
   s32768IsrWasCalled = true;
}
uint16_t s32Counter = 0;
uint16_t s1Counter = 0;

void loop() {
  if (s32768IsrWasCalled) {
      s32768IsrWasCalled = false;
      s32Counter++;
      if (s32Counter == 1024) {
        s32Counter = 0;
        // 32Hz
      }

      s1Counter++;
      if (s1Counter == 32768) {
        s1Counter = 0;
        // 1Hz
      }
  }
}

Update 24.10.2022
I wrote my first timer 1 setup code. Will this run 32 times per second, indefinitely?
// ATmega328P 3.3V 8MHz, Timer 1 & DS3231 32768 Hz
void setupTimer1() {
    // Disables all interrupts
    cli();
    // Reset bits
    TCCR1A = 0;
    TCCR1B = 0;
    // Enable Timer 1 overflow interrupt (TOIE1)
    TIMSK1 = (1 << TOIE1);
    // PWM mode. Mode #7 (fast PWM, top is fixed at 10 bits = 1024)
    TCCR1A |= _BV(WGM10) | _BV(WGM11);
    TCCR1B |= _BV(WGM12);
    // External clock on T1 pin, on falling edge (DS3231 32768Hz pin)
    TCCR1B |= (1 << CS11) | (1 << CS12);
    // Enables interrupts
    sei();
    // pinMode(T1_pin, INPUT_PULLUP); ?
}

void loop() {
    // So get 1 Hz from 32 Hz?
    // There will be no data races here?
    if((pulse_counter % 32) == 0) {
        callback1Hz();
    }
    
    if((pulse_counter % 2) == 0) {
        callback16Hz();
    }
}

volatile uint8_t pulse_counter;
// Timer 1 Overflow (32 Hz)
ISR(TIMER1_OVF_vect) {
    pulse_counter++;
}

Thank you!

user7508: I did not test your program but, just by looking at it, I would expect
it to work... provided you do not add more code! Obviously you will need
to add more code in order to do something useful with those signals, and
then thinks might break.
The problem with this approach is that the interrupt rate is pretty
high: the program gets interrupted every 30.5 µs. You may miss an
interrupt if either:

it fires while there is already an interrupt (or other critical
section) being processed, and that interrupt (maybe combined with
some other pending interrupt) takes more than 30.5 µs to
complete

you add more code to loop() and that function ends up taking more
than 30.5 µs.


The first condition should be obvious, but I would assume the risk is
quite low, as only a very poorly written ISR would take that long to
complete. Beware however of library code, as that might bring surprises.
The second condition is a bigger risk, although maybe less obvious. The
problem is that this loop() assumes the code within
if (s32768IsrWasCalled) is going to be called exactly once per
interrupt. This may not be the case: if the program gets bigger, you may
miss interrupts, and get the frequencies wrong.
A simple way to avoid the issue number 2 is to count the pulses within
the ISR, as PMF suggests in a comment. I would use a single counter for
this, and make it unsigned in order to guarantee that it wraps around
reliably:
volatile uint16_t pulse_counter;
void s32768Isr() {
    pulse_counter++;
}

void loop() {
    int signal_32Hz = (pulse_counter >> 9) & 1;
    int signal_1Hz = (pulse_counter >> 14) & 1;
}

Note that this is one of the few cases when you can access the volatile
multi-byte variable without disabling interrupts: since you only ever
care about one bit, there is no data race.
A better option, though, would be to use a hardware timer for this job.
I would suggest using Timer 1 in “counter” mode (external clock
source on pin T1). Using mode 7 (fast PWM, 10-bit) you get the
32 Hz signal entirely generated by the hardware. And then you can
use the timer overflow interrupt to generate 1 Hz. The interrupt
rate is now 1024 times lower. I let you check the datasheet for the
details.

87134: <p>I have a 32.768 kHz signal at the ATmega328P input.
I need to get 2 signals from this signal: 1Hz and 32Hz.
How well will it work?
How to do this with a ATmega328P Timer/Counter?
What gain will the Timer/Counter give compared to my solution?</p>
<pre><code>void setup() {
   pinMode(S32768Hz_PIN, INPUT_PULLUP); // 32.768 kHz signal
   attachInterrupt(digitalPinToInterrupt(S32768Hz_PIN), s32768Isr, FALLING); // Pin 3
}

volatile bool s32768IsrWasCalled = false;  // ISR flag 32768Hz
void s32768Isr() {
   s32768IsrWasCalled = true;
}
uint16_t s32Counter = 0;
uint16_t s1Counter = 0;

void loop() {
  if (s32768IsrWasCalled) {
      s32768IsrWasCalled = false;
      s32Counter++;
      if (s32Counter == 1024) {
        s32Counter = 0;
        // 32Hz
      }

      s1Counter++;
      if (s1Counter == 32768) {
        s1Counter = 0;
        // 1Hz
      }
  }
}
</code></pre>
<p>Update 24.10.2022
I wrote my first timer 1 setup code. Will this run 32 times per second, indefinitely?</p>
<pre><code>// ATmega328P 3.3V 8MHz, Timer 1 &amp; DS3231 32768 Hz
void setupTimer1() {
    // Disables all interrupts
    cli();
    // Reset bits
    TCCR1A = 0;
    TCCR1B = 0;
    // Enable Timer 1 overflow interrupt (TOIE1)
    TIMSK1 = (1 &lt;&lt; TOIE1);
    // PWM mode. Mode #7 (fast PWM, top is fixed at 10 bits = 1024)
    TCCR1A |= _BV(WGM10) | _BV(WGM11);
    TCCR1B |= _BV(WGM12);
    // External clock on T1 pin, on falling edge (DS3231 32768Hz pin)
    TCCR1B |= (1 &lt;&lt; CS11) | (1 &lt;&lt; CS12);
    // Enables interrupts
    sei();
    // pinMode(T1_pin, INPUT_PULLUP); ?
}

void loop() {
    // So get 1 Hz from 32 Hz?
    // There will be no data races here?
    if((pulse_counter % 32) == 0) {
        callback1Hz();
    }
    
    if((pulse_counter % 2) == 0) {
        callback16Hz();
    }
}

volatile uint8_t pulse_counter;
// Timer 1 Overflow (32 Hz)
ISR(TIMER1_OVF_vect) {
    pulse_counter++;
}
</code></pre>
<p>Thank you!</p>
 7508: <p>I did not test your program but, just by looking at it, I would expect
it to work... provided you do not add more code! Obviously you will need
to add more code in order to do something useful with those signals, and
then thinks might break.</p>
<p>The problem with this approach is that the interrupt rate is pretty
high: the program gets interrupted every 30.5 µs. You may miss an
interrupt if either:</p>
<ol>
<li><p>it fires while there is already an interrupt (or other critical
section) being processed, and that interrupt (maybe combined with
some other pending interrupt) takes more than 30.5 µs to
complete</p>
</li>
<li><p>you add more code to <code>loop()</code> and that function ends up taking more
than 30.5 µs.</p>
</li>
</ol>
<p>The first condition should be obvious, but I would assume the risk is
quite low, as only a very poorly written ISR would take that long to
complete. Beware however of library code, as that might bring surprises.</p>
<p>The second condition is a bigger risk, although maybe less obvious. The
problem is that this <code>loop()</code> assumes the code within
<code>if (s32768IsrWasCalled)</code> is going to be called exactly once per
interrupt. This may not be the case: if the program gets bigger, you may
miss interrupts, and get the frequencies wrong.</p>
<p>A simple way to avoid the issue number 2 is to count the pulses within
the ISR, as PMF suggests in a comment. I would use a single counter for
this, and make it unsigned in order to guarantee that it wraps around
reliably:</p>
<pre class="lang-cpp prettyprint-override"><code>volatile uint16_t pulse_counter;
void s32768Isr() {
    pulse_counter++;
}

void loop() {
    int signal_32Hz = (pulse_counter &gt;&gt; 9) &amp; 1;
    int signal_1Hz = (pulse_counter &gt;&gt; 14) &amp; 1;
}
</code></pre>
<p>Note that this is one of the few cases when you can access the volatile
multi-byte variable without disabling interrupts: since you only ever
care about one bit, there is no data race.</p>
<p>A better option, though, would be to use a hardware timer for this job.
I would suggest using Timer 1 in “counter” mode (external clock
source on pin T1). Using mode 7 (fast PWM, 10-bit) you get the
32 Hz signal entirely generated by the hardware. And then you can
use the timer overflow interrupt to generate 1 Hz. The interrupt
rate is now 1024 times lower. I let you check the datasheet for the
details.</p>
