Skip to Content

Parola-Animationen auf dem MAX7219 LED-Display steuern

Parola-Animationen auf dem MAX7219 LED-Display steuern

In diesem Tutorial lernst du, wie du Parola-Animationen auf einem MAX7219 LED-Matrix-Display steuerst. Wir werden Animationen aneinanderreihen, Taster verwenden, um zwischen Animationen zu wechseln, und Potentiometer einsetzen, um die Helligkeit und die Geschwindigkeit der Animationen einzustellen.

Die MD_Parola-Bibliothek ist eine beliebte Bibliothek, die das Programmieren von Animationen auf einem Display, wie z.B. Lauftext, sehr einfach macht. Einzelne Animationen sind leicht umzusetzen, aber das Aneinanderreihen oder Steuern mehrerer Animationen kann schwieriger sein. Oft möchten wir auch Sensordaten auslesen, ohne die Animation zu unterbrechen. Dieses Tutorial zeigt dir, wie das geht.

Benötigte Teile

Ich habe für dieses Projekt ein Arduino Uno verwendet, aber jedes andere Arduino-Board oder ein ESP8266/ESP32-Board funktioniert genauso gut. Hier nutzen wir ein MAX7219 LED-Matrix-Display, das aus 4 Modulen besteht. Der Code und die Verdrahtung sind für Displays mit mehr oder weniger Modulen im Wesentlichen gleich.

MAX7219 LED-Matrix-Display 

Arduino

Arduino Uno

Dupont wire set

Dupont-Kabelset

Half_breadboard56a

Steckbrett

USB Data Sync cable Arduino

USB-Kabel für Arduino UNO

Potentiometer 10KΩ

Makerguides is a participant in affiliate advertising programs designed to provide a means for sites to earn advertising fees by linking to Amazon, AliExpress, Elecrow, and other sites. As an Affiliate we may earn from qualifying purchases.

MAX7219 LED-Display mit Arduino verbinden

In diesem Tutorial verwenden wir ein MAX7219 LED-Matrix-Display, um Animationen anzuzeigen. Der MAX7219 LED-Display-Treiber kommuniziert mit dem Arduino über SPI (Serial Peripheral Interface). Das erste, was du also tun musst, ist, das Display über die SPI-Schnittstelle mit dem Arduino zu verbinden.

Verdrahtung

Das folgende Diagramm zeigt dir die benötigte Verdrahtung zwischen dem MAX7219-Display und einem Arduino Uno. Achte darauf, dass du das Display an der Eingangsseite (DIN) und nicht an der Ausgangsseite (DOUT) anschließt.

Connecting MAX7219 Display to Arduino UNO
MAX7219-Display mit Arduino UNO verbinden

Beginne damit, die SPI-Pins zu verbinden: Pin 11 des Arduino wird mit dem DIN-Pin des Displays verbunden. Dann verbinde Pin 3 mit CS und Pin 13 mit CLK. Schließlich verbinde 5V mit VCC und GND mit GND. Die folgende Tabelle zeigt die Verbindungen noch einmal:

Display Arduino
VCC 5 V
GND GND
DIN 11 (MOSI)
CS 3 (SS)
CLK 13 (SCK)

Die oben gewählten Pins sind für Hardware-SPI, was schneller ist als Software-SPI, aber du musst dafür bestimmte Pins verwenden, die je nach Board unterschiedlich sind. Für mehr Details siehe die MAX7219 LED dot matrix display Arduino tutorial .

Als Nächstes schreiben und testen wir etwas Beispielcode, um sicherzustellen, dass die Verbindungen korrekt sind.

MD_Parola und MD_MAX72XX Bibliotheken installieren

Zuerst müssen wir die MD_MAX72XX und die MD_Parola Bibliothek installieren. Du kannst diese Bibliotheken über den Library Manager der Arduino IDE installieren. Gehe zu Tools > Manage Libraries , um den Library Manager zu öffnen. Suche nach „MD_MAX72XX“ und die passenden Bibliotheken werden angezeigt. Im Screenshot unten siehst du, dass ich die beiden Bibliotheken bereits installiert habe (gelb markiert):

Install MD_MAX72XX and MD_Parola library
Installiere MD_MAX72XX und MD_Parola Bibliothek

