Monday, December 21, 2009

AVR Tutorial 2: Тоолуур

Зарим тохиолдолд микроконтроллер дээр тодорхой хугацааны дараа юм уу эсвэл тодорхой давталтаар ямар нэгэн үйлдэл хийх хэрэгтэй болдог. Үүнд timer/counter буюу тоолуур ашиглана. AVR микроконтроллер төрлөөсөө хамаараад 8 болон 16 битийн хэд хэдэн тоолууртай байдаг. Энэ хичээлд ашиглаж буй Attiny2313 маань 8 битийн нэг (timer/counter дугаар: 0), 16 битийн нэг (timer/counter дугаар: 1), нийтдээ 2 тоолууртай.

Өмнөх хичээлийн оролт гаралт шиг тоолууруудыг мөн регистрүүдээр тохируулдаг. Энэ удаа 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 -руу шилжих мөчид тоолуурын утга нэгээр нэмэгдэнэ.
Хэрвээ таны микроконтроллер 1 Mhz -ын хурдтай байвал доорх код 1 миллисекунд (1/(1000000/1024) = 0.001024 секунд) тутамд тоолуурын утгыг нэгээр ихэсгэнэ:

// 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 гэж бас нэгэн регистртэй.

3 comments:

  1. hey ene hereg boloh boluu http://fritzing.org/. uug ene chigleleer mash ih sonirhdog gehdee yaaag haanaas yaj ehlehee medq bn kkk
    zol

    ReplyDelete
  2. Сайн байна уу? Би монгол хэл дээр танай блогоос өөр олигтойхон шиг мэдээлэлтэй блог олж харсангүй. Надад хэдэн юмны талааар хичээл оруулаад өгөөч яааралтай тэхүү. Atmega8 дээр 2 wire(TWI), мөн I2C талаар... C ашиглаж хийсэн бяцхаан LED унтрааж асаадаг ч юмуу тиймэрхүү жишээтэй н хамт. PLS

    ReplyDelete