Transistor und PWM gedimmte LEDs. (flackern)

Die Arduino Prescaler stehen normalerweise auf 64 --> die PWM Frequenzen sind dann etwa 500 und 250 Hz.

Jetzt wird durch die äußere Schleife nochmal eine Art PWM drübergelegt die in der Nähe von n Millisekunden liegt.

Das Ergebnis nennt sich je nachdem in welchem Umfeld man es beobachtet mal Schwebung Schwebung – Wikipedia
mal Moiree Effekt Moiré-Effekt – Wikipedia.

Nanosekunden Delay auf einem 16 MhZ Chip geht nicht. Mikrosekunden schon (delayMicroseconds()).

Vermutlich wäre es aber besser das ganze Konzept zu überdenken. Was genau willst Du erreichen? Die LEDs unabhängig voneinander dimmen oder alle gemeinsam? Im zweiten Fall wäre es erheblich leichter die Kathoden zu Modulieren und die Anoden zu schalten.

Ansonsten wäre es sinnvoll die beiden Frequenzen möglichst weit auseinander zu bringen. D.h. PWM hochdrehen. Das ist nicht weiter schwierig, bringt aber das Timingverhalten von von delay() durcheinander.

In wiring.c steht:

#include "wiring_private.h"

// the prescaler is set so that timer0 ticks every 64 clock cycles, and the
// the overflow handler is called every 256 ticks.
#define MICROSECONDS_PER_TIMER0_OVERFLOW (clockCyclesToMicroseconds(64 * 256))

// the whole number of milliseconds per timer0 overflow
#define MILLIS_INC (MICROSECONDS_PER_TIMER0_OVERFLOW / 1000)

// the fractional number of milliseconds per timer0 overflow. we shift right
// by three to fit these numbers into a byte. (for the clock speeds we care
// about - 8 and 16 MHz - this doesn't lose precision.)
#define FRACT_INC ((MICROSECONDS_PER_TIMER0_OVERFLOW % 1000) >> 3)
#define FRACT_MAX (1000 >> 3)

volatile unsigned long timer0_overflow_count = 0;
volatile unsigned long timer0_millis = 0;
static unsigned char timer0_fract = 0;

SIGNAL(TIMER0_OVF_vect)
{
      // copy these to local variables so they can be stored in registers
      // (volatile variables must be read from memory on every access)
      unsigned long m = timer0_millis;
      unsigned char f = timer0_fract;

      m += MILLIS_INC;
      f += FRACT_INC;
      if (f >= FRACT_MAX) {
            f -= FRACT_MAX;
            m += 1;
      }

      timer0_fract = f;
      timer0_millis = m;
      timer0_overflow_count++;
}

Wenn Du also den Prescaler auf 1 stellst, dann wird die ISR 64 mal so oft durchlaufen. Also etwa alle 16 Mikrosekunden. --> es wäre sinnvoll die ISR gleich ganz abzustellen. Ansonsten wird Dein Arduino nur noch in der ISR rumgammeln.

Am bequemsten geht das mit "cli()".

Gruß, Udo