Die MD_MAX72XX-Bibliothek ist im Grunde die Treibersoftware für das MAX7219 LED-Display. Die MD_Parola-Bibliothek nutzt sie, um Animationen wie Lauftext und Sprite-Effekte zu erstellen. Wenn du mehr über die verfügbaren Animationen erfahren möchtest, schau in die MAX7219 LED dot matrix display Arduino tutorial .

Testcode

Der folgende Code ist ein minimales Beispiel, um die Verdrahtung und Funktion des Displays zu testen. Er zeigt einfach den Lauftext „Test“ auf dem Display an.

#include "MD_Parola.h"
#include "MD_MAX72xx.h"
#include "SPI.h"

#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
#define MAX_DEVICES 4
#define CS_PIN 3  

MD_Parola disp = MD_Parola(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);

void setup() {
  disp.begin();
  disp.setIntensity(0);
  disp.displayClear();
  disp.displayText("Test", PA_CENTER, 100, 0, PA_SCROLL_LEFT, PA_SCROLL_LEFT);
}

void loop() {
  if (disp.displayAnimate()) {
    disp.displayReset();
  }
}

Der Code beginnt mit dem Einbinden der benötigten Bibliotheken. Die SPI Bibliothek ist standardmäßig verfügbar, und du hast die MD_Parola und die MD_MAX72xx Bibliothek oben installiert.

#include "MD_Parola.h"
#include "MD_MAX72xx.h"
#include "SPI.h"

Als Nächstes müssen wir einige Konstanten definieren und das Display-Objekt ( disp ) erstellen. Wir müssen den Display-Typ, die Anzahl der Module und den Arduino-Pin, der mit dem Chip Select ( CS ) Signal verbunden ist, festlegen.

#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
#define MAX_DEVICES 4
#define CS_PIN 3  

MD_Parola disp = MD_Parola(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);

Wenn du ein Display mit mehr oder weniger Modulen hast, musst du MAX_DEVICES entsprechend anpassen. Beachte auch, dass wir hier Hardware-SPI verwenden. Für Software-SPI musst du die verwendeten Pins definieren. Sieh dir die MAX7219 LED dot matrix display Arduino tutorial für Details an.

In der setup Funktion bereitet der Code das Display vor, stellt die Helligkeit ein und löscht das Display. Im letzten Schritt definieren wir eine Animation, die den Text “ Test “ von links nach rechts mit einer Geschwindigkeit von 100 scrollt, also einer Verzögerung von 100 ms zwischen jedem Animationsschritt. Je niedriger der Wert, desto schneller läuft die Animation.

void setup() {
  disp.begin();
  disp.setIntensity(0);
  disp.displayClear();
  disp.displayText("Test", PA_CENTER, 100, 0, PA_SCROLL_LEFT, PA_SCROLL_LEFT);
}

Die Hauptfunktion loop führt die Animation kontinuierlich aus, indem sie displayAnimate() aufruft. Wenn diese Funktion true zurückgibt, ist die Animation abgeschlossen und das Display wird für eine neue Runde zurückgesetzt. Das bedeutet, der Lauftext startet erneut.

void loop() {
  if (disp.displayAnimate()) {
    disp.displayReset();
  }
}

Wenn du diesen Code hochlädst und ausführst, solltest du den Text „Test“ von links nach rechts über dein MAX7219-Display scrollen sehen:

Scrolling Test Output on MAX7219 LED Display
Scrolling-Testausgabe auf MAX7219 LED-Display

Wenn das funktioniert, Glückwunsch! Jetzt sind wir bereit für weitere Animationen.

Animationen verketten

Eine häufige Frage ist, wie man eine Kette oder Sequenz von Animationen erstellt, die nacheinander ausgeführt werden. Zum Beispiel möchten wir den Text „Left“ nach links scrollen lassen und danach den Text „Right“ nach rechts scrollen und den Zyklus wiederholen.

Chaining of two animations
Verkettung von zwei Animationen

Wir können jedoch die Animationsschleife nicht unterbrechen oder einfach zwei Schleifen hintereinander ausführen. Irgendwie müssen wir innerhalb der Schleife zwischen den Animationen wechseln.

void loop() {
  if (disp.displayAnimate()) {
    disp.displayReset();
  }
}

Der folgende Code zeigt dir, wie das geht:

#include "MD_Parola.h"
#include "MD_MAX72xx.h"
#include "SPI.h"

#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
#define MAX_DEVICES 4
#define CS_PIN 3  

MD_Parola disp = MD_Parola(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);

void switchAnimation(int animationId) {
  switch(animationId) {
    case 0:
      disp.displayText("Left", PA_CENTER, 100, 0, PA_SCROLL_LEFT, PA_SCROLL_LEFT);
      break;
    case 1:
      disp.displayText("Right", PA_CENTER, 100, 0, PA_SCROLL_RIGHT, PA_SCROLL_RIGHT);
      break;      
  }
}

void setup() {
  disp.begin();
  disp.setIntensity(0);
  disp.displayClear();
  switchAnimation(0);
}

void loop() {
  static int animationId = 0;
  if (disp.displayAnimate()) {
    disp.displayReset();
    switchAnimation(++animationId % 2);
  }
}

Schauen wir uns diesen Code genauer an. Die Include-Anweisungen, die Konstantendefinitionen und die Erstellung des MD_Parola-Displays sind wie zuvor.

switchAnimation Funktion

Neu ist die switchAnimation() Funktion. Sie nimmt die id einer Animation und stellt entweder die nach links oder nach rechts scrollende Animation ein. Beachte, dass switchAnimation() die Animation nicht ausführt. Sie teilt dem Display nur mit, welche Animation ausgeführt werden soll. Die eigentliche Ausführung der Animation übernimmt displayAnimate() in der Hauptschleife.

void switchAnimation(int animationId) {
  switch(animationId) {
    case 0:
      disp.displayText("Left", PA_CENTER, 100, 0, PA_SCROLL_LEFT, PA_SCROLL_LEFT);
      break;
    case 1:
      disp.displayText("Right", PA_CENTER, 100, 0, PA_SCROLL_RIGHT, PA_SCROLL_RIGHT);
      break;      
  }
}

setup Funktion

Die setup-Funktion bleibt weitgehend unverändert. Wie zuvor bereitet sie das Display vor, stellt die Helligkeit ein und löscht das Display. Im letzten Schritt rufen wir jedoch switchAnimation(0) auf, was die Animation mit id=0 setzt. In diesem Fall ist das die Animation, die den Text „Left“ scrollt.

loop Funktion

In der loop-Funktion definieren wir die Variable animationId , um die aktuelle Animation zu verfolgen. Sie ist static , das heißt, ihr Wert bleibt über die Schleifen hinweg erhalten.

void loop() {
  static int animationId = 0;
  if (disp.displayAnimate()) {
    disp.displayReset();
    switchAnimation(++animationId % 2);
  }
}

Innerhalb der Schleife führt der Aufruf von displayAnimate() die aktuelle Animation aus. Wenn eine Animation abgeschlossen ist (Text ist komplett durchgelaufen), gibt diese Funktion true zurück und wir gelangen in den Rumpf der if -Anweisung. Dort führen wir ein Reset durch und wechseln zur nächsten Animation.

Der Ausdruck ++animationId % 2 erhöht die Animations-ID bis sie 2 erreicht und setzt sie dann wieder auf 0. Wenn du mehr als 2 Animationen verketten möchtest, musst du die 2 durch die Anzahl deiner Animationen ersetzen. Außerdem müssen diese Animationen in der switchAnimation() Funktion definiert sein.

Hier ist ein Beispielcode für eine Sequenz von drei Animationen:

...

void switchAnimation(int animationId) {
  switch(animationId) {
    case 0:
      disp.displayText(...);
      break;
    case 1:
      disp.displayText(...);
      break;    
    case2:
      disp.displayText(...);
      break;     
  }
}

void setup() {
...
}

void loop() {
  static int animationId = 0;
  if (disp.displayAnimate()) {
    disp.displayReset();
    switchAnimation(++animationId % 3);
  }
}

Wenn du diesen Code hochlädst und ausführst, solltest du folgende Animation sehen:

Chained "Left" and "Right" animation
Verkettete „Left“ und „Right“ Animation

Im nächsten Abschnitt zeige ich dir, wie du Animationen per externem Input, z.B. Taster, umschalten kannst.

Animationen umschalten

