Arduino a přerušení událostí. Použití přerušení v Arduino

Přišli jsme na iterační počitadlo hlavní smyčky a zjistili jsme, že není absolutně vhodný pro přesné odečty času - rychlost závěrky plave a je obtížné ji spočítat. Co dělat?

Je zřejmé, že je potřeba nějaký externí čítač, který by zaškrtl bez ohledu na operaci procesoru a procesor mohl kdykoli vidět, co se v něm děje. Nebo pro čítač generovat události přetečení nebo podtečení - zvedněte příznak nebo vygenerujte přerušení. A procento to přečte a zpracuje.

A existuje takový čítač, ani jeden - to jsou periferní časovače. V AVR jich může být několik, a to i s různou bitovou hloubkou. ATmega16 má tři, ATmega128 má čtyři. A v nové sérii MK AVR, možná ještě více, jsem nepoznal.

Časovač navíc nemusí být jen hloupý čítač, časovač je jedním z nejnáročnějších periferních zařízení (z hlediska alternativních funkcí).

Jaké časovače mohou udělat

  • Zaškrtněte jiná rychlostpočítání času
  • Počítání příchozích impulsů zvenčí (režim počítadla)
  • Klíště od vnějšího křemene při 32768 Hz
  • Generujte více typů signálu PWM
  • Vydat přerušení (půl tuctu různých událostí) a nastavit příznaky

Různé časovače mají různé funkce a různé velikosti bitů. Pro více informací viz katalogový list.

Zdroj časovače zaškrtnutí
Časovač / čítač (dále jej nazývám T / C) počítá buď hodinové impulsy z vestavěného generátoru hodin nebo z počítacího vstupu.

Podívejte se pozorně na pinout nohou ATmega16, vidíte tam nohy T1 a T0?

Jedná se tedy o počítací vstupy, časovač 0 a časovač 1. Při odpovídajícím nastavení bude T / C počítat buď úvodní (pokles z 0-1) nebo koncový (pokles 1-0) přední pulzy přicházející na tyto vstupy.

Hlavní věc je, že frekvence příchozích impulsů nepřesahuje taktovací frekvenci procesoru, jinak nebude mít čas na zpracování pulsů.

Kromě toho je T / C2 schopen pracovat v asynchronním režimu. To znamená, že T / C nezapočítává taktovací hodiny procesoru, nikoli vstupní impulsy do nohou, ale impulzy vlastního generátoru, poháněné samostatným krystalem. K tomu má T / C2 vstupy TOSC1 a TOSC2, na kterých můžete zavěsit křemenný rezonátor.

Proč je to nutné? Ano, alespoň uspořádat hodiny reálného času. Zavěsil jsem na ně 32768 Hz křemen a počítal čas - 128 přetečení nastane za sekundu (protože T / C2 je osmibit). Jeden přepad je tedy 1/128 sekundy. Kromě toho se časovač nezastaví při zpracování přerušení přetečení, ale také se počítá. Takže sledujte, jak dělat maličkosti!

Prescaler
Pokud časovač počítá impulsy z generátoru hodin nebo z jeho interního, mohou být stále předávány prescalerem.

To znamená, že i před vstupem do registru počítání bude pulzní frekvence rozdělena. Můžete jej rozdělit na 8, 32, 64, 128, 256, 1024. Pokud tedy zavěsíte hodinový křemen na T / C2 a předáte jej přes 128 předzesilovačů, váš časovač bude tikat rychlostí jednoho tiknutí za sekundu.

Výhodně! Je také vhodné použít předzesilovač, když potřebujete pouze získat velký interval, a jediným zdrojem klíšťat je generátor procesorových hodin na 8 MHz, počítání těchto megahertzů se nudí, ale pokud projdete předzesilovačem, do roku 1024 je vše mnohem více růžové.

Ale je tu jedna zvláštnost, faktem je, že pokud začneme T / C s nějakým brutálním prescalerem, například 1024, pak první klíště do registru počítání nemusí nutně dorazit po 1024 pulsech.

Závisí to na tom, v jakém stavu byl prescaler, ale co když se to započítalo téměř do 1024 v době, kdy jsme jej zapnuli? To znamená, že bude okamžitě zaškrtnuto. Prescaler pracuje po celou dobu, bez ohledu na to, zda je časovač zapnutý nebo ne.

Proto mohou být a by měla být resetována předvolba. Rovněž je nutné vzít v úvahu skutečnost, že předzesilovač je stejný pro všechny čítače, proto je při resetování nutné vzít v úvahu skutečnost, že druhý časovač ztratí svou expozici až do příštího zaškrtnutí, a může být ztracen přesně tak.

Například první časovač běží na pin 1:64 a druhý na pin 1: 1024 prescaleru. Druhý z nich dosáhl téměř 1024 v předzesilovači a nyní by měla být zaškrtávací značka časovače, ale pak jste předzesilovač spustili a spustili první časovač přesně od nuly. Co se bude dít? Správně, druhý dělič se okamžitě sklopí na 0 (prescaler je stejný, má pouze jeden registr) a druhý časovač bude muset čekat dalších 1024 hodinových cyklů, aby získal požadovaný impuls!

A pokud resetujete prescaler v cyklu, ve prospěch prvního časovače, častěji než jednou za každých 1024 hodinových cyklů, pak druhý časovač nikdy nezatrhne, a budete trápit hlavu na stole, snažíte se pochopit, proč pro vás druhý časovač nepracuje. by měl.

Pro resetování předvoleb stačí zapsat bit PSR10 do registru SFIOR. Bit PSR10 bude automaticky vymazán v příštím hodinovém cyklu.

Počítání registru
Celý výsledek trápení popsaného výše se hromadí v registru počítání TCNTx, kde místo x je číslo časovače. může to být buď osmibitová nebo šestnáctibitová, v tom případě se skládá ze dvou registrů TCNTxH a TCNTxL - vysoké a nízké bajty.

A je tu háček, pokud potřebujete vložit číslo do osmibitového registru, pak neexistují žádné problémy OUT TCNT0, Rx a žádné hřebíky, pak budete muset zvrátit dvoubajtové.

A věc je, že časovač se počítá bez ohledu na procesor, takže můžeme dát první bajt, začne počítat, pak druhý, a přepočet začne brát v úvahu druhý bajt.

Cítíte se dál? Tady! Časovač je přesné zařízení, takže je třeba načíst jeho počítací registry současně! Ale jak? A inženýři z Atmel vyřešili problém jednoduše:
Zápis do horního registru (TCNTxH) se provádí nejprve v registru TEMP. Tento registr je čistě servisní a není pro nás v žádném případě k dispozici.

Výsledkem je, že zapíšeme vysoký byte do registru TEMP (pro nás je to jeden křen TCNTxH) a potom zapíšeme nízký byte. V tomto okamžiku je ve skutečném TCNTxH vložena dříve zaznamenaná hodnota. To znamená, že dva bajty, vysoký a nízký, jsou psány současně! Nemůžete změnit objednávku! Jediná možnost

Vypadá to takto:

CLI; Zakázání přerušení bez selhání! OUT TCNT1H, R16; Vysoký bajt byl na začátku zapsán do TEMP OUT TCNT1L, R17; A teď jsem se zaregistroval na senior i junior! SEI; Povolit přerušení

