Arduino Uno mit PWM an einem Shiftregister

Guten Tag zusammen,

ich bitte um Nachsicht, da das hier mein erster Post ist.
Meist lese ich sehr, sehr viel, und finde die Lösung ohne direkte Nachfrage, aber heute möchte ich gerne zu einer Schwierigkeit die Mitforisten befragen.

Zur Zeit versuche ich an den Ausgängen eines 74HC595 PWM Signale mit verschiedenen Tastverhältnissen zu erzeugen.
Das ganze möchte ich ohne Hardware-PWM oder Interrupt-Timer realisieren.

int latchPin = 5;  // RCLK (Register Clock / Latch) Pin des 74HC595 ist verbunden mit dem digitalen Pin 5
int clockPin = 6; // SRCLK (Shit Register Clock) Pin des 74HC595 ist verbunden mit dem digitalen Pin 6
int dataPin = 4;  // SER (Serial input) Pin des 74HC595 ist verbunden mit dem digitalen Pin 4

int microsCycle = 2000;
int microsDutyOn[8] = {1000, 0, 2000, 0, 80, 0, 100, 10};

void setup() 
{
  // Alle Pins für den 74HC595 des Arduino auf OUTPUT (=Ausgang) setzen
  pinMode(latchPin, OUTPUT);
  pinMode(dataPin, OUTPUT);  
  pinMode(clockPin, OUTPUT);
  pinMode(13, OUTPUT);
}

void loop() 
{
  //Beschreiben des Shiftregisters in micros-Intervallen
  digitalWrite(latchPin, LOW);
  for (int i = 0; i < 8; i++) {
    digitalWrite(clockPin, LOW);
    if ((micros()%microsCycle) < microsDutyOn[i]) { //die 8 Ausgänge des Shiftregisters sollen unterschiedliche Tastverhältnisse bekommen
      digitalWrite(dataPin, HIGH);
    }
    else {
      digitalWrite(dataPin, LOW);
    }
    digitalWrite(clockPin, HIGH);
  }
  digitalWrite(latchPin, HIGH);
  
  //Der folgende Teil erzeugt ein Rechtecksignal zur Kontrolle der grundsätzlichen Möglichkeit eine PWM auf diese Art zu erzeugen
  if ((micros()%microsCycle) < 1000) {
    digitalWrite(13, HIGH);
  }
  else {
    digitalWrite(13, LOW);
  }
}

Die Ausgänge des Shiftregisters sind zu Testzwecken mit LEDs ausgestattet.
Es wird erwartet, dass jede LED je nach Tastverhältnis unterschiedlich hell leuchtet.
Bei einer Wiederholfrequenz (microsCycle) von 2ms sollte das “Flimmern” außerhalb der Wahrnehmbarkeit liegen.
Die einzelnen Ausgänge des Shiftregisters “flackern” aber, so dass die LEDs sichtbar flimmern.

An Pin13 habe ich zu Testzwecken mit dem gleichen Ansatz ein sauberes Rechtecksignal erzeugen können.
(Ich habe die Möglichkeit mit einem Oszilloskop zu messen).
Sobald ich aber den Code-Teil für das Shiftregister integriere, ist auch dieses Signal unregelmäßig unterbrochen.

Ich hoffe ich konnte mich verständlich ausdrücken und das Einfügen des Codes hat den Erwartungen des Forums entsprechend geklappt.

Hoffentlich hat jemand Freude daran mir Tipps zu diesem “Problem” zu geben.

Vielen Dank für’s Lesen
Beste Grüße
Christoph

“Break it. Fix it. Repeat”

warum verwendest du nicht shiftOut, oder gleich HW-SPI?

Oder 3 Schritte zurück: warum überhaupt ein 74HC595? Was soll es am Ende werden? Für LED PWM gibt es so schöne IC's da findet sich sicher etwas wenn man weis was es genau werden soll.

Flackern bedeutet (viel) zu langsamer Refresh. Vor allem dürfte die Modulo-Funktion "%" eine Bremse sein, weil die kleinen Arduinos alle Divisionen emulieren müssen.

Hallo zusammen,

zunächst vielen Dank für die Annahme meines “Problems”.
Mir ist natürlich bewußt, dass es dazu auch modernere ICs als das 595 gibt.
Mir ging es jetzt eher darum zu verstehen, weshalb dieser Code nicht wie erwartet funktioniert.

Der Tipp mit Modulo war da wohl richtig.
Mit folgendem Code funktioniert es wie erwartet.
Jeder Ausgang des Shiftregisters hat seine eigene “On-Time” bei einer “Cycle-Time” von 2000µs.

Folgender Code macht das:

int latchPin = 5;  // RCLK (Register Clock / Latch) Pin des 74HC595 ist verbunden mit dem digitalen Pin 5
int clockPin = 6; // SRCLK (Shit Register Clock) Pin des 74HC595 ist verbunden mit dem digitalen Pin 6
int dataPin = 4;  // SER (Serial input) Pin des 74HC595 ist verbunden mit dem digitalen Pin 4

int microsCycle = 2000;
int microsDutyOn[8] = {10, 0, 200, 0, 300, 0, 500, 100};
unsigned long previousMicros;

void setup() 
{
  // Alle Pins für den 74HC595 des Arduino auf OUTPUT (=Ausgang) setzen
  pinMode(latchPin, OUTPUT);
  pinMode(dataPin, OUTPUT);  
  pinMode(clockPin, OUTPUT);
  pinMode(13, OUTPUT);
}

void loop() 
{
  //Beschreiben des Shiftregisters in micros-Intervallen
  digitalWrite(latchPin, LOW);
  unsigned long currentMicros = micros();
  for (int i = 0; i < 8; i++) {
    digitalWrite(clockPin, LOW);
    if (currentMicros - previousMicros < microsCycle) {
      if ((currentMicros-previousMicros) < microsDutyOn[i]) { //die 8 Ausgänge des Shiftregisters sollen unterschiedliche Tastverhältnisse bekommen
        digitalWrite(dataPin, HIGH);
      }
      else {
        digitalWrite(dataPin, LOW);
      }
    }
    else {
      previousMicros = micros();
    }
    digitalWrite(clockPin, HIGH);
  }
  digitalWrite(latchPin, HIGH);
  
  //Der folgende Teil erzeugt ein Rechtecksignal zur Kontrolle der grundsätzlichen Möglichkeit eine PWM auf diese Art zu erzeugen
  if ((micros()-previousMicros) < 1000) {
    if (micros() - previousMicros < 500) {
      digitalWrite(13, HIGH);
    }
    else {
      digitalWrite(13, LOW);
    }
  }
  else {
    previousMicros = micros();
  }
}

Völlig klar, dass dies nicht mit Hardware-PWM oder Interrupt gesteuerten Signalen vergleichbar ist.
Aber für unterschiedlich helle, nicht flackernde LEDs genügt es.

currentMicros muss tatsächlich mitgenutzt werden. Die for-Schleife scheint mehr als 2000µs zu benötigen.
Vermutlich wäre hier das Arbeiten mit ganzen Ports von Vorteil.
Aber das ist ein anderes Thema.

Besten Dank für die Zusammenarbeit.
Freundliche Grüße
Christoph