Oft möchtest du Animationen per externem Input umschalten. Das kann ein Taster, eine Fernbedienung, ein Bewegungssensor oder Sensordaten wie Temperatur sein. Im folgenden Beispiel verwenden wir zwei Taster, um entweder die „Left“- oder die „Right“-Animation zu aktivieren.

Switching two animations
Umschalten von zwei Animationen

Fangen wir an, indem wir die beiden Taster zu unserer Schaltung hinzufügen.

Verdrahtung

Das Hinzufügen der beiden Taster ist einfach. Verbinde einfach einen Pin beider Taster mit Masse (GND) und den anderen Pin mit Pin 7 bzw. Pin 8 des Arduino, wie unten gezeigt:

Wiring for Control Buttons
Verdrahtung für Steuertaster

Achte beim Anschließen der Taster darauf, dass du die Pins verwendest, die tatsächlich geschaltet werden. Wir brauchen keine Pull-Up-Widerstände, da wir die internen Pull-Ups des Arduino nutzen.

Code zum Umschalten der Animation

Der Code zum Umschalten zwischen Animationen ist eine einfache Erweiterung des Codes für verkettete Animationen.

#include "MD_Parola.h"
#include "MD_MAX72xx.h"
#include "SPI.h"

#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
#define MAX_DEVICES 4
#define CS_PIN 3

#define BTN1_PIN 6
#define BTN2_PIN 7

MD_Parola disp = MD_Parola(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);

void switchAnimation(int animationId) {
  switch (animationId) {
    case 0:
      disp.displayText("Left", PA_CENTER, 100, 0, PA_SCROLL_LEFT, PA_SCROLL_LEFT);
      break;
    case 1:
      disp.displayText("Right", PA_CENTER, 100, 0, PA_SCROLL_RIGHT, PA_SCROLL_RIGHT);
      break;
  }
}

void setAnimation(int btn_pin, int animationId) {
  if (!digitalRead(btn_pin)) {
    disp.displayReset();
    disp.displayClear();
    switchAnimation(animationId);
    delay(200);
  }
}

void animate() {
  if (disp.displayAnimate()) {
    disp.displayReset();
  }
}

void setup() {
  disp.begin();
  disp.setIntensity(0);
  disp.displayClear();
  setAnimation(0);

  pinMode(BTN1_PIN, INPUT_PULLUP);
  pinMode(BTN2_PIN, INPUT_PULLUP);
}

void loop() {
  setAnimation(BTN1_PIN, 0);
  setAnimation(BTN2_PIN, 1);
  animate();
}

Der Teil, der die benötigten Bibliotheken einbindet, die Konstanten definiert und das MD_Parola-Display-Objekt erstellt, bleibt weitgehend unverändert. Der einzige Unterschied ist, dass wir die Pins festlegen, an denen die beiden Taster angeschlossen sind.

#define BTN1_PIN 6
#define BTN2_PIN 7

Auch die switchAnimation() Funktion ist wie zuvor. Aber jetzt gibt es eine neue Funktion setAnimation() :

void setAnimation(int btn_pin, int animationId) {
  if (!digitalRead(btn_pin)) {
    disp.displayReset();
    disp.displayClear();
    switchAnimation(animationId);
    delay(200);
  }
}

Sie nimmt einen Button-Pin und eine Animations-ID und prüft, ob der Taster am angegebenen Pin gedrückt ist, indem sie !digitalRead(btn_pin) aufruft. Beachte, dass die Logik invertiert ist, da wir den GPIO-Pin beim Drücken des Tasters auf Masse ziehen.

Wenn der Taster gedrückt ist, setzen und löschen wir das Display und wechseln zur Animation, die diesem Taster zugeordnet ist. Die 200 ms Verzögerung dient zum Entprellen des Tasters. Die Verzögerung ist hier unproblematisch, da wir gerade zu einer neuen Animation gewechselt haben und somit keine laufende Animation verzögern.

Als Nächstes verschieben wir den Code, der eine Animation ausführt, aus der Hauptschleife in eine neue Funktion animate() . Dadurch wird die loop-Funktion viel übersichtlicher.

void animate() {
  if (disp.displayAnimate()) {
    disp.displayReset();
  }
}

Die setup()-Funktion ist weitgehend gleich, aber wir setzen den Modus für die beiden Pins, an denen die Taster angeschlossen sind. Beachte, dass wir INPUT_PULLUP setzen, um den internen pull-up resistors zu nutzen.