Proč zakázat přerušení? Ano, takže po napsání prvního bajtu se program náhodně nespěchá, nepřerušuje a pak někdo nevyjel náš časovač. Pak ve svých registrech nebude to, co jsme sem poslali (nebo v přerušení), ale co sakra. Tak se pokuste zachytit takovou chybu později! Ale ona se může dostat ven v nejnepříznivější chvíli, ale chytíte peklo, protože přerušení je téměř náhodná proměnná. Takové momenty tedy musí být okamžitě přerušeny.

Vše je čteno stejným způsobem, pouze v obráceném pořadí. Nejprve nejmenší bajt (zatímco nejvýznamnější je tlačen do TEMP), pak nejvýznamnější. To zajišťuje, že vezmeme v úvahu přesný bajt, na kterém byl tento moment v registru počítání, a ne ten, který jsme našli, když jsme jej vybrali byte byte byte z registru počítání.

Kontrolní registry
Nebudu popisovat všechny funkce časovačů, jinak se ukáže, že to bude nesnesitelné pojednání, raději bych vám řekl o hlavním - počítání a všechny druhy PWM a dalších generátorů budou v jiném článku. Takže buďte trpěliví nebo nahlodejte datový list, je to také užitečné.

Hlavní registr je tedy TCCRx
Pro T / C0 a T / C2 je to TCCR0, respektive TCCR2, a pro T / C1 je TCCR1B

Zatím nás zajímají pouze první tři bity tohoto registru:
CSx2 .. CSx0, číslo časovače je nahrazeno x.
Jsou zodpovědní za nastavení předzesilovače a zdroje hodin.

Různé časovače mají trochu odlišně, takže popíšu bity CS02..CS00 pouze pro časovač 0

  • 000 - časovač zastaven
  • 001 - prescaler je 1, to znamená, že je vypnutý. časovač počítá taktovací impulsy
  • 010 - prescaler je 8, hodinová frekvence je dělena 8
  • 011 - prescaler je 64, taktovací frekvence je dělena 64
  • 100 - Prescaler je 256, rychlost hodin je dělitelná 256
  • 101 - prescaler je 1024, hodinová rychlost je dělitelná 1024
  • 110 - hodinové impulsy přicházejí z T0 ramene při přechodu z 1 na 0
  • 111 - hodinové impulsy přicházejí z T0 ramene při přechodu z 0 na 1

Přerušení
Každá hardwarová událost má přerušení a časovač není výjimkou. Jakmile dojde k přetečení nebo jiné zvláštní události, objeví se přerušení.

Registry TIMSK, TIFR jsou odpovědné za přerušení časovačů. A chladnější AVR, jako je ATMega128, mají také ETIFR a ETIMSK - druh pokračování, protože tam bude více časovačů.

TIMSK je registr masky. To znamená, že bity v něm umožňují přerušení místně. Pokud je bit nastaven, je povoleno konkrétní přerušení. Pokud je bit nula, pak je toto přerušení pokryto umyvadlem. Ve výchozím nastavení jsou všechny bity nulové.

V současné době nás zajímá pouze přerušení přetečení. Bity jsou za ně zodpovědné

  • TOIE0 - Povoleno přerušení přetečení časovače 0
  • TOIE1 - Povoleno přerušení přetečení časovače 1
  • TOIE2 - Povoleno přerušení přetečení časovače 2

O zbývajících funkcích a časových přerušeních si promluvíme později, když rozložíme PWM.

Registr TIFR je přímo registr příznaků. Když se spustí nějaký druh přerušení, objeví se příznak, že máme přerušení. Tento program je odstraněn hardwarem, když program opustí vektor. Pokud jsou přerušení zakázána, pak příznak zůstane zapnutý, dokud nejsou povolena přerušení a program neodejde k přerušení.

Aby se tomu zabránilo, může být příznak vymazán ručně. Chcete-li to provést, napište 1 do registru TIFR!

Nyní podvádíme
Pojďme znovu program pro práci s časovačem. Představme si časovač programu. Hlavový orgán tak zůstane, nechte ho klíště. Přidáme druhou proměnnou, také čtyři bajty:

ORG $ 010 RETI; (TIMER1 OVF) Časovač / Počítadlo1 Přetečení. ORG $ 012 RJMP Časovač0_OV; (TIMER0 OVF) Přetečení časovače / čítače0. ORG $ 014 RETI; (SPI, STC) Sériový přenos dokončen

Do části Přerušení přidejte popisovač přerušení přetečení časovače 0. Protože naše tikající makro aktivně pracuje s registry a příznaky kazí, musíme nejprve uložit vše do zásobníku:

Mimochodem, vytvořme další makro, které posune registr příznaků SREG do zásobníku a druhé odtud vytáhne odtud.

1 2 3 4 5 6 7 8 9 10 11 12 .MACRO PUSHF PUSH R16 IN R16, SREG PUSH R16 .ENDM .MACRO POPF POP R16 OUT SREG, R16 POP R16 .ENDM

MACRO PUSHF PUSH R16 IN R16, SREG PUSH R16 .ENDM .MACRO POPF POP R16 OUT SREG, R16 POP R16 .ENDM

Jako vedlejší účinek si stále zachovává R16, pamatujte na to :)

1 2 3 4 5 6 7 8 9 10 11 12 13 Timer0_OV: PUSHF PUSH R17 PUSH R18 PUSH R19 INCM TCNT POP R19 POP R18 POP R17 POPF RETI

Timer0_OV: PUSHF PUSH R17 PUSH R18 PUSH R19 INCM TCNT POP R19 POP R18 POP R17 POPF RETI

Nyní inicializace časovače. Přidejte jej do sekce Internal Hardware Init.

; Internal Hardware Init \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d SETB DDRD, 4, R16; DDRD.4 \u003d 1 SETB DDRD, 5, R16; DDRD.5 \u003d 1 SETB DDRD, 7, R16; DDRD.7 \u003d 1 SETB PORTD, 6, R16; PD6 pin pro vstup s pull-up CLRB DDRD, 6, R16; Pro přečtení tlačítka SETB TIMSK, TOIE0, R16; Povolit přerušení časovače OUTI TCCR0,1<

Zbývá přepsat náš srovnávací blok a přepočítat číslo. Nyní je vše jednoduché, jeden zatrhněte jeden pruh. Bez problémů s různými délkami kódu. Po dobu jedné sekundy při 8MHz musí být provedeno 8 milionů ticků. V hexech je to 7A 12 00, vezmeme-li v úvahu, že nejméně významný bajt je TCNT0, pak 7A 12 zůstává na našem počítadle a existují další dva vyšší bajty 00 00, které nelze zkontrolovat. Není třeba maskovat, časovač přesto resetujeme.

Jediným problémem je nízký bajt, ten v časovači. Zaškrtne každé zaškrtnutí a bude téměř nemožné zkontrolovat shodu. Protože nejmenší neshoda a srovnávací podmínka vypadnou v NoMatch a hádej, aby se kontrola její hodnoty shodovala s tímto konkrétním opatřením ... Je snazší vytáhnout jehlu z kupce sena při prvním pokusu náhodně.

I v tomto případě je přesnost omezená - musíte mít čas na kontrolu hodnoty, než se dostane mimo rozsah. V tomto případě bude rozsah pro jednoduchost 255 - hodnota nejméně významného bytu v časovači.

