CTC timer v mikrokontroléri ATtiny85

Zápisník experimentátora

Hierarchy: Časovač (timer)

ATtiny85 obsahuje dva 8-bitové timery. Nemajú síce taký rozsah ako tie v ATmega328P, ale na väčšinu úloh to postačuje. V tomto článku sa pozrieme na časovače z hľadiska CTC režimu. Na generovanie programov budeme využívať online kalkulátor.

Použité súčiastky

Ak si chcete experimenty vyskúšať, budete potrebovať.

  • Vývojovú dosku pre ATtiny85, alebo len skúšobné pole so zastrčeným mikrokontrolérom.
  • USBasp programátor.

Zdrojové texty som písal pre frekvencie 1000000, 8000000 a 16000000. Používal som jadro https://github.com/SpenceKonde/ATTinyCore. Pre každý timer sú tri príklady. Všetky blikajú LED diódou, ktorá je pripojená na pin 0. Pin 0 je na mikrokontroléri vpravo dole.

Timer0

Timer0 je v podstate zhodný s rovnakým timerom v ATmega328P. Preto aj nastavenie registrov vyzera skoro rovnako. To čo sa môže líšiť je umiestnenie jednotlivých bitov, ale pretože používame môj kalkulátor, nemusí nás to trápiť a základ programu nám kalkulátor vygeneruje. Pretože pracujeme s nízkou frekvenciou 1 Hz, nemôžeme ju nastaviť na timeri priamo. Používam drobný trik a nastavil som frekvenciu na 100 Hz a v obsluhe prerušenia si pomocou modula delím túto frekvenciu hodnotou 100 a tým sa dostanem na  požadovaný 1 Hz. V kalkulačke je na to už pripravená šablóna, ktorá generuje tento kód.

#define ledPin 0
volatile int divider=0;

void setupTimer0() {
  noInterrupts();
  // Clear registers
  TCCR0A = 0;
  TCCR0B = 0;
  TCNT0 = 0;

  // 100.16025641025641 Hz (1000000/((155+1)*64))
  OCR0A = 155;
  // CTC
  TCCR0A |= (1 << WGM01);
  // Prescaler 64
  TCCR0B |= (1 << CS01) | (1 << CS00);
  // Output Compare Match A Interrupt Enable
  TIMSK |= (1 << OCIE0A);
  interrupts();
}

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

void loop() {
}

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

Timer1

Timer1 je v CTC režime zložitejší. Nastavuje sa odlišne a musíme nastaviť viac registrov. Na druhej strane ale máme k dispozícii omnoho viac deliacich pomerov, čo dáva tomuto timeru lepšie možnosti.

Všimnite si, že na nastavenie požadovanej frekvencie musíme nastaviť dva registre. Tento timer totiž pomocou jedného registra nastavuje frekvenciu a pomocou iného vyvoláva prerušenie. V mojom prípade majú oba registre rovnakú hodnotu. Hodnota registra OCR1A ale môže mať hocijakú hodnotu, len nesmie byť väčšia ako hodnota v OCR1C. V tomto prípade nám je jedno, kedy presne prerušenie nastane, stačí nám, že nastane a vyvolá náš kód na spracovanie prerušenia. Ale takto sa mi to javilo byť prehľadnejšie a tak som to aj nastavil v kalkulačke.

#define ledPin 0
volatile int divider=0;

void setupTimer1() {
  noInterrupts();
  // Clear registers
  TCNT1 = 0;
  TCCR1 = 0;

  // 100.16025641025641 Hz (1000000/((155+1)*64))
  OCR1C = 155;
  // interrupt COMPA
  OCR1A = OCR1C;
  // CTC
  TCCR1 |= (1 << CTC1);
  // Prescaler 64
  TCCR1 |= (1 << CS12) | (1 << CS11) | (1 << CS10);
  // Output Compare Match A Interrupt Enable
  TIMSK |= (1 << OCIE1A);
  interrupts();
}

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

void loop() {
}

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

Zdrojové texty

Zdrojové texty sa nachádzajú na serveri GitHub.


05.04.2017


Menu