void setup() {
  ...

  pinMode(BTN1_PIN, INPUT_PULLUP);
  pinMode(BTN2_PIN, INPUT_PULLUP);
}

Die loop Funktion ist jetzt schön einfach. Wir ordnen den Tastern per setAnimation() die Animations-IDs zu und rufen dann animate() auf, um die aktuell aktive Animation auszuführen. Der Code liest sich wie eine kleine Geschichte oder ein Rezept – so soll es sein.

void loop() {
  setAnimation(BTN1_PIN, 0);
  setAnimation(BTN2_PIN, 1);
  animate();
}

Lade den Code hoch und probiere es aus! Die kurzen Clips unten zeigen dir die beiden Animationen, die du sehen solltest, wenn du den linken (BTN1) oder rechten (BTN2) Taster drückst.

Animation for left button
Animation für linken Taster
Animation for right button
Animation für rechten Taster

Im nächsten Abschnitt ändern wir die Funktion der beiden Taster.

Animationen umschalten oder pausieren

Anstatt für jede Animation einen eigenen Taster zu verwenden, nutzen wir einen Taster (BTN1) zum Umschalten der Animation und den anderen Taster (BTN2), um die aktuell laufende Animation zu pausieren. Der folgende Code zeigt dir, wie das geht.

#include "MD_Parola.h"
#include "MD_MAX72xx.h"
#include "SPI.h"

#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
#define MAX_DEVICES 4
#define CS_PIN 3

#define BTN1_PIN 6
#define BTN2_PIN 7

int animationId = 0;

MD_Parola disp = MD_Parola(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);

void switchAnimation() {
  switch (animationId) {
    case 0:
      disp.displayText("Left", PA_CENTER, 100, 0, PA_SCROLL_LEFT, PA_SCROLL_LEFT);
      break;
    case 1:
      disp.displayText("Right", PA_CENTER, 100, 0, PA_SCROLL_RIGHT, PA_SCROLL_RIGHT);
      break;
  }
}

void toggleAnimation() {
  if (!digitalRead(BTN1_PIN)) {    
    disp.displayReset();
    disp.displayClear();
    animationId = (animationId + 1) % 2;
    switchAnimation();
    delay(200);
  }
}

void pauseAnimation() {
  static bool isPaused = false;
  if (!digitalRead(BTN2_PIN)) {
    isPaused = !isPaused;
    disp.displaySuspend(isPaused);
    delay(200);
  }
}

void animate() {
  if (disp.displayAnimate()) {
    disp.displayReset();
  }
}

void setup() {
  disp.begin();
  disp.setIntensity(0);
  disp.displayClear();
  switchAnimation();

  pinMode(BTN1_PIN, INPUT_PULLUP);
  pinMode(BTN2_PIN, INPUT_PULLUP);
}

void loop() {
  toggleAnimation();
  pauseAnimation();
  animate();
}

Es gibt ein paar Änderungen im Vergleich zum vorherigen Code. Erstens nimmt die switchAnimation() keinen animationId mehr als Argument, sondern verwendet eine globale Variable, um die aktuell laufende Animation zu verfolgen.

Zweitens gibt es zwei neue Funktionen: toggleAnimation() und pauseAnimation() . Schauen wir uns zuerst toggleAnimation() genauer an.

void toggleAnimation() {
  if (!digitalRead(BTN1_PIN)) {    
    disp.displayReset();
    disp.displayClear();
    animationId = (animationId + 1) % 2;
    switchAnimation();
    delay(200);
  }
}

Diese Funktion prüft, ob BTN1 gedrückt wurde. Falls ja, wird zuerst das Display zurückgesetzt und gelöscht. Dann wird die animationId auf die nächste Animation gesetzt und switchAnimation() aufgerufen, um die Animation für diese ID zu setzen. Am Ende gibt es wie üblich eine Verzögerung zum Entprellen des Tasters.

Die pauseAnimation() Funktion prüft, ob BTN2 gedrückt wurde und schaltet dann das isPaused Flag um. Je nach Wert dieses Flags wird die Display-Animation dann pausiert oder nicht.

void pauseAnimation() {
  static bool isPaused = false;
  if (!digitalRead(BTN2_PIN)) {
    isPaused = !isPaused;
    disp.displaySuspend(isPaused);
    delay(200);
  }
}