Pak je náš druhý vybaven přesností 8 000 000 plus mínus 256 hodinových cyklů. Chyba není velká, pouze 0,003%.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 ; Main \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d Main: SBIS PIND, 6; Pokud je tlačítko stisknuto - přechod RJMP BT_Push SETB PORTD, 5; Rozsvítí se LED2 CLRB PORTD, 4; Zhasněte LED1 Další: LDS R16, TCNT; Načíst čísla do registrů LDS R17, TCNT + 1 CPI R16,0x12; Pojďme porovnat bajt. První byte BRCS NoMatch; Pokud je méně, pak to nezasáhlo. CPI R17,0 x 7A; Druhý bajt BRCS NoMatch; Pokud je méně, pak to nezasáhlo. ; Pokud se shoduje, uděláme akci Match: INVB PORTD, 7, R16, R17; Invertovaná LED3; Nyní musíte resetovat čítač, jinak během stejné iterace hlavní smyčky; dostaneme se sem více než jednou - časovač nebude mít čas zasáhnout 255 hodnot ,; takže číslo v prvních dvou bajtech čítače se změní a podmínka je spuštěna. ; Samozřejmě to můžete obejít dalším příznakem, ale je snazší vynulovat čítač :) CLR R16; Potřebujeme nulové CLI; Přístup k vícebajtové proměnné; současně z přerušení a pozadí; potřebuje atomový přístup. Zakázat přerušení OUTU TCNT0, R16; Registr nulových až časových počítadel STS TCNT, R16; Nula v prvním byte čítače v RAM STS TCNT + 1, R16; Nula v druhém byte čítače v RAM STS TCNT + 2, R16; Nula ve třetím bajtu čítače v RAM STS TCNT + 3, R16; Nula v prvním byte čítače v RAM SEI; Znovu povolíme přerušení. ; Neodpovídá - nedělej to :) NoMatch: NOP INCM CCNT; Počitadlo cyklů je tikající; Nech to být, i když není použito. JMP Main BT_Push: SETB PORTD, 4; Rozsvítí se LED1 CLRB PORTD, 5; Zhasněte LED2 RJMP Další; Hlavní konec \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d \u003d\u003d\u003d\u003d\u003d

; Hlavní \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d Main: SBIS PIND, 6; Pokud je tlačítko stisknuto - přechod RJMP BT_Push SETB PORTD, 5; Rozsvítí se LED2 CLRB PORTD, 4; Zhasněte LED1 Další: LDS R16, TCNT; Načíst čísla do registrů LDS R17, TCNT + 1 CPI R16,0x12; Pojďme porovnat bajt. První byte BRCS NoMatch; Pokud je méně, pak to nezasáhlo. CPI R17,0 x 7A; Druhý bajt BRCS NoMatch; Pokud je méně, pak to nezasáhlo. ; Pokud se shoduje, uděláme akci Match: INVB PORTD, 7, R16, R17; Invertovaná LED3; Nyní musíte resetovat čítač, jinak během stejné iterace hlavní smyčky; dostaneme se sem více než jednou - časovač nebude mít čas zasáhnout 255 hodnot ,; takže číslo v prvních dvou bajtech čítače se změní a podmínka je spuštěna. ; Samozřejmě to můžete obejít dalším příznakem, ale je snazší vynulovat čítač :) CLR R16; Potřebujeme nulové CLI; Přístup k vícebajtové proměnné; současně z přerušení a pozadí; potřebuje atomový přístup. Zakázat přerušení OUTU TCNT0, R16; Registr nulových až časových počítadel STS TCNT, R16; Nula v prvním byte čítače v RAM STS TCNT + 1, R16; Nula v druhém byte čítače v RAM STS TCNT + 2, R16; Nula ve třetím bajtu čítače v RAM STS TCNT + 3, R16; Nula v prvním byte čítače v RAM SEI; Znovu povolíme přerušení. ; Neodpovídá - nedělej to :) NoMatch: NOP INCM CCNT; Počitadlo cyklů je tikající; Nech to být, i když není použito. JMP Main BT_Push: SETB PORTD, 4; Rozsvítí se LED1 CLRB PORTD, 5; Vypněte LED2 RJMP Další; Hlavní konec \u003d\u003d\u003d\u003d\u003d

Takto vypadá práce.

A pokud je nutné blikat druhou diodu s jinou periodou, můžeme bezpečně vložit do programu ještě jednu proměnnou a v obslužném programu pro přerušení časovače najednou zvýšit dvě proměnné. Kontrola je zase v hlavní smyčce programu.

Proces ověřování můžete trochu optimalizovat. Zrychlete to.

Musíte pouze vytvořit účet, aby nedošlo ke zvýšení, ale ke snížení. Ty. načíst číslo do proměnné a začít jej snižovat v přerušení. A tam, v psovodovi, to zkontrolujeme na nulu. Pokud je nula, zaškrtněte políčko v paměti. Náš program na pozadí zachytí tuto vlajku a zahájí akci a současně resetuje rychlost závěrky.

Co když potřebujete být přesnější? Existuje pouze jedna možnost - použít zpracování událostí přímo v obslužném programu přerušení a vždy upravit hodnotu v TCNT: TCNT0 tak, aby k přerušení došlo přesně ve správný čas.

Časovač1

Tato knihovna je sada funkcí pro konfiguraci hardwarového 16bitového časovače 1 v ATMega168 / 328. V mikrokontroléru jsou k dispozici 3 hardwarové časovače, které lze různými způsoby nakonfigurovat tak, aby získaly různé funkce. Počáteční vývoj této knihovny byl vyvolán potřebou rychle a snadno nastavit periodu nebo frekvenci signálu PWM, ale později se rozšířil o zpracování přerušení časovače přetečení a další funkce. Lze jej snadno rozšířit nebo přenést do práce s jinými časovači.

Přesnost časovače závisí na rychlosti hodin procesoru. Frekvence hodin Timer1 je určena nastavením předzesilovače. Tento dělitel lze nastavit na 1, 8, 64, 256 nebo 1024.

  • Maximální doba \u003d (Dělič / Frekvence) × 2 17
  • Trvání jednoho vzorku \u003d (Dělič / Frekvence)

Chcete-li nainstalovat, jednoduše rozbalte a umístěte soubory do adresáře Arduino / hardware / knihovny / Timer1 /.

Timer3

Knihovnu Timer1 lze použít na Arduino Mega, ale nepodporuje všechny tři výstupní piny OCR1A, OCR1B a OCR1C. Podporovány jsou pouze A a B. OCR1A je připojen na pin 11 na Mega a OCR1B je připojen na pin 12. Pomocí jednoho ze tří hovorů, které určují pin, 1 nastaví pin 11 na Mega a 2 nastaví pin 12. Knihovna Timer3 byla testována pouze na Mega.

Knihovnu pro Timer3 najdete zde ()

Chcete-li nainstalovat, jednoduše rozbalte a umístěte soubory do adresáře Arduino / hardware / knihovny / Timer3 /.

Metody knihovny TimerOne a TimerThree

Nastavení

inicializace prázdnoty (dlouhé mikrosekundy \u003d 1000000); Před použitím jakékoli jiné metody knihovny musíte tuto metodu nejprve zavolat. V případě potřeby můžete nastavit periodu časovače (v mikrosekundách), ve výchozím nastavení je periody nastavena na 1 sekundu. Všimněte si, že tím dojde k přerušení analogového zápisu na digitálních pinech 9 a 10 na Arduinu. void setPeriod (dlouhé mikrosekundy); Nastaví období v mikrosekundách. Minimální perioda a maximální frekvence podporované touto knihovnou jsou 1 mikrosekunda 1 MHz. Maximální doba je 8388480 mikrosekund nebo přibližně 8,3 sekund. Všimněte si, že nastavení periody změní frekvenci připojeného přerušení a frekvenci a pracovní cyklus na obou výstupech PWM.

Kontrola startu

