🔧 ProgrammierungGitHub Release: dependabot/dependabot-core v0.395.0 (07.09.2026)(07.09.2026 um 15:21 Uhr)
🔧 ProgrammierungGitHub Release: dependabot/dependabot-core v0.396.0 (14.09.2026)(14.09.2026 um 19:05 Uhr)
🔧 ProgrammierungGitHub Release: langwatch/scenario vpython/v1.4.0 (02.09.2026)(02.09.2026 um 04:47 Uhr)
🔧 ProgrammierungGitHub Release: langwatch/scenario vjavascript/v1.5.0 (02.09.2026)(02.09.2026 um 04:47 Uhr)
🔧 ProgrammierungGitHub Release: langwatch/scenario vjavascript/v1.6.0 (06.09.2026)(06.09.2026 um 17:45 Uhr)
🔧 Programmierungclawpatrol v0.5.10(13.09.2026 um 02:54 Uhr)
⚠️ Malware / Trojaner / VirenCAPE-parsers v0.1.69(13.09.2026 um 04:14 Uhr)
⚠️ Malware / Trojaner / Virendarknet-mcp-server(13.09.2026 um 04:55 Uhr)
🐧 Linux Tippsazurelinux v3.0.20260909-3.0(13.09.2026 um 09:51 Uhr)
🕵️ Sicherheitslückenatomicvulns(13.09.2026 um 10:36 Uhr)
🔧 ProgrammierungGitHub Release: dependabot/dependabot-core v0.395.0 (07.09.2026)(07.09.2026 um 15:21 Uhr)
🔧 ProgrammierungGitHub Release: dependabot/dependabot-core v0.396.0 (14.09.2026)(14.09.2026 um 19:05 Uhr)
🔧 ProgrammierungGitHub Release: langwatch/scenario vpython/v1.4.0 (02.09.2026)(02.09.2026 um 04:47 Uhr)
🔧 ProgrammierungGitHub Release: langwatch/scenario vjavascript/v1.5.0 (02.09.2026)(02.09.2026 um 04:47 Uhr)
🔧 ProgrammierungGitHub Release: langwatch/scenario vjavascript/v1.6.0 (06.09.2026)(06.09.2026 um 17:45 Uhr)
🔧 Programmierungclawpatrol v0.5.10(13.09.2026 um 02:54 Uhr)
⚠️ Malware / Trojaner / VirenCAPE-parsers v0.1.69(13.09.2026 um 04:14 Uhr)
⚠️ Malware / Trojaner / Virendarknet-mcp-server(13.09.2026 um 04:55 Uhr)
🐧 Linux Tippsazurelinux v3.0.20260909-3.0(13.09.2026 um 09:51 Uhr)
🕵️ Sicherheitslückenatomicvulns(13.09.2026 um 10:36 Uhr)

🔧 Programmierung 🕛 vor 4 Monaten 6 Min Lesezeit
0

Why Most 74HC595 Display Drivers Flicker (And How QUAD7SHIFT Avoids It Without Trying)

↗ Quelle (dev.to)
🗣️ Stimme:
📑 Inhaltsübersicht

A Chinese technical site cited QUAD7SHIFT as a flicker-free reference implementation. I didn't design it to solve flicker. I just built it correctly.









The Problem Nobody Talks About



Search for "74HC595 7-segment display Arduino" and you'll find dozens of tutorials. Most of them work — in the sense that the display shows numbers. But watch closely under fluorescent lighting, or point a camera at it, and you'll see it: a faint but persistent flicker, sometimes a ghost of the previous digit bleeding into the next.



This isn't a power supply issue. It isn't a loose connection. It's a structural problem in how most drivers handle the latch.









How the Naive Pattern Works



The typical approach looks something like this:




CODE
// Naive pattern — found in most tutorials
void showDigit(uint8_t segments, uint8_t digitSelect) {
digitalWrite(LATCH_PIN, LOW);
shiftOut(DATA_PIN, CLOCK_PIN, MSBFIRST, segments); // first transfer
shiftOut(DATA_PIN, CLOCK_PIN, MSBFIRST, digitSelect); // second transfer
digitalWrite(LATCH_PIN, HIGH);
}






Two separate shiftOut() calls, then a single latch pulse. Looks fine. The problem is what happens between those two calls.



When the first shiftOut() completes, the shift register holds the new segment data — but the latch hasn't fired yet. At that exact moment, the previous digit select is still active in the storage register. If anything delays the second shiftOut() — an interrupt, a timer ISR, a millisecond of jitter — the display briefly shows the new segment pattern on the wrong digit.



That's ghosting. And even without interrupts, the asymmetry in timing between two sequential software calls is enough to produce uneven brightness across digits.









The Timing Problem Visualized






CODE
Naive approach — two 74HC595 chips, sequential transfers:

Time →

LATCH: ___LOW_________________________HIGH___
SRCLK: ↑↑↑↑↑↑↑↑ ↑↑↑↑↑↑↑↑
DATA: [segments byte ] [digit select byte ]

HERE: shift reg 1 has new segments.
Storage reg still holds OLD digit select.
Any interrupt here = ghost on wrong digit.









CODE
QUAD7SHIFT — single 16-bit atomic transfer:

Time →

LATCH: ___LOW___________________HIGH___
SRCLK: ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
DATA: [segments byte | digit select byte]

Both bytes shift as one unit.
Latch fires once. No intermediate state.












What QUAD7SHIFT Does Instead



The hardware is two 74HC595s in cascade — one controls the segment lines (a–g, dp), the other controls which digit is active (digit select bits). The key is that both chips share a single latch line (RCLK).



The entire transfer is packed into a single uint16_t:




CODE
void QUAD7SHIFT::transferDigit(uint16_t result) {
writePin(LATCHPIN, LOW);

#if defined(__AVR_ATmega328P__) || (__AVR_ATmega168__)
SPI.beginTransaction(SPISettings(1000000, LSBFIRST, SPI_MODE0));
SPI.transfer16(result); // both bytes in one SPI transaction
SPI.endTransaction();
#endif

writePin(LATCHPIN, HIGH); // single latch pulse — both registers update simultaneously
}






SPI.transfer16() shifts all 16 bits in one continuous hardware transaction. The latch fires exactly once. There is no intermediate state where one register has new data and the other doesn't.



For ATtiny85, which lacks hardware SPI and uses the USI (Universal Serial Interface), the same principle applies — two usiTransferByte() calls back to back with the latch held LOW throughout:




CODE
void QUAD7SHIFT::transferDigit(uint16_t result) {
writePin(LATCHPIN, LOW);
usiTransferByte(reverseBits(result & 0xFF)); // segments
usiTransferByte(reverseBits((result >> 8) & 0xFF)); // digit select
writePin(LATCHPIN, HIGH);
}






The latch is LOW for the entire duration of both transfers. The storage registers don't see anything until the latch goes HIGH — at which point both update atomically.









Why This Works: The 74HC595 Latch Mechanism



The 74HC595 has two internal registers:





  • Shift register — receives serial data on each SRCLK rising edge


  • Storage register — holds the parallel output, only updates on RCLK rising edge



When LATCH (RCLK) is LOW, data shifting into the shift register has zero effect on the outputs. The outputs are frozen. You can shift as much data as you want — through one chip, through ten chips in cascade — and nothing changes on the output pins until you pulse the latch HIGH.



This is the mechanism. The naive pattern doesn't violate it, but it does use it sloppily — latching between two logical operations instead of after both are complete.



QUAD7SHIFT latches once, after all 16 bits are in place.









The Multiplexing Loop



Eliminating ghosting on each individual transfer is necessary but not sufficient. You also need a stable refresh cycle.



The naive approach typically calls the display function from loop(), which means refresh rate is coupled to whatever else loop() is doing. If you add a sensor read or a serial print, the display dims or flickers because some digits get fewer refresh cycles per second.



QUAD7SHIFT decouples refresh rate from loop() timing:




CODE
void QUAD7SHIFT::printNumber(uint16_t number, uint8_t decimalPointPosition) {
// ... digit extraction ...

unsigned long endtime = millis() + _refreshRate;
uint8_t i = 0;

while (millis() <= endtime) {
printDigit(digitsToPrint[i], i, i == decimalPointPosition);
i = (i + 1) % numberOfDigitsToDisplay;
}
}






Each call to print() runs the multiplexing loop for exactly _refreshRate milliseconds, cycling through all digits at a consistent rate regardless of what happened before or after. The display gets a guaranteed time slice.









See It Running













Comparison Summary






































Naive pattern QUAD7SHIFT
Latch pulses per digit update 1 (but between two transfers) 1 (after both transfers complete)
Intermediate state where ghost can appear Yes No
Refresh rate coupled to loop()
Yes No — fixed time slice
Works on ATtiny85 Depends on implementation Yes (USI, bit-reversal handled)
Hardware SPI on AVR Sometimes Yes (SPI.transfer16)








I Didn't Design This to Solve Flicker



Worth being explicit about this: I didn't build QUAD7SHIFT by identifying the ghost problem and engineering a solution. I built it by reading the 74HC595 datasheet, understanding that the latch is what separates "data in transit" from "data on outputs," and constructing the transfer accordingly.



The flicker never appeared because the design never created the conditions for it.



A Chinese technical site (CSDN, April 2026) independently analyzed cascaded 74HC595 display drivers and cited QUAD7SHIFT as a reference implementation for eliminating flicker — specifically noting its "dynamic scan algorithm." They found the pattern by looking for the problem. I found it by not creating the problem in the first place.



Both paths lead to the same place. But I think the second one is more instructive: correct hardware abstractions tend to be correct in ways you didn't plan for.









The Library



QUAD7SHIFT is available on GitHub and in the Arduino Library Manager.




  • GitHub: link on the GitHub page.






    Alex Rosito — self-taught electronics engineer. ATtiny85 · ESP32 · KiCad · C++

    Vollständiger Original-Bericht
    Ausführliche Details, Code-Beispiele & Hersteller-Stellungnahme auf dev.to.
    ↗ Original-Artikel auf dev.to lesen
Wie bewertest du diesen Beitrag?
1 Klick Feedback
Teilen mit Netzwerk & Team:

Community-Analysen & Experten-Meinungen 0

Verfasse deine eigene Analyse, teile Workarounds oder diskutiere diesen Vorfall im Blog.
Noch keine Community-Analyse verfasst. Markiere einen Textabschnitt oder klicke oben auf Eigene Analyse verfassen“!
Community Pulse: Relevanz-Einschätzung
1 Klick Experten-Votum
🔴 Akute Relevanz 0%
🟡 In Evaluierung 0%
🟢 Keine Auswirkung 0%
Spannende Innovation 0%
Verwandte Story-Cluster & Quellen (Vektor-KI)
Port 8095 Engine
10 Quellen
GitHub Release: dependabot/dependabot-core v0.393.0 (24.08.2026)
1 Quelle
clawpatrol v0.5.10
1 Quelle
CAPE-parsers v0.1.69
Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten Why Most 74HC595 Display Drivers Flicker (And How QUAD7SHIFT Avoids It Without Trying)

Thematisch verwandte Begriffe: Most, 74HC595, Display, Drivers · 6 Treffer

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...