Die setup-Funktion ist im Wesentlichen unverändert und die loop-Funktion liest sich wieder schön wie eine kleine Geschichte:

void loop() {
  toggleAnimation();
  pauseAnimation();
  animate();
}

In jeder Iteration kümmern wir uns um das Umschalten oder Pausieren der Animation. Wie du siehst, ist es einfach, die Funktion der Taster zu ändern und alles übersichtlich zu halten.

In den nächsten beiden Abschnitten gehen wir noch einen Schritt weiter und fügen ein Potentiometer hinzu, um die Helligkeit oder Geschwindigkeit einer laufenden Animation einzustellen.

Animation-Helligkeit ändern

In diesem Teil schauen wir uns an, wie wir die Helligkeit des angezeigten Textes während der laufenden Animation anpassen können.

Verdrahtung

Fangen wir an, indem wir ein Potentiometer zu unserer Schaltung hinzufügen. Damit können wir die Helligkeit bzw. Intensität des Displays analog einstellen. Ich habe ein 10kΩ-Potentiometer verwendet, aber jeder Wert zwischen 1kΩ und 100kΩ funktioniert ebenfalls.

Wiring for Potentiometer
Verdrahtung für Potentiometer

Verbinde den mittleren Pin des Potentiometers (POT) mit dem analogen Eingang A0 des Arduino. Dann verbinde 5V und GND mit den beiden anderen Pins des Potentiometers. Die Reihenfolge ist eigentlich egal, beeinflusst aber, ob die Helligkeit beim Drehen nach links oder rechts steigt. Tausche einfach die 5V- und GND-Anschlüsse am Potentiometer, wenn du eine bestimmte Richtung bevorzugst, z.B. dass beim Drehen nach rechts die Helligkeit steigt.

Code zum Ändern der Helligkeit

Hier ist der Code von vorher mit der zusätzlichen Funktion, die Helligkeit des Displays je nach Stellung des Potentiometers einzustellen.

#include "MD_Parola.h"
#include "MD_MAX72xx.h"
#include "SPI.h"

#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
#define MAX_DEVICES 4
#define CS_PIN 3

#define BTN1_PIN 6
#define BTN2_PIN 7

int animationId = 0;

MD_Parola disp = MD_Parola(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);

void switchAnimation() {
  switch (animationId) {
    case 0:
      disp.displayText("Left", PA_CENTER, 100, 0, PA_SCROLL_LEFT, PA_SCROLL_LEFT);
      break;
    case 1:
      disp.displayText("Right", PA_CENTER, 100, 0, PA_SCROLL_RIGHT, PA_SCROLL_RIGHT);
      break;
  }
}

void toggleAnimation() {
  if (!digitalRead(BTN1_PIN)) {    
    disp.displayReset();
    disp.displayClear();
    animationId = (animationId + 1) % 2;
    switchAnimation();
    delay(200);
  }
}

void pauseAnimation() {
  static bool isPaused = false;
  if (!digitalRead(BTN2_PIN)) {
    isPaused = !isPaused;
    disp.displaySuspend(isPaused);
    delay(200);
  }
}

void adjustBrightness() {
  int val = analogRead(A0);
  int intensity = map(val, 0, 1023, 0, 15);
  disp.setIntensity(intensity);
}

void animate() {
  if (disp.displayAnimate()) {
    disp.displayReset();
  }
}

void setup() {
  disp.begin();
  disp.setIntensity(0);
  disp.displayClear();
  switchAnimation();

  pinMode(BTN1_PIN, INPUT_PULLUP);
  pinMode(BTN2_PIN, INPUT_PULLUP);
}

void loop() {
  toggleAnimation();
  pauseAnimation();
  adjustBrightness();
  animate();
}

Schauen wir uns die Änderungen im Code an. Wir brauchen nur eine neue Funktion, die den Potentiometerwert per analogRead() ausliest, ihn auf einen Intensitätswert zwischen 0 und 15 abbildet und dann die Display-Intensität/Helligkeit entsprechend setzt.

void adjustIntensity() {
  int val = analogRead(A0);
  int intensity = map(val, 0, 1023, 0, 15);
  disp.setIntensity(intensity);
}