neplatný start (); Spouští časovač od nového období. void stop (); Zastaví časovač. void restart (); Restartuje časovač, resetuje počítadlo a začíná novou periodu.

Řízení výstupu PWM

void pwm (char pin, int duty, dlouhé mikrosekundy \u003d -1); Generuje signál PWM na určeném kolíku. Výstupní piny časovače 1 jsou PORTB piny 1 a 2, takže musíte vybrat jeden z nich, všechno ostatní bude ignorováno. Na Arduinu jsou to digitální kolíky 9 a 10, tyto aliasy také fungují. Výstupní piny Timer3 jsou PORTE piny, odpovídající piny 2, 3 a 5 na Arduino Mega. Pracovní cyklus je specifikován jako 10bitová hodnota v rozsahu od 0 do 1023 (0 odpovídá konstantní logické nule na výstupu a 1023 - konstantní logická). Všimněte si, že periodu lze také nastavit v této funkci, je-li to nutné, přidáním hodnoty v mikrosekundách jako posledního argumentu. void setPwmDuty (char pin, int duty); Rychlý způsob, jak vyladit pracovní cyklus signálu PWM, pokud jste jej již vylepšili voláním metody pwm () dříve. Tato metoda se vyhýbá zbytečným krokům pro povolení režimu PWM pro výstup, změnu stavu registru, který řídí směr pohybu dat, kontrolu volitelné hodnoty periody a dalších akcí, které jsou vyžadovány při volání pwm (). void disablePwm (char pin); Vypne PWM na určeném kolíku, po kterém můžete použít tento kolík pro něco jiného.

Přerušení

void attachInterrupt (void (* isr) (), dlouhé mikrosekundy \u003d -1); Vyvolá funkci v intervalu zadaném v mikrosekundách. Při pokusu o spuštění příliš složitého obslužného programu přerušení při příliš vysoké hodinové frekvenci buďte opatrní, protože CPU se nikdy nemusí vrátit do hlavní programové smyčky a váš program bude „uzamčen“. Všimněte si, že periodu lze také nastavit v této funkci, je-li to nutné, přidáním hodnoty v mikrosekundách jako posledního argumentu. void detachInterrupt (); Zakáže připojené přerušení.

Odpočinek

nepodepsané dlouhé čtení (); Čte čas od posledního přetečení v mikrosekundách.

Příklad 1

V příkladu PWM je na kolík 9 aplikován signál s pracovním cyklem 50% a připojený obslužný program přerušení přepíná stav digitálního kolíku 10 každou půl sekundu.

#include "TimerOne.h" neplatné nastavení () (pinMode (10, OUTPUT); Timer1.initialize (500000); // inicializuje časovač1 a nastaví periodu na 1/2 sekundy. Timer1.pwm (9, 512); //) nastavit PWM signál na pin 9, pracovní cyklus 50% Timer1.attachInterrupt (zpětné volání); // připojit callback () jako handler pro přerušení přetečení časovače) neplatné zpětné volání () (digitalWrite (10, digitalRead (10) ^ 1);)) void loop () (// váš program ...)

Upravené knihovny Paul Stoffregen

K dispozici jsou také samostatně udržované a upgradovatelné kopie TimerOne a TimerThree, které podporují více hardwaru a jsou optimalizovány pro efektivnější kód.

PlatitPWM piny TimerOnePWM piny TimerThree
Teensy 3.13, 4 25, 32
Teensy 3.03, 4
Teensy 2.04, 14, 15 9
Teensy ++ 2.025, 26, 27 14, 15, 16
Arduino Uno9, 10
Arduino Leonardo9, 10, 11 5
Arduino Mega11, 12, 13 2, 3, 5
Zapojení-S4, 5
Sanguino12, 13

Metody modifikovaných knihoven jsou podobné těm, které byly popsány výše, ale byla přidána jedna další metoda pro řízení začátku časovače:

Prázdný životopis (); Obnoví zastavený časovač. Nové období nezačíná.

Příklad 2

#zahrnout // Tento příklad používá přerušení časovače pro // blikání LED a také ukazuje, jak // sdílet proměnnou mezi obsluhou přerušení a // hlavním programem. const int led \u003d LED_BUILTIN; // výstup s nastavením LED void (void) (pinMode (led, OUTPUT); Timer1.initialize (150000); Timer1.attachInterrupt (blikající LED); // blikající LED každých 0,15 s. Serial.begin (9600);) //) Obsluha přerušení blikne LED a // uloží počet bliknutí. int ledState \u003d LOW; volatile unsigned long blinkCount \u003d 0; // použití volatile pro sdílené proměnné void blinkLED (void) (if (ledState \u003d\u003d LOW) (ledState \u003d HIGH; blinkCount \u003d blinkCount + 1; // zvyšte hodnotu, když LED svítí) jinak (ledState \u003d LOW;) digitalWrite (led, ledState);) // Hlavní program vytiskne blikání čítače // do smyčky Arduino Serial Monitor void loop (void) (nepodepsané dlouhé blinkCopy; // uchovává kopii blinkCount //, aby bylo možné číst proměnnou zapsanou v obslužném programu // přerušení, musíme dočasně zakažte přerušení, abyste se ujistili, že se během jeho čtení nezmění // // Chcete-li minimalizovat čas, kdy jsou přerušení zakázána, // jednoduše rychle zkopírujte a poté použijte kopii, což umožní // přerušení, aby pokračovala.noInterrupts () ; blinkCopy \u003d blinkCount; přerušení (); Serial.print ("blinkCount \u003d"); Serial.println (blinkCopy); zpoždění (100);)

Přerušit kontextové problémy

Pro komunikaci mezi kódem obsluhy přerušení a zbytkem vašeho programu musí být provedeny další kroky.

Ve skutečnosti je časovač mikrokontroléru digitální čítač, pouze „fantazie“. Na vstup čítače se přivádí hodinový signál a čítač zvyšuje jeho hodnotu o kapky. Pokud dojde k událostem - přetečení čítače nebo shoda jeho hodnoty se specifikovanou - vygeneruje se požadavek na přerušení.

Pojďme se podívat, jak používat časovač T0 v normálním režimu. V tomto režimu se časovač počítá od některé počáteční hodnoty počítacího registru na maximum možné (až 255 nebo 0xFF). Když se časovač T0 počítá na maximum, pak v dalším cyklu časovače dojde k přetečení registru počítání TCNT0 - je vymazán a je nastaven příznak TOV0. Pokud jsou v programu povoleny přerušení globálně (I příznak registru SREG) a přerušení časovače T0 přetečením (příznak TOIE0 registru TIMSK), mikrokontrolér zavolá odpovídající obslužnou rutinu. Pokud se hodnota počítacího registru shoduje s porovnávacím registrem OCR0, bude nastaven příznak OCF0 a pokud je povoleno přerušení události zápasu, bude spuštěn jeho obslužný program.

Časovač T0 v normálním režimu

Uvažujme o praktickém úkolu - musíme každých 20 ms dotazovat tlačítkem. Frekvence mikrokontroléru 8 MHz, mikrokontrolér ATmega16.

První věcí, kterou je třeba udělat, je rozhodnout se o výběru koeficientu přednastavení časovače a vypočítat počáteční hodnotu pro registrační registr TCNT0.

Časovač T0 může být taktován z interního hodinového signálu mikrokontroléru nebo z externího, který je přiváděn na kolík T0. Při práci s interním hodinovým signálem si může uživatel zvolit faktory dělení kmitočtu tohoto signálu. Časovač T0 má pět možných voleb pro faktor předzesilovače - 1, 8, 64, 256, 1024.

