This shows you the differences between two versions of the page.
| Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
| ru:avr:timers [2013/08/14 20:02] – eduardtlmk | ru:avr:timers [Unknown date] (current) – removed - external edit (Unknown date) 127.0.0.1 | ||
|---|---|---|---|
| Line 1: | Line 1: | ||
| - | ====== Счётчики/ | ||
| - | Счётчики (англ. // | ||
| - | |||
| - | ===== Стандартный режим счётчика ===== | ||
| - | |||
| - | В стандартном режиме счётчик не выполняет других функций кроме постоянного считывания последовательных номеров. Значение счётчика в программе можно в любой момент считать и изменить. Единственная дополнительная возможность в стандартном режиме счётчика – это вызвать прерывание при переполнении счётчика. Стандартный режим обычно используется для заполнения какого-либо отрезка программы в определённые интервалы времени. | ||
| - | |||
| - | <box 100% round # | ||
| - | |||
| - | Требуется ATmega128, работающий на частоте 8 MHz, заставить совершать прерывания через каждые 10 ms (частота 100 Hz). Для задания подходит 8-битный счётчик 0. | ||
| - | |||
| - | <code c> | ||
| - | #include < | ||
| - | |||
| - | ISR(TIMER0_OVF_vect) | ||
| - | { | ||
| - | // Придание счётчику такого значения, | ||
| - | // чтобы следующее переполнение происходило через 10 ms. | ||
| - | // Формула: | ||
| - | TCNT0 = 178; | ||
| - | } | ||
| - | |||
| - | int main() | ||
| - | { | ||
| - | // Для того, чтобы первое прерывание переполнения произошло через 10 ms, | ||
| - | // следует и здесь обнулить счётчик. | ||
| - | TCNT0 = 178; | ||
| - | |||
| - | // Коэффициент делителя частоты 1024 | ||
| - | TCCR0 = 0x07; | ||
| - | |||
| - | // Разрешение прерывания заполнения счётчика | ||
| - | TIMSK |= (1 << TOIE0); | ||
| - | |||
| - | // Разрешение глобального прерывания | ||
| - | sei(); | ||
| - | |||
| - | // Бесконечный цикл программы | ||
| - | while (1) continue; | ||
| - | } | ||
| - | </ | ||
| - | |||
| - | Счётчик в данном примере не будет совершать прерывания ровно через 10мс, так как для этого счётчику нужно присвоить десятичное значение, | ||
| - | |||
| - | </ | ||
| - | |||
| - | ==== Счётчик с внешним тактом ==== | ||
| - | |||
| - | В качестве тактового сигнала счётчика можно использовать внешний сигнал микроконтроллера (англ. //external clock source//). Для этого на AVR имеется вывод Tn, где n обозначает номер счётчика. Внешний сигнал такта и полярность можно выбрать с помощью регистра делителя частоты. | ||
| - | |||
| - | ==== Измерение событий ==== | ||
| - | |||
| - | Так как счётчики позволяют измерять время, на более сложных микроконтроллерах AVR есть возможность с помощью аппаратного обеспечения измерить время, в которое произошло какое-либо событие. Эта часть счётчика называется фиксатором событий (англ. //input capture unit//). В AVR есть возможность выбора между двумя событиями: | ||
| - | |||
| - | <box 100% round # | ||
| - | |||
| - | Vaja on 8 MHz taktsagedusel töötava ATmega128-ga mõõta välise 122 Hz - 100 kHz loogilise nelinurksignaali sagedust 1 Hz täpsusega. Programm on tehtud 16-bitise loendur 1 sündmuste püüdjaga. | ||
| - | |||
| - | <code c> | ||
| - | #include < | ||
| - | |||
| - | unsigned long frequency; | ||
| - | |||
| - | // Sündmuse toimumise katkestus | ||
| - | ISR(TIMER1_CAPT_vect) | ||
| - | { | ||
| - | // Loenduri nullimine | ||
| - | TCNT1 = 0; | ||
| - | |||
| - | // Tulemus on ainult siis arvestatav, kui | ||
| - | // loendur pole vahepeal üle täitunud | ||
| - | if (!(TIFR & (1 << TOV1))) | ||
| - | { | ||
| - | // Sageduse arvutamine perioodi pöördväärtusest. | ||
| - | frequency = (unsigned long)8000000 / | ||
| - | (unsigned long)ICR1; | ||
| - | } | ||
| - | else | ||
| - | { | ||
| - | // Sagedus on vähem kui 122 Hz | ||
| - | frequency = 0; | ||
| - | |||
| - | // Loenduri ületäitumise lipukese nullimine | ||
| - | TIFR &= ~(1 << TOV1); | ||
| - | } | ||
| - | } | ||
| - | |||
| - | int main() | ||
| - | { | ||
| - | // Tõusva frondi registreerimine, | ||
| - | TCCR1B = (1 << ICES1) | (1 << CS10); | ||
| - | |||
| - | // Sündmuse toimumise katkestuse lubamine | ||
| - | TIMSK = (1 << TICIE1); | ||
| - | |||
| - | // Globaalne katkestuste lubamine | ||
| - | sei(); | ||
| - | |||
| - | // Lõputu programmitsükkel | ||
| - | while (1) continue; | ||
| - | } | ||
| - | </ | ||
| - | |||
| - | Programmis tekib välise signaali tõusva frondi ajal sündmuse katkestus. Katkestuse jooksul kontrollitakse, | ||
| - | |||
| - | </ | ||
| - | |||
| - | Sündmuste püüdmist ning nende aja registreerimist saab teha ka tarkvaraliselt. Saab kasutada väliseid või muid katkestusi ja nende tekkimise ajal lugeda loenduri väärtus. Riistvaraline sündmuste püüdmine on siiski mõeldud eeskätt programmist sõltumatuks töötamiseks ja suhteliselt lühiajaliste (või tihedate) sündmuste mõõtmiseks. | ||
| - | |||
| - | ===== Signaali genereerimine ===== | ||
| - | |||
| - | Keerukamate loenduritega saab peale signaali pikkuse mõõtmise ka signaali tekitada. Selleks on loenduril väärtuse võrdlemise üksus (inglise keeles //output compare unit//) ja võrdlustulemuse väljastusüksus (inglise keeles //compare match output unit//). Võrdlusüksusesse kuuluvad registrid sama bitilaiusega kui loendur ise ja nende registrite väärtusi võrreldakse loenduri väärtusega selle töö ajal. Hetkel, mil loenduri väärtus saab võrdseks võrdlusüksuse registri väärtusega, | ||
| - | |||
| - | Mõnedel signaali genereerimise režiimidel on määratav ka loenduri suurim väärtus - loenduri füüsiline suurus jääb küll samaks, kuid mängus on võrdlusregister, | ||
| - | |||
| - | Loendurid ja nende abil genereeritavate signaalide režiimid on ühed keerulisemad perifeeriamoodulid AVR-il. Kõigist neist kirjutamine läheks pikaks ja enamasti pole nende kasutamisel kõike detailselt teada. Seetõttu on järgnevalt kirjeldatud vaid üht levinuimat PWM signaali robootikas. Ülejäänut saab juba AVR dokumentatsioonist järgi uurida. | ||
| - | |||
| - | ==== Pulsilaius-modulatsioon ==== | ||
| - | |||
| - | Pulsilaius-modulatsioon (inglise keeles //pulse width modulation//, | ||
| - | |||
| - | <box 100% round # | ||
| - | |||
| - | Vaja on 8 MHz taktsagedusel töötava ATmega128-ga genereerida kaks kiirusreguleeritavat servomootori signaali. Viiguga PB5 (OC1A) tuleb genereerida pulsipikkus 1 ms ja viiguga PB6 (OC1B) pulsipikkus 2 ms. | ||
| - | |||
| - | <code c> | ||
| - | #include < | ||
| - | |||
| - | int main() | ||
| - | { | ||
| - | // Viigud väljundiks | ||
| - | DDRB |= (1 << PIN5) | (1 << PIN6); | ||
| - | |||
| - | // Väljundid A ja B võrdusmomendil madalaks, | ||
| - | // "Fast PWM" režiim, sagedusjagur 8 | ||
| - | TCCR1A = (1 << COM1A1) | (1 << COM1B1) | (1 << WGM11); | ||
| - | TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS11); | ||
| - | |||
| - | // Suurim loenduri väärtus. Valem: | ||
| - | // TOP = 8 MHz / 8 / 50 Hz | ||
| - | ICR1 = 20000; | ||
| - | |||
| - | // Esimese mootori poolperiood 1 ms, teisel 2 ms | ||
| - | OCR1A = 1000; | ||
| - | OCR1B = 2000; | ||
| - | |||
| - | // Lõputu programmitsükkel | ||
| - | while (1) continue; | ||
| - | } | ||
| - | </ | ||
| - | |||
| - | </ | ||