Osmimístný displej s 74HC595 bez práce v loop(). Obnovu číslic necháme na Timer1
Osmimístný sedmisegmentový modul s dvojicí 74HC595 neumí multiplexovat sám. Program musí rychle přepínat číslice, jinak displej bliká nebo zhasne. V běžné ukázce se o to stará
loop() a
delayMicroseconds(). Jde to ale i tak, že smyčka zůstane prázdná a celou obnovu si vezme přerušení od Timer1.
Na Arduino UNO a Nano s ATmega328P k tomu stačí jeden časovač. Druhý časovač na čtení číslic z paměti není potřeba. Buffer je v RAM a obsluha Timer1 si z něj bajt segmentů vezme sama.
Proč ne delay() v loop()
Modul nerozsvítí všech osm míst najednou. Zapne jednu číslici, nastaví její segmenty, za chvíli přepne na další a tak pořád dokola. Když je to dost rychlé, oko blikání nevidí.
Ukázkový program to dělá blokujícím čekáním, typicky
delayMicroseconds(1000) na každou číslici. Celý průchod tak zablokuje smyčku zhruba na 8 ms. Počítadlo to přežije. Jakmile v
loop() přibude měření, sériová linka nebo delší výpočet, displej se rozbliká.
Přerušení od časovače tenhle problém oddělí. Hlavní program může stát, displej se obnovuje dál.
Zapojení
- VCC modulu na 5 V
- GND na GND
- DIO / DATA na D7
- SCK / CLK na D6
- RCK / LATCH na D5
Piny nejsou povinné. V ukázce jsou na portu D schválně, protože obsluha přerušení zapisuje přímo do
PORTD a ne přes
digitalWrite().
Co se mění v programu
V
setup() zůstanou piny, vynulování bufferu a první
setNumber(0). Navíc se nastaví Timer1 do režimu CTC. Při taktu 16 MHz, předděličce 8 a
OCR1A = 1999 přijde přerušení přesně jednou za 1 ms.
loop() se vyprázdní:
V
ISR(TIMER1_COMPA_vect) se děje jen tohle:
- Oba registry se krátce zapíšou nulami, ať neprosvítá sousední číslice.
- Index 0…7 se posune o jednu pozici a přemapuje přes digitMap.
- Z displayBuffer se vezme bajt segmentů, složí se bajt výběru číslice a uplatní se SEGMENTS_ACTIVE_LOW a DIGITS_ACTIVE_LOW.
- Oba bajty se pošlou do 74HC595 v pořadí podle SEND_DIGIT_FIRST. Latch se zvedne až po nich.
- Číslice svítí do dalšího tiku, tedy asi 1 ms. To odpovídá původnímu delayMicroseconds(1000).
- Jednou za 1000 průchodů softwarový dělič zvedne počítadlo a zavolá setNumber(). Tím se plní paměť, ze které multiplex čte.
displayBuffer a počítadlo musí být
volatile.
setNumber() zapisuje celé číslo naráz. Kdyby se buffer měnil i mimo obsluhu, zápis patří mezi
noInterrupts() a
interrupts(), jinak se hodnota roztrhne uprostřed.
V obsluze nesmí být
shiftOut(),
digitalWrite(),
delayMicroseconds() ani
Serial. Jsou pomalé a v přerušení nemají co dělat. Timer0 se nesahej.
millis() dál běží, tahle smyčka ho jen nepotřebuje.
Jas a blikání
Perioda Timer1 je současně délka svitu jedné číslice. Menší
OCR1A znamená rychlejší obnovu a nižší jas. Větší perioda jas zvedne, ale od zhruba 2 ms na číslici už blikání uvidíš. Proud modulu pořád není zanedbatelný. 74HC595 není budič jako MAX7219, proud ani jas sám nehlídá.
Druhý časovač dává smysl až ve chvíli, kdy máš druhou nezávislou periodu, která nesmí rozhodit jas. Třeba měření ADC jednou za 100 ms. Na samotné přečtení číslic a jejich poslání ven je jeden Timer1 přesnější i jednodušší.