K vyřešení problému argumentuji následovně. Pokud by měl jeden časovač časovače T0 dobu 1 ms, vyhovovalo by mi to. 20 hodinových cyklů dává 20 ms. Jaký poměr přednastavovače časovače vám umožní přiblížit se k hodinové periodě přibližně 1 ms? Můžete počítat.

Frekvence mikrokontroléru Fcpu \u003d 8000000 Hz
Časový interval mikrokontroléru Tcpu \u003d 1 / Fcpu
Perioda hodinového signálu časovače T0 se rovná Tt0 \u003d (1 / Fcpu) / k \u003d k / Fcpu

Při k \u003d 1024 bude doba taktovací frekvence časovače T0 rovná Tt0 \u003d 1024/8000000 \u003d 0,128 ms

Toto je maximální časová perioda časovače, kterou můžeme za našich podmínek získat (Fcpu \u003d 8 MHz). Při nižších koeficientech bude toto období ještě kratší.

Dobře, nechte jeden hodinový cyklus časovače 0,128 ms, existuje dostatečná kapacita registru počítání pro počítání tohoto časového intervalu a kolik hodinových cyklů to bude trvat? Požadovaný časový interval (20 ms) vydělíme dobou trvání jednoho časového cyklu a dostaneme odpověď.

n \u003d t / Tto \u003d 20 ms / 0,128 ms \u003d 156,25

Zaokrouhlením nahoru na celé číslo dostaneme 156 opatření. To je méně než 255 (maximální hodnota registru počítání), což znamená, že kapacita registru TCNT0 je dostatečná.

Počáteční hodnota registru TCNT0 se počítá jako rozdíl mezi maximálním počtem hodinových cyklů časovače T0 a požadovaným, tj. 256 - 156 \u003d 100. (256 je maximální počet časových intervalů, které může počítat kterýkoli 8-bitový časovač).

Myslím, že je nyní jasné, jak vypočítat počáteční hodnotu TCNT0 pro normální režim.:

Vypočítáme periodu jednoho hodinového cyklu časovače Tt0 \u003d k / Fcpu,
- vypočítat požadovaný počet hodinových cyklů pro daný interval n \u003d t / Tto,
- vypočítat počáteční hodnotu pro počítací registr TCNT0 \u003d 256 - n.

Tento postup můžete automatizovat pomocí maker. Například takto:

#define F_CPU 8000000UL
#definovat TIME_MS (čas, k) (256L - ((čas) * (F_CPU)) / (1000L * (k)))

Ale s takovým makrem musíte být na pozoru, pro určité hodnoty času ak mohou nastat chyby.

Nyní přejdeme ke kódu. Chcete-li použít časovač T0 (a jakýkoli jiný), musíte jej nakonfigurovat (inicializovat) a popsat popisovač přerušení (pokud jsou použity).

Inicializace časovače se skládá z následujících kroků:

Zastavit časovač,
- nastavení normálního režimu v TCCR0 bez spuštění,
- nastavení počáteční hodnoty TCNT0,
- zúčtování příznaků v registru TIFR,
- povolit přerušení přetečení v TIMSK,
- nastavení prescaleru na TCCR0, tj. začátek časovače

V tomto pořadí jsou možné variace.

Inicializační kód bude pro náš úkol vypadat takto:


/ * hodnota pro počítání registru * /
#define T_POLL 100