Dann müssen wir adjustBrightness() in der Hauptschleife aufrufen, um die Helligkeit des Displays während der Animation anzupassen. Das war’s schon. Jetzt können wir Animationen umschalten und pausieren und die Helligkeit ändern.

Im nächsten Abschnitt machen wir etwas ganz Ähnliches, aber anstatt die Helligkeit des Displays zu ändern, passen wir die Geschwindigkeit der Animation an.

Animationsgeschwindigkeit ändern

Hier ist der komplette Code, um die Animationsgeschwindigkeit abhängig von der Potentiometerstellung einzustellen.

#include "MD_Parola.h"
#include "MD_MAX72xx.h"
#include "SPI.h"

#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
#define MAX_DEVICES 4
#define CS_PIN 3

#define BTN1_PIN 6
#define BTN2_PIN 7

int animationId = 0;

MD_Parola disp = MD_Parola(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);

void switchAnimation() {
  int speed = disp.getSpeed();
  switch (animationId) {
    case 0:
      disp.displayText("Left", PA_CENTER, speed, 0, PA_SCROLL_LEFT, PA_SCROLL_LEFT);
      break;
    case 1:
      disp.displayText("Right", PA_CENTER, speed, 0, PA_SCROLL_RIGHT, PA_SCROLL_RIGHT);
      break;
  }
}

void toggleAnimation() {
  if (!digitalRead(BTN1_PIN)) {
    disp.displayReset();
    disp.displayClear();
    animationId = (animationId + 1) % 2;
    switchAnimation();
    delay(200);
  }
}

void pauseAnimation() {
  static bool isPaused = false;
  if (!digitalRead(BTN2_PIN)) {
    isPaused = !isPaused;
    disp.displaySuspend(isPaused);
    delay(200);
  }
}

void adjustSpeed() {
  int val = analogRead(A0);
  int speed = map(val, 0, 1023, 10, 1000);
  disp.setSpeed(speed);
}

void animate() {
  if (disp.displayAnimate()) {
    disp.displayReset();
  }
}

void setup() {
  disp.begin();
  disp.setIntensity(0);
  disp.displayClear();
  switchAnimation();

  pinMode(BTN1_PIN, INPUT_PULLUP);
  pinMode(BTN2_PIN, INPUT_PULLUP);
}

void loop() {
  toggleAnimation();
  pauseAnimation();
  adjustSpeed();
  animate();
}

Dieser Code ist ein kleines bisschen komplexer, da wir eine neue Funktion hinzufügen und die switchAnimation() Funktion ändern müssen. In der switchAnimation() Funktion holen wir uns jetzt die aktuelle Geschwindigkeit des Displays und verwenden sie, wenn wir zu einer anderen Animation wechseln:

void switchAnimation() {
  int speed = disp.getSpeed();
  switch (animationId) {
    case 0:
      disp.displayText("Left", PA_CENTER, speed, 0, PA_SCROLL_LEFT, PA_SCROLL_LEFT);
      break;
    case 1:
      disp.displayText("Right", PA_CENTER, speed, 0, PA_SCROLL_RIGHT, PA_SCROLL_RIGHT);
      break;
  }
}

Und wir haben die neue Funktion adjustSpeed() , die der vorherigen adjustBrightness() Funktion sehr ähnlich ist. Die adjustSpeed() Funktion liest den Potentiometerwert per analogRead(), wandelt ihn in einen Geschwindigkeitswert zwischen 10 und 1000 um und stellt die Display-Geschwindigkeit entsprechend ein.

void adjustSpeed() {
  int val = analogRead(A0);
  int speed = map(val, 0, 1023, 10, 1000);
  disp.setSpeed(speed);
}

Animationsinhalt ändern

Zum Schluss möchte ich dir noch eine einfache Methode zeigen, um den Inhalt einer Animation zu aktualisieren. Das brauchst du, wenn du z.B. Sensordaten wie Temperatur oder Zeit anzeigen möchtest.

Anstatt einen bestimmten Sensor zu verwenden, nutzen wir im Beispiel unten das Potentiometer, um Sensordaten zu simulieren. Du kannst das Potentiometer aber problemlos durch jeden anderen Sensor ersetzen.

#include "MD_Parola.h"
#include "MD_MAX72xx.h"
#include "SPI.h"

#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
#define MAX_DEVICES 4
#define CS_PIN 3

MD_Parola disp = MD_Parola(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);

