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.
Ak si chcete experimenty vyskúšať, budete potrebovať.
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 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 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 sa nachádzajú na serveri GitHub.
05.04.2017