TCCR0 \u003d 0;
TCCR0 \u003d (0< TCNT0 \u003d T_POLL;
TIFR \u003d (1< TIMSK | \u003d (1< TCCR0 | \u003d (1<

Druhá linie inicializace je ve skutečnosti zbytečná, byla přidána kvůli srozumitelnosti. Chcete-li jasně vidět, který režim časovače je nastaven.

Příznaky přerušení v registru TIFR jsou vymazány zápisem 1 do odpovídajícího bitu. Tuto operaci je třeba provést přepsáním registru a nepoužitím bitového NEBO. A proto.

Řekněme, že v registru TIFR jsou nastaveny dva příznaky přerušení - TOV1 a TOV0. Musíme resetovat TOV0. Při nastavování požadovaného výboje pomocí ORstane se něco jako následující.


// TIFR je 0b00000101
// nastaveny příznakyTOV1 a TOV0
// kód je spuštěnTIFR | \u003d (1<
// TIFR se zkopíruje do R16
IN R16, 0x38

// bit TOV0 je nastaven v R16
// ačkoli je již nainstalována
ORI R16, 0x02

// R16 se rovná 0b00000101 je zapsán do registru TIFR
OUT 0x38, R16

V důsledku toho byly obě vlajky vypuštěny a my jsme chtěli jednu vypustit.

Pokračujme.

Syntaxe popisující popisovače přerušení se u různých kompilátorů mírně liší. Pro IAR `bude popisovač přerušení časovače T0 při události přetečení vypadat takto:



{
TCNT0 \u003d T_POLL;

/ * pro tlačítko by měla být hlasování * /

TIMER0_OVF_vect je vektorová adresa přerušení události přetečení. Je převzata ze souborů záhlaví do mikrokontroléru. V tomto případě jsem to vzal ze souboru iom16.h.

První řádek obsluhy (TCNT0 \u003d T_POLL;) přepíše registr počítání a poté nastaví jeho počáteční hodnotu. Pokud tak neučiníte, časovač bude pokračovat v počítání od 0. Registr počítání musí být přepsán na začátku obsluhy přerušení.

Celý kód pro náš úkol bude vypadat asi takto. (Kód je pro IAR`a. U ostatních kompilátorů musíte změnit soubory záhlaví a popisovač přerušení.)

#zahrnout
#zahrnout
#zahrnout

#define T_POLL 100

int main (neplatné)
{
/ * inicializace časovače * /

TCCR0 \u003d 0;
TCCR0 \u003d (0< TCNT0 \u003d T_POLL;
TIFR | \u003d (1< TIMSK | \u003d (1< TCCR0 | \u003d (1<

/ * inicializuje zbytek periferií * /
DDRB | \u003d (1<

Enable_interrupt ();
zatímco (1);

/ * Popisovač přerušení T0
přetečení události * /
#pragma vector \u003d TIMER0_OVF_vect
__interrupt void TimerT0Ovf (void)
{
/ * přepsat registr počítání * /
TCNT0 \u003d T_POLL;

/ * hlasovací tlačítko * /

/ * inverzní PB0 pro ladění * /
PORTB ^ \u003d (1<

Ovládání kolíku OC0

V normálním režimu může časovač T0 změnit stav kolíku OC0, když se počítací registr a porovnávací registr shodují. A to i bez přerušení. Možnosti řízení jsou určeny bity COM01 a COM00 registru TCCR0.

Zde je příklad programu, který generuje čtvercovou vlnu na pinu OC0.

#zahrnout
#zahrnout

int main (neplatné)
{
/ * inicializace časovače T0 * /

TCCR0 \u003d 0;
TCCR0 \u003d (0< TCNT0 \u003d 0;
OCR0 \u003d 0;
TIMSK \u003d 0;
TCCR0 | \u003d (1<

/ * inicializovat OC0 * /
DDRB | \u003d (1<

Zatímco (1);
návrat 0;
}

Výstup OC0 změní svůj stav na opačný, když je počítací registr nulový.

Pár bodů o používání časovače

Obsluha přerušení časovače (a jakékoli další periferie) by měla být co nejkratší.

Pokud je vypočtená hodnota pro počítací registr (nebo srovnávací registr) zaokrouhlena, časový interval bude počítán časovačem s chybou.

A poslední věc. Může se stát, že zpracování přerušení časovače bude zpožděno (například v důsledku poruchy jiného obsluhy) a registr TCNT0 již započítal několik hodinových cyklů. Pokud právě přepíšete hodnotu TCNT0, bude další přerušení vyvoláno později, než je nutné. Ukazuje se, že předchozí (zpožděná) a nová přerušení nepřežijí požadovaný interval.

Tuto situaci lze zmírnit přepsáním registru počítání takto:

TCNT0 \u003d TCNT0 + startValue;

Přidání aktuální hodnoty počítacího registru k inicializovanému bude brát v úvahu tyto dodatečné hodinové cykly.Pravda je, že existuje jeden VUT v Brně! Pokud je hodnota startValue velká, operace přidání může způsobit přetečení registru počítání.

Například startValue \u003d 250 a časovač se podařilo počítat do 10. Poté operace sčítání povede k následujícímu výsledku:

10 + 250 = 260

Bereme 8 bitů z 260, abychom dostali 4. TCNT0 zapíše 4.

V tomto tutoriálu budeme hovořit o časovačích.

Toto téma je přímo spojeno s tématem mikrokontroléru. Doporučujeme proto, abyste se před čtením této lekce seznámili s předchozím.

Tak proč potřebujeme časovač?

Při stavbě projektů na mikrokontrolérech je často nutné měřit přesné časové intervaly. Například touha blikat LED na určité frekvenci nebo dotazovat stav tlačítka v požadovaných časových intervalech.

Časovače pomáhají řešit úkoly. Časovače mikrokontrolérů AVR však nevědí, co je sekunda, minuta, hodina. Ale oni dobře vědí, co je to takt! Fungují přesně díky přítomnosti hodin kontroléru. To znamená, že časovač počítá počet cyklů hodin kontroléru, a tak měří časové intervaly. Řekněme, že ovladač pracuje s taktovací frekvencí 8 MHz, to znamená, že když se časovač počítá na 8 000 000, projde jedna sekunda, počítá se na 16 000 000, 2 sekundy projdou atd.

Zde však přichází první překážka. Máme 8bitové registry, to znamená, že můžeme počítat až do maxima 255, a vezmeme-li 16-bitový časovač, budeme počítat až do maxima 65535. To znamená, že za jednu sekundu musíme časovač resetovat obrovský početkrát! Samozřejmě to můžete udělat, pokud nemáte co dělat. Ale jednoduše měřit čas pomocí výkonného mikrokontroléru není vůbec zajímavé, chcete udělat něco víc. Zde předzesilovač přichází k naší pomoci. Obecně se jedná o přechodné spojení mezi časovačem a taktovací frekvencí ovladače. Předzesilovač usnadňuje náš úkol tím, že nám umožňuje rozdělit kmitočet hodin určitým číslem před tím, než je přivedeme do časovače. To znamená, že nastavením prescaleru na 8, náš časovač za 1 sekundu bude počítat až 1 000 000, namísto 8 000 000 (samozřejmě při frekvenci kontroléru 8 MHz). Zajímavější, že? A můžeme dělit nejen 8, ale také 64 a dokonce 1024.

Nyní je čas sestavit obvod, nastavit náš časovač, předzesilovač a udělat alespoň něco užitečného!

A dnes uděláme „svítící světla“ z LED. To znamená, že střídavě rozsvítíme 3 LED diody s periodou 0,75 sekundy (tj. Provozní doba jedné LED je 0,25 sekund). Pojďme dát dohromady následující schéma:

Vypočítejte si rezistory R 1-R 3 sami.

Dále zvažte registry odpovědné za provoz časovačů. Celkově má \u200b\u200bAtMega 8 3 časovače, dva 8bitové (časovač 0, časovač 2) a jeden 16bitový (časovač 1). Uvažujeme to na příkladu 16bitového časovače 1.

Dvojice 8bitových registrů TCNT 1H a TCNT 1L společně tvoří 16bitový registr TCNT 1. Tento registr je otevřen pro zápis i čtení. Když je spuštěn časovač 1, hodnota tohoto registru se při každém počtu změní o jednu. To znamená, že registr TCNT 1 obsahuje počet hodinových cyklů, které časovač počítal. Můžeme zde také napsat libovolné číslo v rozsahu od 0 do 2 do 16. síly. V tomto případě se klíště nebude počítat od 0, ale od čísla, které jsme zaznamenali.

Registr TIMSK je zodpovědný za přerušení generovaná, když jsou spuštěny časovače mikrokontroléru. Přerušení je obsluha speciálního signálu, který přichází, když se něco změní... Jakékoli přerušení mikrokontroléru může být povoleno nebo zakázáno. Pokud dojde k povolenému přerušení, hlavní program se přeruší a tento signál se zpracuje. Dojde-li k zakázanému přerušení, programový tok se nepřeruší a přerušení se ignoruje. TOIE 1 bit (Povoleno přerušení přetečení časovače 1) je zodpovědné za umožnění přetížení přerušení čítacího registru TCNT 1 časovače 1. Když je do tohoto bitu 1 zapsáno, je přerušení aktivováno a když je zapsáno 0, je deaktivováno. Toto přerušení je generováno časovačem 1, když je dosaženo maximální hodnoty registru TCNT 1. V další lekci budeme mluvit o přerušení.

Registr TCCR 1B je zodpovědný za konfiguraci časovače 1. V tomto případě nastavíme pomocí bitů CS 10-CS 12 hodnotu prescaleru podle následující tabulky.

Zbytek bitů nás zatím nezajímá.

K dispozici je také registr TCCR 1A, který umožňuje konfigurovat další režimy časovače, například PWM, ale o nich v samostatném článku.

A nyní kód C:

#define F_CPU 16000000UL #include #zahrnout uint8_t num \u003d 0; ISR (TIMER1_OVF_vect) (PORTD \u003d (1<2) (num \u003d 0;) TCNT1 \u003d 61630; // Počáteční hodnota časovače) int main (void) (DDRD | \u003d (1)<

#define F_CPU 16000000UL

#zahrnout

#zahrnout

uint8_t num \u003d;

ISR (TIMER1_OVF_vect)

PORTD \u003d (1<< num ) ;

num ++;

pokud (číslo\u003e 2)

num \u003d;

TCNT1 \u003d 61630; // Počáteční hodnota časovače

int main (neplatné)

DDRD | \u003d (1<< PD0 ) | (1 << PD1 ) | (1 << PD2 ) ;

TCCR1B | \u003d (1<< CS12 ) | (1 << CS10 ) ; // Prescaler \u003d 1024

TIMSK | \u003d (1<< TOIE1 ) ; // Povolí přerušení přetečení časovače 1

TCNT1 \u003d 61630; // Počáteční hodnota časovače

sei (); // Povolit přerušení

zatímco (1)

// Hlavní smyčka programu je prázdná, protože veškerá práce je přerušena

ASM kód:

Sestava (x86)

Zahrňte "m8def.inc" rjmp start .org OVF1addr rjmp TIM1_OVF start: ldi R16, LOW (RamEnd) out SPL, R16 ldi R16, HIGH (RamEnd) out SPH, R16 ldi R16,1 ldi R17,0b00000111 out DDRD, R17 ldi R17,0b00000101 out TCCR1B, R17 ldi R17,0b11110000 out TCNT1H, R17 ldi R17,0b10111110 out TCNT1l, R17 ldi R17,0b00000100 out TIMSK, R17 se main_loop: nop rjmp main_loop TIM1_OV16 R16 l16 label_1 ldi R16,1 label_1: ldi R17,0b10111110 out TCNT1L, R17 ldi R17,0b11110000 out TCNT1H, R17 reti

Zahrnout „m8def.inc“

Rjmp začít

Org OVF 1addr

Rjmp TIM 1_ OVF

start:

Ldi R 16, LOW (RamEnd)

Z SPL, R 16

Ldi R 16, HIGH (RamEnd)

Z SPH, R 16

Ldi R 16, 1

Ldi R 17, 0b00000111

Z DDRD, R 17

Ldi R 17, 0b00000101

Z TCCR 1B, R17

Ldi R 17, 0b11110000

Z TCNT 1H, R17

Ldi R 17, 0b10111110

Lekce 10

Počítadla časovačů. Přerušení

Dnes zjistíme, co to je čítače časovačů v mikrokontrolérech a k čemu slouží a co je přerušení a k čemu jsou také.

Počítadla časovačů - jedná se o zařízení nebo moduly v mikrokontroléru, které, jak název napovídá, něco neustále počítají. Počítají buď do určité hodnoty, nebo do takové hodnoty, kolik bitů jsou. Počítají se neustále stejnou rychlostí, s rychlostí taktovací frekvence mikrokontroléru, korigovanou na frekvenční děliče, které budeme konfigurovat v určitých registrech.

A tyto čítače časovačů neustále počítají, pokud je inicializujeme.

Časovače v MK Atmega8 tři.

Dva z nich jsou osm bitů časovače, to znamená ty, které mohou počítat pouze do 255. Tato hodnota pro nás nebude stačit. I když použijeme maximální frekvenční dělič, nebudeme počítat sekundu, ani nebudeme schopni počítat půl sekundy. A naším úkolem je přesně to spočítat až 1 sekundu, abychom mohli řídit nárůst počtu LED indikátorů. Můžete samozřejmě použít další sestavení proměnné na určitou hodnotu, ale já bych chtěl úplně hardwarový účet.

Ale je tu ještě jeden časovač - to je plnohodnotný 16bitovéčasovač. On nejen 16bitové, ale také má určitá kouzla, která ostatní časovače nemají. S těmito možnostmi se seznámíme později.

Tento 16bitový časovač je to, co dnes budeme studovat a používat. Když se seznámíte s tímto časovačem, nebude vás nic stát samostatným studováním práce dalších dvou, protože jsou mnohem jednodušší. V budoucnu však vezmeme v úvahu také 8bitové časovače, protože jeden časovač nám nebude stačit k dosažení složitějších úkolů.

Nyní krátce o přerušení.

Přerušení (Přerušení) Existují takové mechanismy, které přerušují kód v závislosti na určitých podmínkách nebo určité situaci, které budou diktovat některá zařízení, moduly a sběrnice umístěné v mikrokontroléru.

V našem ovladači Atmega8 je 19 typů přerušení. Zde jsou všechny v tabulce v technické dokumentaci k ovladači.

Jaké mohou být podmínky? V našem případě například časovač odpočítává určitou hodnotu, nebo například na některou sběrnici došlo k bajtu a dalším podmínkám.

V tuto chvíli zvládneme přerušení, které je umístěno v tabulce umístěné o 7 pozic výše - TIMER1 COMPAvolal na 0x006.

Nyní se podívejme na náš 16bitový časovač nebo TIMER1.

Zde je jeho strukturální schéma

Vidíme tam registr TCNTn, ve kterém se číslo neustále mění, to znamená, že se neustále zvyšuje. V praxi je to čítač. To znamená, že tento registr také ukládá číslo, na které časovač započítal.

A v registrech OCRnA a OCRnB (písmena n je číslo časovače, v našem případě to bude 1) - jedná se o registry, do kterých zadáme číslo, se kterým bude číslo v registru TCNTn porovnáno.

Například jsme do registru OCRnA zadali nějaké číslo a jakmile se toto číslo shoduje s hodnotou v registru počítání, dojde k přerušení a my to zvládneme. Časovače s přerušeními jsou velmi podobné obvyklému zpoždění v kódu, pouze když jsme ve zpoždění, nemůžeme v tuto chvíli provést žádný kód (dobře, opět, obrazně „my“, ve skutečnosti ALU). A když se časovač počítá, veškerý kód našeho programu se v tuto chvíli potichu spustí. Vyhrajeme tedy nesmírně, protože nedovolíme, aby obrovské zdroje kontrolérů byly nečinné po dobu jedné nebo dokonce půl sekundy. V tuto chvíli zvládneme stisknutí tlačítek, které zvládneme také v časovači a další.

K dispozici je také registr TCCR. Tento registr je kontrolní registr. Tam jsou nakonfigurovány určité bity, které jsou zodpovědné za konfiguraci časovače.

Časovač má také několik režimů, s nimiž se také trochu později seznámíme.

Skládá se ze dvou polovin, protože máme 8bitový řadič a nemůže mít 16bitové registry. Proto je v jedné polovině registru (a fyzicky v jednom registru) uložena horní část registru a ve druhé - dolní část. Můžete také nazvat dvojicí registrů, která se skládá ze dvou samostatných registrů TCCR1A a TCCR1B. Číslice 1 znamená, že registr náleží časovači 1.

Tento registr TCCR je zodpovědný za nastavení děliče tak, aby se časovač nepočítal tak rychle, je také zodpovědný (nebo spíše za jeho určité bity) za nastavení určitého režimu.

Bity WGM jsou zodpovědné za nastavení režimu

Vidíme zde mnoho režimů.

Normální - toto je obvyklý režim, časovač se počítá do konce.

PWM - tohle je PWM roli mohou hrát pouze různé odrůdy, tj. časovač modulátor šířky pulsu... S touto technologií se seznámíme v pozdějších lekcích.

CTC Je to náhodný reset, přesně to, co potřebujeme. Zde se porovnávají registry TCNT a OCR. Existují dva takové režimy, potřebujeme první, druhý pracuje s jiným registrem.

V této lekci nebudeme studovat všechny typy režimů. Když tyto režimy potřebujeme, zjistíme to.

Pojďme se mučit dokumentací a nakonec se pokusíme něco vložit do některých registrů.

Kód byl jako vždy vygenerován z předchozího projektu. Pro proteus byl kód také zkopírován a přejmenován z poslední hodiny, ve vlastnostech řadiče byla také specifikována cesta k novému firmwaru. Projekty pojmenujeme Test07.

Zkusme, jako vždy, zkompilovat kód a spustit ho v proteu. Pokud vše funguje dobře, začneme přidávat nový kód.

Přidejme ještě jednu funkci, protože jsme se dozvěděli, jak přidat funkce v poslední lekci. Umístěte funkční kód za funkci segchar a před hlavní funkci. Poté, protože v naší nové funkci budeme nazývat funkci segchar.

Navíc nebudeme vytvářet jednu funkci, ale dvě. Do jedné funkce umístíme veškerý inicializační kód pro náš časovač a druhou funkcí bude obsluha přerušení časovače, a takové funkce jsou specifické a není třeba je volat. Až vznikne potřeba, budou se nazývat sami, v závislosti na určitých podmínkách, které byly uvedeny výše.

Proto nazveme první funkci timer_ini

//———————————————

neplatnýtimer_ini( neplatný)

{

}

//———————————————

Také oddělme naše funkce, jakož i některé kompletní bloky s deklarací globálních proměnných, s prototypy funkcí, budeme od sebe oddělit takovými řádky, které kvůli přítomnosti dvou lomítků, kompilátor nebude zpracovávat a vezme je pro připomínky. Díky tomuto sledování uvidíme, kde jedna funkce končí a druhá začíná.

Jak vidíme, tato funkce nemá žádné argumenty - ani vstup, ani návratný. Okamžitě zavoláme tuto funkci v hlavní funkci ()

nepodepsanýcharbutcount \u003d 0,butstate \u003d 0;

timer_ini();

Nyní začneme tuto funkci plnit kódem.

Začněme registrem časovače, například TCCR1B. Pomocí naší oblíbené operace „NEBO“ vložíme jednu do určité části registru

neplatnýtimer_ini( neplatný)

TCCR1B|= (1<< WGM12);

Z komentáře vidíme, že pracujeme s režimovými bity a nastavíme pouze bit WGM12, zbytek necháme. Na základě toho jsme nakonfigurovali následující režim:

Časovač má také takový registr - TIMSK... Tento registr je zodpovědný za masky přerušení - Maska přerušení... Tento registr je k dispozici pro všechny časovače, nejen pro první, je běžný. V tomto registru nastavíme bit OCIE1Acož umožní typ přerušení, který potřebujeme TIMER1 COMPA

TCCR1B|= (1<< WGM12); // nastavení režimu CTC (reset shodou okolností)

TIMSK|= (1<< OCIE1A);

Nyní si zahrajeme s porovnávacími registry. OCR1A (H a L)... Chcete-li to provést, musíte udělat malý výpočet. Registrovat OCR1AH uloží horní část čísla pro srovnání a registr OCR1AL - nejmladší.

Než ale spočítáme, napíšeme kód s libovolnými hodnotami tohoto registru a poté jej opravíme, protože dále inicializujeme dělitel a také se budeme podílet na výpočtu požadovaného času počítání. Bez oddělovače se časovač bude počítat příliš rychle.

TIMSK|= (1<< OCIE1A); // nastavte bit pro povolení přerušení pro 1. čítač shodou okolností s OCR1A (H a L)

OCR1AH= 0b10000000;

OCR1AL= 0b00000000;

TCCR1B|= ( ); // nastavit dělitele.

Doposud jsme nestanovili žádného dělitele, protože jsme ho ještě nepočítali. Udělejme to a udělejme to.

I když máme v registru OCR1A existuje číslo 0b100000000000000000, které odpovídá desetinnému číslu 32768.

Náš mikrokontrolér pracuje, jak jsme se dohodli, na frekvenci 8 000 000 Hz.

Vydělte 8 000 000 32 768, dostaneme přibližně 244,14. Právě s takovou frekvencí v hertzech bude náš časovač fungovat, pokud nepoužijeme dělič. To znamená, že se naše čísla změní 244krát za sekundu, takže je ani neuvidíme. Proto budete muset použít dělič kmitočtu časovače. Vezměme si dělič o 256. Bude nám vyhovovat dobře, a pak ho opravíme porovnávacím číslem přesně na 1 Hz.

Zde jsou rozdělovače pro 1 časovač

Vybral jsem v tabulce potřebného dělitele. Vidíme, že potřebujeme pouze nastavit bit CS12.

Protože máme frekvenční dělič 256, vydělíme 8000000 tímto děličem, dostaneme 31250, proto musíme číslo zadat do TCNT. Náš časovač bude počítat až do tohoto počtu, aby počítal až 1 sekundu. Číslo 31250 je 0b0111101000010010 v binární reprezentaci. Toto číslo jsme vložili do dvojice registrů a také použili dělitel

OCR1AH= 0b 01111010 ; // zapište číslo pro porovnání do registru

OCR1AL= 0b 00010010 ;

TCCR1B|= (1<< CS12 ); // nastavit dělitele.

To je s touto funkcí.

Nyní je další funkcí shoda obsluhy přerušení časovače. Je psáno takhle

ISR( TIMER1_COMPA_vect)

{

}

A tělo této funkce bude vykonáno samo o sobě při výskytu shodnosti čísel.

Budeme potřebovat proměnnou. Pojďme to prohlásit globálně, na začátku souboru

#zahrnout

//———————————————

nepodepsanýchari;

//———————————————

Podle toho odstraníme stejnou proměnnou z kódu ve funkci main ().

inthlavní( neplatný)

nepodepsanýchari;

Také komentujte celý kód v nekonečné smyčce. Jeho roli bude nyní vykonávat časovač a já si myslím, že se s tím vyrovná bez horšího a ještě lepšího, aniž by zasahoval do „kohokoli“.

zatímco(1)

{

// pro (i \u003d 0; i<10;i++)

// {

// while (butstate \u003d\u003d 0)

// {

// if (! (PINB & 0b00000001))

// {

// if (butcount< 5)

// {

// butcount ++;

// }

// jinde

// {

// i \u003d 0;

// butstate \u003d 1;

// }

// }

// jinde

// {

// if (butcount\u003e 0)

// {

// butcount—;

// }

// jinde

// {

// butstate \u003d 1;

// }

// }

// }

// segchar (i);

// _delay_ms (500);

// butstate \u003d 0;

// }

Nyní, ve skutečnosti, tělo obsluhy funguje. Zde budeme volat funkci segchar. Pak se zvýší o 1 proměnnou i... A tak, aby nepřekračovalo jednociferné číslo, za tohoto stavu jej vynulujeme

ISR( TIMER1_COMPA_vect)

-li( i>9) i=0;

segchar( i);

i++;

Nyní opravme kód na začátku hlavní funkce (). Přístav D, který je zodpovědný za stav segmentů, budeme skóre s těmi, aby se rozsvítil indikátor, když se rozsvítí, protože se jedná o běžnou anodu. Pak sem vložíme číslo 0 do globální proměnné i, jen pro objednávku. Obecně platí, že při startu v neinicializovaných proměnných jsou obvykle nuly. Stále to však inicializujeme. A co je nejdůležitější, aby přerušení časovače fungovalo, nestačí jej zahrnout do inicializace časovače. Obecně také, aby všechna přerušení fungovala, je nutné povolit globální přerušení. K tomu existuje speciální funkce sei () - Nastavit přerušení.

Nyní bude kód takto

DDRB= 0x00;

PORTD= 0b 11111111 ;

PORTB= 0b00000001;

i=0;

sei();

zatímco(1)

Musíme také zahrnout soubor knihovny přerušení na začátek souboru.

#zahrnout

#zahrnout

#zahrnout

Také pro tlačítko zatím nebudeme potřebovat proměnné, protože s tlačítkem dnes nebudeme pracovat. Pojďme je komentovat

inthlavní( neplatný)

// nepodepsané char butcount \u003d 0, butstate \u003d 0;

timer_ini();

Pojďme dát dohromady náš kód a zkontrolovat jeho výkon nejprve v proteu. Pokud všechno funguje dobře, zkontrolujeme také živý obvod

Všechno pro nás funguje. Pokuta!

Tady jsou takové stopky. Ale protože nemáme ani křemenný rezonátor, nelze tyto stopky nazvat přesné.

Přesto jsme se dnes s vámi hodně naučili. Dozvěděli jsme se o přerušeních, naučili jsme se s nimi také pracovat, naučili jsme se pracovat s časovači, nakonfigurovat několik nových registrů mikrokontroléru, předtím jsme pracovali pouze s portovými registry. V důsledku toho jsme také významně uvolnili aritmeticko-logické zařízení našeho mikrokontroléru.

Podívejte se na VIDEO LESSON

Zobrazení příspěvků: 17 258