void updateAnimation() {
  static char buffer[32] = "";
  int value = analogRead(A0);
  sprintf(buffer, "value=%d", value);
  disp.displayText(buffer, PA_CENTER, 50, 0, PA_SCROLL_LEFT, PA_SCROLL_LEFT);
}

void animate() {
  if (disp.displayAnimate()) {
    disp.displayReset();
    updateAnimation();
  }
}

void setup() {
  disp.begin();
  disp.setIntensity(0);
  disp.displayClear();
  updateAnimation();
}

void loop() {
  animate();
}

Die Kernfunktionalität für das Aktualisieren der Animation steckt in der Funktion updateAnimation() . Sie liest den aktuellen Sensorwert, in diesem Beispiel den Potentiometerwert, formatiert ihn und schreibt ihn in einen String buffer per sprintf und aktualisiert schließlich den angezeigten Text mit displayText() . Wenn du den Code hochlädst und ausführst, solltest du folgende Animation sehen:

Animation update from potentiometer reading
Animation-Update durch Potentiometerwert

Beachte, dass die Größe des String-Buffers auf 32 Zeichen gesetzt ist. Wenn du längere Texte anzeigen möchtest, musst du die Puffergröße erhöhen.

Die updateAnimation() kann leicht angepasst werden, um andere Daten anzuzeigen. Angenommen, du schließt statt des Potentiometers einen DHT11-Temperatursensor an. Dann würdest du die Funktion wie folgt ändern:

float t = dht.readTemperature();
void updateAnimation() {
  static char buffer[32] = "";
  float temp = dht.readTemperature();
  sprintf(text, "Temp=%.2f", temp);
  disp.displayText(buffer, PA_CENTER, 50, 0, PA_SCROLL_LEFT, PA_SCROLL_LEFT);
}

Das setzt natürlich voraus, dass du den DHT11-Sensor angeschlossen und seine Funktion im Code eingerichtet hast. Schau dir das Tutorial zu How to use DHT11 and DHT22 Sensors with Arduino für mehr Informationen an.

Beachte, dass das Aktualisieren des Inhalts passiert, wenn eine neue Animation startet, aber nicht während eine Animation läuft. Zum Beispiel: Bei der Lauftext-Animation wird der Text nicht während des Scrollens aktualisiert, sondern erst, wenn ein neuer Durchlauf beginnt. Das siehst du in der animate() Funktion, wo wir updateAnimation() aufrufen, wenn die aktuelle Animation abgeschlossen ist.

void animate() {
  if (disp.displayAnimate()) {
    disp.displayReset();
    updateAnimation();
  }
}

Und das war’s! Mehrere hoffentlich nützliche Beispiele, wie du verschiedene Funktionen einer Animation mit digitalen oder analogen Eingaben steuern kannst, ohne die Animation zu unterbrechen. Wenn du Fragen hast, hinterlasse gerne einen Kommentar.

Fazit

Die Parola-Bibliothek ist super für Animationen, aber es kann etwas knifflig sein, zu verstehen, wie man Animationen steuert, ändert oder aktualisiert, ohne sie zu unterbrechen. Ich hoffe, dieses Tutorial hat dir alle Infos gegeben, um das in deinen Projekten umzusetzen.

Wir haben Taster und ein Potentiometer als Eingaben verwendet, um die Animationen zu steuern. Aber es ist genauso einfach, andere digitale oder analoge Eingaben zu nutzen. Du könntest z.B. die Animationen per IR-Fernbedienung steuern oder einen Fotowiderstand verwenden, um die Display-Helligkeit je nach Umgebungslicht anzupassen und aktuelle Wetterdaten aus dem Internet anzeigen.

Außerdem erlaubt dir die Parola-Bibliothek, ein Display in mehrere Zonen zu unterteilen, die unterschiedliche Animationen anzeigen können, z.B. eine Zone für eine Uhr und eine andere für Wetterdaten. Wenn du mehr darüber wissen möchtest, schau in das Coordinate Parola Zone Animations on MAX7219 Display Tutorial.

Obwohl wir in diesem Tutorial ein Arduino verwendet haben, funktioniert jeder andere gängige Mikrocontroller wie ESP32 oder ESP8266 genauso gut.

Und jetzt: Viel Spaß beim Animieren ; )