[Multiplexing 4x7Segment] Komisches "Nachleuchten" - Verständnisfrage

Liebe Expertinnen und Experten,

ich möchte an einem Attiny4313 ein rotes 4x7Segment-Display (Common Cathode) betreiben. Da er insgesamt 18 Pins hat sollte das mit Multiplexing, ohne Shiftregister, ohne Transistoren und einigen Zusatzfunktionen gehen. Ich habe mir dieses Mal zum Ziel gesetzt, dass mein Code kurz und knapp und einigermaßen "schön" ist.

Nach vielem Herumprobieren habe ich auch etwas hinbekommen, was funktioniert - aber nicht so RICHTIG. Ich kann eine vierstellige Zahl ausgeben … aber mit einem "Nachleuchten" in den jeweils nächsten Digits. Wenn die Zahl 21 ist, dann leuchtet die zwei auch schwach bei der zweiten Ziffer mit. Sieht natürlich hässlich aus. Weg ist es, wenn ich einen Delay einbaue. Warum muss ich das machen? Woher kommt dieser Effekt.

Dies ist mein Code:

void setup() {
  /* Die folgenden beiden Zeile setzen alle nutzbaren
    Pins von Port "B" und "D" auf OUTPUT: */
  DDRD = B1111111;
  DDRB = B11111111;
}


void ausgabe(byte ausgabe) {

  switch (ausgabe) {
    /* Hier werden alle Ziffern beschrieben, indem die Pins des
      Ports "B" auf HIGH bzw. LOW gesetzt werden:
            PORTB = BHGFEDCBA  */
    case 0: PORTB = B11000000; break;
    case 1: PORTB = B11111001; break;
    case 2: PORTB = B10100100; break;
    case 3: PORTB = B10110000; break;
    case 4: PORTB = B10011001; break;
    case 5: PORTB = B10010010; break;
    case 6: PORTB = B10000010; break;
    case 7: PORTB = B11111000; break;
    case 8: PORTB = B10000000; break;
    case 9: PORTB = B10010000; break;
  }
}

void loop() {

  int zahl = 3456;
  byte einer, zehner, hunderter, tausender;

  einer     = zahl % 10;
  zehner    = (zahl / 10) % 10;
  hunderter = (zahl / 100) % 10;
  tausender = (zahl / 1000) % 10;

  byte zeit = 200; // WOZU IST DIESE ZEITVERZÖGERUNG NÖTIG?????

  // Welche Ziffer soll angeschaltet werden (1=an)?
  //PORTD = B___4321;
  PORTD   = B0000001;
  ausgabe(tausender);
  delayMicroseconds(zeit);
  PORTD   = B0000010;
  ausgabe(hunderter);
  delayMicroseconds(zeit);
  PORTD   = B0000100;
  ausgabe(zehner);
  delayMicroseconds(zeit);
  PORTD   = B0001000;
  ausgabe(einer);
  delayMicroseconds(zeit);
}

Danke für den Denkanstoß und einen schönen Abend,
kuahmelcher

P.S.: Konstruktive Verbessererungsvorschläge sind IMMER willkommen!

Du schaltest auf die nächste Stelle um, hast aber noch die Ziffer der vorhergehenden drin. Das ist das Nachleuchten.

Beim Wechsel:
alle Segmente aus
Stelle wechseln
neue Segmente ausgeben

Das delay kannst Du evtl. weglassen.

Gruß Tommy

ohne delay wird die Anzeige aber wahrscheinlich dunker ...

Deshalb schrieb ich evtl. Das müsste man probieren.

Gruß Tommy

Tommy56:
Du schaltest auf die nächste Stelle um, hast aber noch die Ziffer der vorhergehenden drin. Das ist das Nachleuchten.

Beim Wechsel:
alle Segmente aus
Stelle wechseln
neue Segmente ausgeben

Das delay kannst Du evtl. weglassen.

Gruß Tommy

Tja, also ich weiß nicht recht. Ich habe deinen Hinweis ausprobiert, indem ich in die Funktion ausgabe VOR den switch-case-Verzweigung ein

PORTB = B11111111;

eingebaut habe. Damit sollten sie ja aus sein. Aber es ist kein Unterschied zu sehen. Es ist egal, ob die Zeile drin ist oder nicht. Oder meinst du das "Ausschalten" anders?

Danke und Gruß, kuahmelcher

kuahmelcher:
PORTB = B11111111;

Damit sollten sie ja aus sein.

Falsch gedacht!!! Die Zeile gehört hinter jeden Funktionsaufruf im loop, z.B. so:

  PORTD   = B0000001;
  ausgabe(tausender);
  delayMicroseconds(zeit);
  PORTB = B11111111;

Kurioserweise wird die Darstellung tatsächlich merklich dunkler, wenn ich die delay-Zeile weglasse. Sogar wenn der Wert "0" ist, ist es heller. ::slight_smile:

Ehrlich gesagt verstehe ich weder das eine noch das andere (warum die Ausschaltung nicht in der ausgabe-funktion nutzt und warum die Heligkeit abnimmt, wenn eine delay-Zeile mit dem Wert "0" fehlt) … aber das Multiplexen funzt jetzt. Danke auf jeden Fall!

Falls es für jemand interessant ist - hier der jetzt funktionierende Code:

void setup() {
  /* Die folgenden beiden Zeile setzen alle nutzbaren
    Pins von Port "B" und "D" auf OUTPUT: */
  DDRD = B1111111;
  DDRB = B11111111;
}


void ausgabe(byte ausgabe) {

  switch (ausgabe) {
    /* Hier werden alle Ziffern beschrieben, indem die Pins des
      Ports "B" auf HIGH bzw. LOW gesetzt werden:
            PORTB = BHGFEDCBA  */
    case 0: PORTB = B11000000; break;
    case 1: PORTB = B11111001; break;
    case 2: PORTB = B10100100; break;
    case 3: PORTB = B10110000; break;
    case 4: PORTB = B10011001; break;
    case 5: PORTB = B10010010; break;
    case 6: PORTB = B10000010; break;
    case 7: PORTB = B11111000; break;
    case 8: PORTB = B10000000; break;
    case 9: PORTB = B10010000; break;
  }
  delayMicroseconds(1000);
  PORTB = B11111111;
}

void loop() {

  int zahl = millis()/1000;
  byte einer, zehner, hunderter, tausender;

  einer     = zahl % 10;
  zehner    = (zahl / 10) % 10;
  hunderter = (zahl / 100) % 10;
  tausender = (zahl / 1000) % 10;

  // Welche Ziffer soll angeschaltet werden (1=an)?
  //PORTD = B___4321;
  PORTD   = B0000001;
  ausgabe(tausender);
  PORTD   = B0000010;
  ausgabe(hunderter);
  PORTD   = B0000100;
  ausgabe(zehner);
  PORTD   = B0001000;
  ausgabe(einer);
}