Vizualizácia činnosti registra TCNT2 v CTC režime

Zápisník experimentátora

Hierarchy: Časovač (timer)

Pri testovaní mojej aplikácie na výpočet timerov v CTC režime som natrafil na zaujímavý článok, ktorý ma inšpiroval k tomuto pokusu. Jednoduchý spôsob, ako možno vizualizovať to, čo sa deje počas činnosti timera. Preto som len mierne preusporiadal zapojenie z predchádzajúceho experimentu a pustil sa do vlastnej vizualizácie.

Použité súčiastky

Na vytvorenie animácie môžeme použiť:

  • Arduino Pro Mini (link) - Použil som ho preto, lebo sa zmestí aj na najmenšie skúšobné pole.
  • Mini Breadboard (link) - Najmenšie predávané skúšobné pole. Použil som dve a treba si dať pozor, že sa predávajú dve modifikácie tohoto breadboardu. Tie čo majú drobné výstupky sa dajú takto pekne navzájom pospájať.
  • Prevodník CP2102 USB to Serial (link) - Prevodník slúži na naprogramovanie Arduina.
  • Dosku s rezistormi a LED diódami (link) - Pretože mám vyrobených niekoľko takýchto dosiek, použil som ju, aby som nemusel komplikovane pripojiť 8 LED a 8 rezistorov k pinom Arduina. Ale rovnako môžete použiť aj priamo rezistory a LED, len si dajte pozor, aby ste neprekročili maximálny prúd na pine. Preto používajte rezistory od 330 do 1000 ohmov.

Všetko je zapojené podľa nasledovného obrázka. LED diódy sú pripojené na piny RX (0), TX (1), 2-7 a na obrázku je ešte vidno pripojenie GND na mojej LED doske pomocou dvoch drôtených prepojok k Arduinu. Arduino Pro Mini má vyvedené GND aj na druhej strane, takže som mohol použiť aj jedinú prepojku, ale potom by sa to zle fotografovalo.

RX a TX sú navzájom prehodené, pretože sa bude zobrazovať bitová podoba 8bitového čísla pomocou priameho zápisu do registra PORTD a potrebujeme mať piny zoradené rovnako, ako sú bity v registri. Budeme zobrazovať obsah registra TCNT2, čo je register pre timer2. V ňom sa postupne zvyšuje hodnota až po nastavenú hodnotu registra OCR2A. To sa deje v prípade režimu CTC. Malo by platiť, že maximálna hodnota TCNT2=OCR2A. Na diódach je to ľahko skontrolovateľné, pretože ak do OCR2A zapíšete napríklad hodnotu 63 (binárne 0b00111111), nemali by svietiť posledné dve LED. Ak sa rozsvietia, potom ste niečo naprogramovali zle.

Programovanie

Napísal som dva programy:

  • Prvý je len simulácia, ktorá nám zjednodušene ukáže, čo sa vlastne deje v spomínanom registri.
  • Druhý potom nastaví timer na frekvenciu 100 Hz a zobrazuje obsah registra cez LED diódy.

Simulácia

Simulácia len priamym zápisom na port PORTD postupne zapisuje čísla od 0-255. Preto mám piny prepojené na LED tak, ako vidíte na obrázku. Aby som mohol jedným priradením nastaviť všetkých osem diód.

void setup() {
  for (int i = 0; i < 8; i++)
    pinMode(i, OUTPUT);
}

void loop() {
  for (uint8_t i = 0; i <= 255; i++) {
    PORTD = i;
    delay(50);
  }
}

Vizualizácia

Základ programu som vygeneroval v mojej aplikácii. Pretože hodiny Arduina sú nastavené na 16 MHz a používame 8bitový timer, nemôžeme ho nastaviť na príliš nízku hodnotu. Minimum je približne 70 Hz. Preto som to radšej nastavil na 100 Hz.

Aby sme videli, že program funguje správne, nechal som v programe blikať aj LED diódu na pine 13. Blikanie sa odohráva v obsluhe prerušenia ISR(TIMER2_COMPA_vect) a pretože prerušenie sa vyvolá 100x za sekundu, spomalil som ho pomocou premennej divider na frekvenciu 1 Hz.

Vizualizácia prerušenia sa nachádza vo funkcii loop. Nemôžeme ju mať v prerušení, pretože v okamihu, ako sa prerušenie vyvolá, má register TCNT2 stále rovnakú hodnotu. Vo funkcii loop ho vizualizujeme každých 20 ms. Pretože to je v násobku 1 Hz (1000/20=50), zdanlivo to pekne vykresľuje obsah registra akoby v spomalenom tempe. Keby som použil inú hodnotu, bolo by blikanie LED diód viac nepravidelné. Keď sa zadívate do blikania, všimnete si, že binárne číslo nejde až do 255. Keby bola v registri OCR2A napríklad hodnota 31, 63 alebo 127, boli by zhasnuté diódy z horných bitov ešte viac viditeľné. To je vlastne aj dôkazom toho, že to v režime CTC naozaj počíta správne.

#define ledPin 13

int divider=0;

void setupTimer() {
  noInterrupts();
  TCCR2A = 0;
  TCCR2B = 0;
  TCNT2  = 0;
  
  OCR2A = 155; // 100.16025641025641 Hz
  TCCR2A |= (1 << WGM21);
  TCCR2B |= 0;
  TCCR2B |= (1 << CS22) | (1 << CS21) | (1 << CS20);
  TIMSK2 |= (1 << OCIE2A);
  interrupts();
}

void setup() {
  pinMode(ledPin, OUTPUT);

  for (int i = 0; i < 8; i++)
    pinMode(i, OUTPUT);
    
  setupTimer();
}

void loop() {
  PORTD = TCNT2;
  delay(20);
}

ISR(TIMER2_COMPA_vect) {
  if(divider==0)
    digitalWrite(ledPin, digitalRead(ledPin) ^ 1);
  divider++;
  divider%=100;
}

Zdrojový kód

Zdrojový kód sa nachádza na GitHub.


27.01.2017


Menu