Өмнөх хичээлийн оролт гаралт шиг тоолууруудыг мөн регистрүүдээр тохируулдаг. Энэ удаа 0 дугаарын 8 битийн timer/counter -ыг хэрхэн тохируулахыг тайлбарлая.
Тоолуур хэр хурдан тоолохыг timer/counter control register буюу TCCR0B регистрийн баруун захын CS02, CS01, CS00 (CS нь chip select -ийн товчлол) гэсэн гурван битээр тохируулна.
- CS02=0, CS01=0, CS00=0 бол тоолуур ажиллахгүй байх болно.
- CS02=0, CS01=0, CS00=1 бол тоолуур микроконтроллерын хурдаар тоолно.
- CS02=0, CS01=1, CS00=0 бол тоолуур микроконтроллерын хурднаас 8 дахин удаан тоолно.
- CS02=0, CS01=1, CS00=1 бол тоолуур микроконтроллерын хурднаас 64 дахин удаан тоолно.
- CS02=1, CS01=0, CS00=0 бол тоолуур микроконтроллерын хурднаас 256 дахин удаан тоолно.
- CS02=1, CS01=0, CS00=1 бол тоолуур микроконтроллерын хурднаас 1024 дахин удаан тоолно.
- CS02=1, CS01=1, CS00=0 бол микроконтроллерын T0 хөлийн утга 1 -ээс 0 -руу шилжих мөчид тоолуурын утга нэгээр нэмэгдэнэ. Attiny2313 -ын хувьд T0 хөл бол PD4 хөл юм. Жишээ нь энэ хөлийг ашиглаж товчлуур хэд дахиж дарагдсаныг тоолж болно гэсэн үг.
- CS02=1, CS01=1, CS00=1 бол микроконтроллерын T0 хөлийн утга 0 -ээс 1 -руу шилжих мөчид тоолуурын утга нэгээр нэмэгдэнэ.
// CS02=1, CS01=0, CS00=1 -> 1/(1000000/1024) = 0.001024 секунд
TCCR0B = (1 << CS02) | (1 << CS00);
0 дугаар тоолуурын утга TCNT0 регистр дээр хадгалагдана.
Одоо энэ хоёр регистрийг ашиглаад PB1 хөл дээр залгасан LED диодоо секунд болгонд асааж унтраадаг болгоё:
#include "avr/io.h"
// 200 миллисекунд хүлээ
void wait_200_milliseconds() {
// Тоолуурыг тэглэнэ
TCNT0 = 0;
// Микроконтроллер 1000000 hertz ийн хурдтай ажиллаж байгаа
// 1/(1000000/1024) = 0,001024 секунд
// Тоолуурын утга 1,024 миллисекунд болгонд нэгээр ихсэнэ
TCCR0B = (1 << CS02) | (1 << CS00);
// Тоолуурын утга 200 болтол хүлээ
while (TCNT0 < 200);
// Тоолуур ажиллуулахын болиул
TCCR0B = 0;
}
int main() {
uint8_t i;
// PB1 хөл дээр LED залгасан
DDRB |= (1 << PB1);
// LED асаа
PORTB |= (1 << PB1);
while(1) {
// 5 удаа 200 миллисекунд хүлээх = нийтдээ нэг секунд
for (i = 0; i < 5; i++) {
wait_200_milliseconds();
}
// LED унтраастай бол асаа, асаалттай бол унтраа
PORTB ^= (1 << PB1);
}
return 0;
}
Дээрх кодын сул тал нь тоолуур ажиллаж байх үед микроконтроллер өөр юу ч хийх боломжгүй. Энэ асуудлыг хоёр янзын тасалдал (англиар interrupt) ашиглаж арилгаж болно. TCNT0 регистрийн утга 255 -аас 0 -руу шилжих мөчид timer/counter overflow interrupt эсвэл TCNT0 -ын утга OCR0A регистрийн утгаас илүү гарсан тохиолдолд timer/counter compare match interrupt тус тус үүсгэн ашиглаж болдог.
Timer/counter overflow тасалдал үүсгэхийн тулд TIMS (timer/counter interrupt mask) регистрийн TOIE0 битэд 1 гэсэн утга олгох хэрэгтэй. Харин timer/counter compare match тасалдал үүсгэе гэвэл TIMS регистрийн OCIE0A битийг 1 болгох ёстой бөгөөд тухайн тасалдлын үед тоолуурын утгыг тэглэе гэвэл TCCR0A регистрийн WGM01 битийг 1 болгоод бусад WGM битүүдийг тэглэнэ.
Дээр бичсэн кодыг одоо timer/counter compare match тасалдал ашигладаг болгож өөрчилье:
#include "avr/io.h"
#include "avr/interrupt.h"
volatile uint8_t i = 0;
ISR (TIMER0_COMPA_vect)
{
i++;
// 5 udaa 200 millisekunden = 1 sekund
if (i == 5) {
// LED g untraastai bol asaa, asaalttai bol untraa
PORTB ^= (1 << PB1);
i = 0;
}
}
int main() {
// PB1 hol deer LED zalgagdsan
DDRB |= (1 << PB1);
// LED g asaa
PORTB |= (1 << PB1);
// Tooluuriin utgiig 0 bolgo
TCNT0 = 0;
// tooluuriin utga OCR0A tai tentsvel tooluuriig tegle
TCCR0A |= (1 << WGM01);
// mikrocontroller 1000000 herz iin hurdtai ajillaj baigaa
// 1/(1000000/1024) = 0,001024 sekund
// tooluuriin utga 1,024 millisekund bolgond 1 eer nemegdene
TCCR0B |= (1 << CS02) | (1 << CS00);
// 200 millisekund tutamt compare match interrupt uusne
OCR0A = 199;
// compare match interrupt iig uusehiig zovshooroh
TIMSK |= (1 << OCIE0A);
// global interrupt zovshooroh
sei();
while(1) {
// end oor uildel hiij bolno
}
return 0;
}
0 дугаар тоолуур OCR0A -аас гадна OCR0B гэж бас нэгэн регистртэй.