| Next revision | Previous revision |
| ru:avr:timers [2013/08/14 16:29] – создано eduardtlmk | ru:avr:timers [2020/07/20 09:00] (current) – external edit 127.0.0.1 |
|---|
| ====== Loendurid/Taimerid ====== | ====== Счётчики/Таймеры ====== |
| |
| Loendurid (inglise keeles //counter//), teatud mõttes taimerid (inglise keeles //timer//), on mikrokontrollerite ühed oluliseimad lisafunktsioonid. Nende abil saab protsesse täpselt ajastada, signaale genereerida ja sündmusi loendada. Loenduri tööpõhimõte seisneb sisendtaktide arvu trigerite ahela abil binaarväärtuseks teisendamises. Ahela pikkusest oleneb maksimaalne loendatavate taktide arv, mida tähistatakse kahendkoodi pikkusega. AVR mikrokontrolleril on loendurid 8- ja 16-bitised. Kui loendur omab maksimaalset väärtust (8-bitiste puhul 255, 16-bitiste puhul 65535), tekib järgmise taktiga ületäitumine (inglise keeles //overflow//) ja loendur alustab uuesti nullist. Loenduri taktsignaal saab tulla mikrokontrolleri töötaktist ja sel juhul on võimalik selle sagedust sagedusjaguriga (inglise keeles //prescaler//) ka vähendada. Mõnel AVR-il on sisemine eraldiseisev taktsignaali generaator, mille sagedust saab sageduskordistiga tõsta. Loendurid erinevad ka rakendusvõimaluste ja töörežiimide poolest. | Счётчики (англ. //counter//), в некотором смысле таймеры (англ. //timer//), являются одними из важнейших дополнительных функций микроконтроллеров. С их помощью можно регулировать процессы точно по времени, генерировать сигналы и считывать события. Рабочий принцип счётчика состоит в том, что он преобразовывает число входных тактов в бинарное значение при помощи цепочки триггеров. От длины цепочки зависит максимальное считываемое количество тактов, которое обозначается длинной двоичного кода. Счётчики микроконтроллера AVR 8- и 16-битные. Если счётчик достигает максимального значения (у 8-битных 255, 16-битных 65535), то при следующем такте происходит переполнение (англ. //overflow//) и счётчик обнуляется. Тактовый сигнал может приходить из рабочего такта микроконтроллера и в этом случае можно уменьшить его частоту при помощи делителя частоты (англ. //prescaler//). У некоторых AVR имеется отдельный внутренний генератор тактовых сигналов, частоту которого можно увеличить с помощью умножителя частоты. Счётчики различаются так же по возможностям применения и рабочим режимам. |
| |
| ===== Loenduri normaalrežiim ===== | ===== Стандартный режим счётчика ===== |
| |
| Normaalrežiimis ei täida loendur muud funktsiooni kui pidevat järestikulist arvude loendamist. Loenduri väärtust saab igal hetkel programmis muidugi ka lugeda ja muuta. Ainuke lisavõimalus normaalrežiimis on katkestuse tekitamine loenduri ületäitumisel. Normaalrežiimi kasutatakse tavaliselt mingi programmilõigu täitmiseks kindlate ajaintervallide järel. | В стандартном режиме счётчик не выполняет других функций кроме постоянного считывания последовательных номеров. Значение счётчика в программе можно в любой момент считать и изменить. Единственная дополнительная возможность в стандартном режиме счётчика – это вызвать прерывание при переполнении счётчика. Стандартный режим обычно используется для заполнения какого-либо отрезка программы в определённые интервалы времени. |
| |
| <box 100% round #EEEEEE|Näide> | <box 100% round #EEEEEE|Пример> |
| |
| Vaja on 8 MHz taktsagedusel töötav ATmega128 10 ms (sagedus 100 Hz) ajavahemiku järel katkestust tekitama panna. Ülesandeks sobib 8-bitine loendur 0. | Требуется ATmega128, работающий на частоте 8 MHz, заставить совершать прерывания через каждые 10 ms (частота 100 Hz). Для задания подходит 8-битный счётчик 0. |
| |
| <code c> | <code c> |
| ISR(TIMER0_OVF_vect) | ISR(TIMER0_OVF_vect) |
| { | { |
| // Loendurile sellise väärtuse omistamine, | // Придание счётчику такого значения, |
| // et järgmine ületäitumine tekiks 10 ms pärast. | // чтобы следующее переполнение происходило через 10 ms. |
| // Valem: 256 - 8 MHz / 1024 / 100 Hz = 177,785 = ~178 | // Формула: 256 - 8 MHz / 1024 / 100 Hz = 177,785 = ~178 |
| TCNT0 = 178; | TCNT0 = 178; |
| } | } |
| int main() | int main() |
| { | { |
| // Et esimene ületäitumise katkestus tekiks 10 ms pärast, | // Для того, чтобы первое прерывание переполнения произошло |
| // tuleb ka siinkohal loendur algväärtustada. | // через 10 ms, следует и здесь обнулить счётчик. |
| TCNT0 = 178; | TCNT0 = 178; |
| |
| // Sagedusjaguri teguriks 1024 | // Коэффициент делителя частоты 1024 |
| TCCR0 = 0x07; | TCCR0 = 0x07; |
| |
| // Loenduri täitumise katkestuse lubamine | // Разрешение прерывания заполнения счётчика |
| TIMSK |= (1 << TOIE0); | TIMSK |= (1 << TOIE0); |
| |
| // Globaalne katkestuste lubamine | // Разрешение глобального прерывания |
| sei(); | sei(); |
| |
| // Lõputu programmitsükkel | // Бесконечный цикл программы |
| while (1) continue; | while (1) continue; |
| } | } |
| </code> | </code> |
| |
| Näites toodud loendurile omistatava väärtusega siiski täpselt 10 ms järel katkestust ei tekitata, sest vaja oleks loendurile omistada komakohaga väärtus, kuid see pole võimalik. Et täpset katkestuse intervalli saada, tuleb nii sagedusjaguri tegur kui ka loendurile täitumisel omistatav väärtus valida nii, et taktsagedus jaguks täpselt. Paraku pole see alati võimalik, ja eriti just 8-bitise loenduri puhul, sest selle väärtuste skaala on üsna väike. Täpsema ja suurema intervalli tekitamiseks saab kasutada 16-bitist loendurit. | Счётчик в данном примере не будет совершать прерывания ровно через 10мс, так как для этого счётчику нужно присвоить десятичное значение, а это невозможно. Для того чтобы получить точный интервал прерывания, следует коэффициент делителя частоты и значение, получаемое счётчиком при заполнении выбирать так, чтобы их деление было точным. К сожалению, это не всегда возможно, особенно в случае с 8-битным счётчиком, так как его шкала значений достаточна мала. Для получения более точного и широкого интервала можно использовать 16-битный счётчик. |
| |
| </box> | </box> |
| |
| ==== Välise taktiga loendur ==== | ==== Счётчик с внешним тактом ==== |
| |
| Loenduri taktsignaalina saab kasutada ka mikrokontrollerivälist signaali (inglise keeles //external clock source//). Selleks on AVR mikrokontrolleril Tn viik, kus n tähistab loenduri numbrit. Välist taktsignaali ja polaarsust saab valida sagedusjaguri registriga. | В качестве тактового сигнала счётчика можно использовать внешний сигнал микроконтроллера (англ. //external clock source//). Для этого на AVR имеется вывод Tn, где n обозначает номер счётчика. Внешний сигнал такта и полярность можно выбрать с помощью регистра делителя частоты. |
| |
| ==== Sündmuste mõõtmine ==== | ==== Измерение событий ==== |
| |
| Kuna loendurid võimaldavad mõõta aega, on keerukamatel AVR mikrokontrolleritel võimalus riistvaraliselt mõõta ka aega, mil toimus mingi sündmus. Seda loenduri osa nimetatakse sündmuse püüdjaks (inglise keeles //input capture unit//). AVR-is on valida kahe sündmuse vahel: spetsiaalse sisendviigu või analoogkomparaatori võrdlustulemuse loogilise väärtuse muutus. Kui toimub valitud sündmus, kirjutatakse loenduri väärtus spetsiaalsesse registrisse, kust selle võib soovitud ajal välja lugeda. Kui sündmuse toimumise aeg on pikem kui loenduri ületäitumise aeg, tuleb tarkvaraliselt lugeda ka loenduri ületäitumisi (näiteks ületäitumise katkestusega) ja need lõpptulemusse arvestada. | Так как счётчики позволяют измерять время, на более сложных микроконтроллерах AVR есть возможность с помощью аппаратного обеспечения измерить время, в которое произошло какое-либо событие. Эта часть счётчика называется фиксатором событий (англ. //input capture unit//). В AVR есть возможность выбора между двумя событиями: изменение логического значения результатов сравнения специального входного вывода или аналогового компаратора. Если происходит выбранное событие, значение счётчика записывается в специальный регистр, где его можно вычитать в желаемое время. Если время происхождения события длиннее, чем время переполнения счётчика, следует программно считать и переполнения счётчика (например, прерыванием переполнений) и учесть их в конечном результате. |
| |
| <box 100% round #EEEEEE|Näide> | <box 100% round #EEEEEE|Пример> |
| |
| 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. | Требуется при помощи работающего на тактовой частоте в 8 MHz ATmega128 измерить частоту внешнего 122 Hz - 100 kHz логического прямоугольного сигнала с точностью в 1 Hz. Программа использует фиксатор событий 16-битного счётчика 1. |
| |
| <code c> | <code c> |
| unsigned long frequency; | unsigned long frequency; |
| |
| // Sündmuse toimumise katkestus | // Прерывание совершения событий |
| ISR(TIMER1_CAPT_vect) | ISR(TIMER1_CAPT_vect) |
| { | { |
| // Loenduri nullimine | // Обнуление счётчика |
| TCNT1 = 0; | TCNT1 = 0; |
| |
| // Tulemus on ainult siis arvestatav, kui | // Результат является истинным только в случае, |
| // loendur pole vahepeal üle täitunud | // если счётчик не переполнялся |
| if (!(TIFR & (1 << TOV1))) | if (!(TIFR & (1 << TOV1))) |
| { | { |
| // Sageduse arvutamine perioodi pöördväärtusest. | // Расчёт частоты из обратной величины периода. |
| frequency = (unsigned long)8000000 / | frequency = (unsigned long)8000000 / |
| (unsigned long)ICR1; | (unsigned long)ICR1; |
| else | else |
| { | { |
| // Sagedus on vähem kui 122 Hz | // Частота меньше, чем 122 Hz |
| frequency = 0; | frequency = 0; |
| |
| // Loenduri ületäitumise lipukese nullimine | // Обнуление флага при переполнении счётчика |
| TIFR &= ~(1 << TOV1); | TIFR &= ~(1 << TOV1); |
| } | } |
| int main() | int main() |
| { | { |
| // Tõusva frondi registreerimine, sagedusjaguri tegur 1 | // Регистрация нарастающего фронта, коэффициент делителя частоты 1 |
| TCCR1B = (1 << ICES1) | (1 << CS10); | TCCR1B = (1 << ICES1) | (1 << CS10); |
| |
| // Sündmuse toimumise katkestuse lubamine | // Разрешение прерывания совершения события |
| TIMSK = (1 << TICIE1); | TIMSK = (1 << TICIE1); |
| |
| // Globaalne katkestuste lubamine | // Разрешение глобальных прерываний |
| sei(); | sei(); |
| |
| // Lõputu programmitsükkel | // Бесконечный цикл программы |
| while (1) continue; | while (1) continue; |
| } | } |
| </code> | </code> |
| |
| Programmis tekib välise signaali tõusva frondi ajal sündmuse katkestus. Katkestuse jooksul kontrollitakse, ega loenduri ületäitumine pole toimunud - see saab juhtuda, kui signaali sagedus on alla 122 Hz (8 MHz / 2<sup>16</sup>), ja sel juhul ei kajasta loenduri väärtus reaalset perioodi. Sagedus arvutatakse 32-bitiste arvudega pöördväärtusena perioodist. Esimese asjana aga nullitakse loendur, sest taimer töötab samal taktil mis protsessor ja iga instruktsiooni täitmine, mis toimub pärast välist sündmust, lühendab mõõdetavat perioodi ning sellest tulenevalt rikub ka mõõtetulemust. Maksimaalsele mõõdetavale sagedusele seab piiri katkestuse programmiosa tööaeg. | В программе происходит прерывание события во время нарастающего фронта внешнего сигнала. Во время прерывания проверяется, не произошло ли переполнение счётчика – это может случиться, если частота сигнала меньше 122 Hz (8 MHz / 2<sup>16</sup>), и в таком случае значение счётчика не отображает реальный период. Частота высчитывается с помощью 32-битных чисел для получения обратной величиной периода. Первым делом обнуляется счётчик, так как таймер работает на том же такте, что и процессор и выполнение каждой инструкции, которая происходит после внешнего события, уменьшает измеряемый период и, исходя из этого, искажает результат измерения. Рабочее время отрезка программы прерывания ограничивает максимальную измеряемую частоту. |
| |
| </box> | </box> |
| |
| 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, saab tekitada katkestuse ja spetsiaalsete väljundviikude oleku muutuse. Valida on võrdusmomendil viigu kõrgeks muutumise, madalaks muutumise ja ümbermuutumise vahel. Väljundviigu oleku muutused tekitavadki signaali. | С помощью более сложных счётчиков можно помимо измерения длинны сигнала так же создавать сигналы. Для этого у счётчика есть компаратор (блок сравнения) значений (англ. //output compare unit//) и блок вывода результатов сравнения (англ. //compare match output unit//). Регистры компаратора имеют ту же битовую ширину, что и сам счётчик и значения их регистров сравниваются со значениями счётчика во время его работы. В тот момент, когда значение регистра компаратора сравняется со значением счётчика, можно совершить прерывание и изменение состояния специальных выходных выводов. В момент сравнения вывод может быть установлен в высокое, низкое или обратное положение. Изменения состояния выходного вывода генерируют сигнал. |
| |
| 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, mille väärtust ületades loendur nullitakse. Seda võimalust kasutades saab eespool toodud ülesandeid täpse ajalise katkestuse tekitamise kohta lahendada, kuid mõeldud on see pigem signaali perioodi muutmiseks. Lisaks sellele on võimalik loendurit seadistada režiimi, kus see toimib nii juurde- kui mahalugemisel. | В некоторых режимах генерирования сигнала максимальное значение счётчика может быть изменено. Физическая величина счётчика остаётся такой же, но он обнуляется при превышении значения регистра сравнения. Используя эту возможность, можно решить вышеприведённые задания, но это скорее предусмотрено для изменения периода сигнала. Так же счётчик можно настроить в режим прямого (увеличение) и обратного (уменьшение) счёта. |
| |
| 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. | Счётчики, и генерируемые с их помощью режимы сигналов, являются одними из самых сложных периферических модулей в AVR. Их описание выходит за рамки данного текста, и в большинстве случаев нет необходимости знать все аспекты их использования. В связи с этим, далее приведён только один из них, наиболее распространённый в роботике, сигнал ШИМ (широтно-импульсная модуляция). Информацию об остальных можно получить в документации к AVR. |
| |
| ==== Pulsilaius-modulatsioon ==== | ==== Широтно-импульсная модуляция ==== |
| |
| Pulsilaius-modulatsioon (inglise keeles //pulse width modulation//, lühend PWM) on signaali tüüp, mille sagedus ja ühtlasi ka perioodid on konstantne (enamasti), kuid mõlema poolperioodi pikkus on muutuv. PWM signaale kasutatakse elektromehaaniliste, optiliste jms. seadmete juhtimiseks. Näiteks mudelismist tuntud servomootorite PWM signaal on 50 Hz sagedusega ja 1 ms kuni 2 ms pikkuse kõrge poolperioodiga. | ШИМ (англ. //pulse width modulation//) – это тип сигнала, частота и период (обычно), которого константен, но длинна полупериодов меняется. Сигналы ШИМ используются для управления электромеханическими, оптическими и другими приборами. Например, сервомотор, известный в моделировании, использует сигнал ШИМ с частотой в 50 Hz и высокий полупериод длинной от 1 ms до 2 ms. |
| |
| <box 100% round #EEEEEE|Näide> | <box 100% round #EEEEEE|Пример> |
| |
| 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. | Используя 8 MHz ATmega128, требуется сгенерировать два регулирующих скорость сигнала сервомотора. Выводом PB5 (OC1A) следует сгенерировать длину пульса в 1 ms и выводом PB6 (OC1B) длину пульса в 2 ms. |
| |
| <code c> | <code c> |
| int main() | int main() |
| { | { |
| // Viigud väljundiks | // Установить выводы выходами |
| DDRB |= (1 << PIN5) | (1 << PIN6); | DDRB |= (1 << PIN5) | (1 << PIN6); |
| |
| // Väljundid A ja B võrdusmomendil madalaks, | // Выходы A и B во время сравнения низкими, |
| // "Fast PWM" režiim, sagedusjagur 8 | // режим "Fast PWM", делитель частоты 8 |
| TCCR1A = (1 << COM1A1) | (1 << COM1B1) | (1 << WGM11); | TCCR1A = (1 << COM1A1) | (1 << COM1B1) | (1 << WGM11); |
| TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS11); | TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS11); |
| |
| // Suurim loenduri väärtus. Valem: | // Наибольшее значение счётчика. Формула: |
| // TOP = 8 MHz / 8 / 50 Hz | // TOP = 8 MHz / 8 / 50 Hz |
| ICR1 = 20000; | ICR1 = 20000; |
| |
| // Esimese mootori poolperiood 1 ms, teisel 2 ms | // Полупериод первого мотора 1 ms, второго 2 ms |
| OCR1A = 1000; | OCR1A = 1000; |
| OCR1B = 2000; | OCR1B = 2000; |
| |
| // Lõputu programmitsükkel | // Бесконечный цикл программы |
| while (1) continue; | while (1) continue; |
| } | } |