Микроконтроллер LGT8F328P содержит 4-е таймера, Timer_1 и Timer_3 16 бит, а Timer_0 и Timer_2 8 бит.
Использование таймеров позволяет вызывать прерывание микроконтроллера для выполнения определенного фрагмента кода через заранее установленное время. Например необходимо мигать светодиодом каждую секунду, таймер будет запускать каждую секунду фрагмент кода отвечающего за мигание светодиода, в независимости от действия основной программы.
Все таймеры содержат счетный регистр TCNT который считает тактовые импульсы до определенной величины (зависит от размера), при достижении предельного числа счетчик переполняется и сбрасывается обратно в ноль. Таймер устанавливает бит флага, давая знать, что переполнение произошло, при этом вызывается прерывание.
Источником тактового сигнала для таймера/счетчика может быть как тактовый сигнал используемый для всего микроконтроллера с использованием предделителя, так и сигнал, поступающий с внешнего входа.
Для того чтобы использовать эти таймеры нужно использовать регистры настроек. Каждый таймер содержат несколько таких регистров, как именно использовать эти регистры и режимы работы таймеров будет описано в этой статье.
Режим CTC (сброс при совпадении)
Режим работы таймера CTC (сброс при совпадении) это когда в регистр OCR микроконтроллера загружается число, а счетный регистр TCNT сравнивает свое значение с числом регистра OCR и при совпадении происходит прерывание и сброс счетного регистра TCNT. При этом в обработчик прерывания исполняет помещенный в него код.
Для примера использования таймера выберем 16 битный таймер Timer_1.
Для настройки таймера в данном примере используется 3 регистра:
- TCCR1B — Регистр управления B
- OCR1A — Регистр сравнения А выходных данных
- TIMSK1 — Регистр маски прерываний счетчика/таймера
Пример скетча:
void setup() { pinMode(12, OUTPUT); noInterrupts(); TCNT1 = 0; TCCR1A = 0; TCCR1C = 0; byte n = 5; // clksys / 1 = 1 // clksys / 8 = 2 // clksys / 64 = 3 // clksys / 256 = 4 // clksys / 1024 = 5 // [CS12:CS10] TCCR1B = (1 << WGM12) | n; OCR1A = 9999;// 0-65535 TIMSK1 |= (1 << OCIE1A); // f_ctc = f_sys / (2 * n * (1 + OCR1A)) // 32 000 000 / (2 * 1024 * (1 + 9999)) = 1.5625 Hz interrupts(); } void loop() {} ISR(TIMER1_COMPA_vect){digitalWrite(12, !digitalRead(12));}
Подключите светодиод (через резистор 200 Ом) к выходу D12. После загрузки скетча светодиод начнет мигать с частотой 1,5625 Гц.
TCCR1B
В регистре управления используем бит WGW12 и биты CS10:CS12.
WGW12 активирует режим СТС
CS10:CS12 предделитель который делит тактовую частоту микроконтроллера
OCR1A
16-и битный регистр сравнения, содержит два 8-и битных регистра: OCR1AL и OCR1AH объединены для
формирования 16-разрядного OCR1A.
TIMSK1
Бит регистра TIMSK1 OCIE1A разрешают прерывания при совпадении с A (OCR1A).
ISR(TIMER1_COMPA_vect) — функция обработчика прерывания, в нее помещается код который необходимо исполнять в режиме прерывания.
Если имеется необходимость использовать таймер для генерации импульсов (меандр), в микроконтроллере имеются выходы таймера. Для Timer_1 это выходы D9 и D10.
При совпадении регистра сравнения OCIE1A и счетного регистра состояние выхода таймера меняется на противоположное, а счетный регистр TCNT1 сбрасывается.
Ниже показан пример скетча генерации меандра, таймер работает в режиме CTC
void setup() { pinMode(9, OUTPUT); noInterrupts(); TCNT1 = 0; TCCR1A = 0; TCCR1C = 0; byte n = 5; // clksys / 1 = 1 // clksys / 8 = 2 // clksys / 64 = 3 // clksys / 256 = 4 // clksys / 1024 = 5 // [CS12:CS10] TCCR1B = (1 << WGM12) | n; OCR1A = 9999;// 0-65535 TCCR1A |= (1 << COM1A0); // f_ctc = f_sys / (2 * n * (1 + OCR1A)) // 32 000 000 / (2 * 1024 * (1 + 9999)) = 1.5625 Hz interrupts(); } void loop() {}
Бит COM1A0 регистра TCCR1A определяет режим работы таймера. Если установлен бит COM1A0 то состояние на выходе OC1A меняется на противоположное при совпадении.
В этом примере если подключить светодиод (через резистор 200 Ом) к выходу D9, то после загрузки скетча он начнет мигать с частотой 1,5625 Гц.
Калькулятор расчета значения OCR1A и предделителя в зависимости от тактовой частоты контроллера и частоты прерываний таймера.
Нормальный режим работы таймера
В нормальном режиме работы таймера можно использовать регистр сравнения OCR1A, при равенстве счетного регистра TCNT1 и регистра сравнения OCR1A происходит прерывание, но в отличии от режима СТС счетный регистр TCNT1 не сбрасывается, а увеличивает свое значение до максимального 65535 и только после этого происходит его сброс и новое прерывание.
Для нормальной работы этого режима в регистре масок прерывания TIMSK1 используются биты OCIE1A и TOIE1.
Бит OCIE1A разрешает прерывание по совпадению, а бит TOIE1 разрешает прерывание по переполнению.
При этом прерывания происходят два раза за один цикл заполнения счетного регистра TCNT1.
Пример скетча
void setup() { pinMode(12, OUTPUT); noInterrupts(); TCNT1 = 0; TCCR1A = 0; TCCR1C = 0; byte n = 5; // clksys / 1 = 1 // clksys / 8 = 2 // clksys / 64 = 3 // clksys / 256 = 4 // clksys / 1024 = 5 // [CS12:CS10] TCCR1B = n; OCR1A = 9999;// 0-65535 TIMSK1 |= (1 << OCIE1A) | (1 << TOIE1); interrupts(); } void loop() {} ISR(TIMER1_COMPA_vect){ digitalWrite(12, !digitalRead(12)); }
При обнулении счетного регистра светодиод подключенный к D12 (через резистор 200 Ом) загорается, как только значение счетного регистра станет равным значению регистра сравнения, светодиод погаснет и не будет светится пока значение счетного регистра не достигнет максимального значения.
Период работы прерывания при переполнении счетного регистра равен:
Tпереполнения = 1/(f sys / (2 * N * 65536))
Период работы прерывания при совпадении равен:
Tсовпадения = 1/(f_sys / (2 * n * (1 + OCR1A)))
В скетче установлен предделитель на 1024, значит:
Tпереполнения = 1/(32 000 000 / (2 * 1024 * 65536)) = 4,19424 с
Период работы прерывания при совпадении при OCR1A = 9999:
Tсовпадения = 1/(32 000 000 / (2 * 1024 * (1 + 9999))) = 0,64 с
Если например не использовать режим работы таймера прерывание и сбор при переполнении, то подключенный светодиод к D12 (через резистор 200 Ом), будет загораться при совпадении значений счетного регистра и регистра сравнения, а после переполнения счетного регистра и новом совпадении значений счетного регистра и регистра сравнения гаснуть.
void setup() { pinMode(12, OUTPUT); noInterrupts(); TCNT1 = 0; TCCR1A = 0; TCCR1C = 0; byte n = 5; // clksys / 1 = 1 // clksys / 8 = 2 // clksys / 64 = 3 // clksys / 256 = 4 // clksys / 1024 = 5 // [CS12:CS10] TCCR1B = n; OCR1A = 20000;// 0-65535 TIMSK1 |= (1 << OCIE1A); interrupts(); } void loop() {} ISR(TIMER1_COMPA_vect){ digitalWrite(12, !digitalRead(12)); }
Если например не использовать режим работы таймера при совпадении значений счетного регистра и регистра сравнения, то подключенный светодиод к D12 (через резистор 200 Ом), будет загораться при переполнении счетного регистра, а после гаснуть при новом переполнении счетного регистра.
void setup() { pinMode(12, OUTPUT); noInterrupts(); TCNT1 = 0; TCCR1A = 0; TCCR1C = 0; byte n = 5; // clksys / 1 = 1 // clksys / 8 = 2 // clksys / 64 = 3 // clksys / 256 = 4 // clksys / 1024 = 5 // [CS12:CS10] TCCR1B = n; TIMSK1 |= (1 << TOIE1); interrupts(); } void loop() {} ISR(TIMER1_OVF_vect){ digitalWrite(12, !digitalRead(12)); }
В нормальном режиме работы таймера можно использовать выход таймера, например если к D9 (через резистор 200 Ом) подключить светодиод, то при совпадении значений счетного регистра и регистра сравнения подключенный светодиод будет загораться и гаснуть при новом при совпадении значений счетного регистра и регистра сравнения.
Если установлен бит COM1A0 то состояние на выходе OC1A (D9) меняется на противоположное при совпадении.
void setup() { pinMode(D9, OUTPUT); noInterrupts(); TCNT1 = 0; TCCR1A = 0; TCCR1C = 0; byte n = 5; // clksys / 1 = 1 // clksys / 8 = 2 // clksys / 64 = 3 // clksys / 256 = 4 // clksys / 1024 = 5 // [CS12:CS10] TCCR1A = (1 << COM1A0); TCCR1B = n; OCR1A = 9999; interrupts(); } void loop() {}
Режим PWM (ШИМ)
Широтно-импульсная модуляция (PWM) — процесс управления мощностью методом пульсирующего включения и выключения потребителя энергии.
Основной причиной применения ШИМ является стремление к повышению КПД при построении вторичных источников питания электронной аппаратуры и в других узлах, например, ШИМ используется для регулировки яркости подсветки LED-мониторов и дисплеев в телефонах, КПК и т. п.
По сути выходной PWM сигнал в LGT8F328P это импульсный сигнал с изменяемой длительностью импульсов. Если взять период следования импульсов за 100 %, то длительность импульсов может меняться от 0 до 100%, а так как Timer_1 16 бит, то заполнение длительности импульса периода следования импульса может меняться от 0 до 65535 значений, то есть от 0 до 100%.
Режим FPWM
Режим работы FPWM определяется несколькими регистрами, а в частности регистром захвата ICR1 и регистром сравнения OCR1A.
В регистр ICR1 записывается значение которое сравнивается с счетным регистром TCNT1 и при равенстве происходит изменение состояния на выводе OC1A (D9), в данном случае появляется лог. 1, в регистре ICR1 указываем максимальное значение (зависит от разрядности).
В регистр OCR1A записывается значение которое сравнивается с счетным регистром TCNT1 и при равенстве происходит изменение состояния на выводе OC1A (D9), в данном случае появляется лог. 0.
void setup() { pinMode(D9, OUTPUT); noInterrupts(); TCNT1 = 0; TCCR1A = 0; TCCR1C = 0; byte n = 1; // clksys / 1 = 1 // clksys / 8 = 2 // clksys / 64 = 3 // clksys / 256 = 4 // clksys / 1024 = 5 // [CS12:CS10] TCCR1A = (1 << COM1A1) | (1 << WGM11); TCCR1B = (1 << WGM13) | (1 << WGM12) | n; ICR1 = 65535; OCR1A = 5000; interrupts(); } void loop() {}
Бит COM1A1 делает активным выход OC1A (D9), а биты WGM11 WGM12 WGM13 активируют режим FPWM.
Частота PWM в этом режиме определяется:
Fpwm = f sys / (N * (1 + ICR1))
Если предделитель установлен на 1, а регистр ICR1 имеет значение 65535, то:
Fpwm = 32 000 000 / (1 * (1 + 65535)) = 488,28125 Hz
Аналогично можно использовать выход Timer_1 OC1B (D10), использование которого определяет бит COM1B1, при этом используется регистр сравнения OCR1B.
void setup() { pinMode(D10, OUTPUT); noInterrupts(); TCNT1 = 0; TCCR1A = 0; TCCR1C = 0; byte n = 1; // clksys / 1 = 1 // clksys / 8 = 2 // clksys / 64 = 3 // clksys / 256 = 4 // clksys / 1024 = 5 // [CS12:CS10] TCCR1A = (1 << COM1B1) | (1 << WGM11); TCCR1B = (1 << WGM13) | (1 << WGM12) | n; ICR1 = 65535; OCR1B = 1000; interrupts(); } void loop() {}
Так же в этом режиме PWM имеется возможность инверсии выходного сигнала. Биты COM1A1 COM1A0 определяют режим работы выходного сигнала.
void setup() { pinMode(D9, OUTPUT); noInterrupts(); TCNT1 = 0; TCCR1A = 0; TCCR1C = 0; byte n = 1; // clksys / 1 = 1 // clksys / 8 = 2 // clksys / 64 = 3 // clksys / 256 = 4 // clksys / 1024 = 5 // [CS12:CS10] TCCR1A = (1 << COM1A1) | (1 << COM1A0) | (1 << WGM11); TCCR1B = (1 << WGM13) | (1 << WGM12) | n; ICR1 = 65535; OCR1A = 5000; interrupts(); } void loop() {}
Выше показаны примеры работы режима FPWM где регистр захвата ICR1 имеет максимально возможное значение 65535, при этом PWM работает в режиме 16 бит. Но регистр захвата можно указывать любое значение при условии что оно будет больше значения регистра сравнения OCR1A. При этом битность PWM будет снижена, но при этом можно значительно увеличить частоту PWM сигнала (Быстрый режим PWM).
void setup() { pinMode(D9, OUTPUT); noInterrupts(); TCNT1 = 0; TCCR1A = 0; TCCR1C = 0; byte n = 1; // clksys / 1 = 1 // clksys / 8 = 2 // clksys / 64 = 3 // clksys / 256 = 4 // clksys / 1024 = 5 // [CS12:CS10] TCCR1A = (1 << COM1A1) | (1 << WGM11); TCCR1B = (1 << WGM13) | (1 << WGM12) | n; ICR1 = 99; OCR1A = 10; interrupts(); } void loop() {}
Если предделитель установлен на 1, а регистр ICR1 имеет значение 9, то:
Fpwm = 32 000 000 / (1 * (1 + 99)) = 320000 Hz
В режиме FPWM помимо режима 16 бит и быстрого PWM имеются режимы 8, 9 и 10 бит. При этом значение регистра OCR1A не должно превышать разрядности счетного регистра TCNT1.
Режим 8 бит
void setup() { pinMode(D9, OUTPUT); noInterrupts(); TCNT1 = 0; TCCR1A = 0; TCCR1C = 0; byte n = 1; // clksys / 1 = 1 // clksys / 8 = 2 // clksys / 64 = 3 // clksys / 256 = 4 // clksys / 1024 = 5 // [CS12:CS10] TCCR1A = (1 << COM1A1) | (1 << WGM10); TCCR1B = (1 << WGM12) | n; OCR1A = 10; interrupts(); } void loop() {}
В этом режиме счетный регистр TCNT1 имеет разрядность 8 бит. При совпадении значений счетного регистра TCNT1 и регистра сравнения OCR1A, происходит изменение состояния выхода OC1A (D9), при достижении счетным регистром TCNT1 максимального значения (255) происходит сброс регистра и изменение состояния выхода OC1A (D9).
Частота PWM в этом режиме определяется:
Fpwm = f sys / (N * (1 + TOP))
где TOP = 255
Fpwm = 32 000 000 / (1 * (1 + 255)) = 125000 Hz
void setup() { pinMode(D9, OUTPUT); noInterrupts(); TCNT1 = 0; TCCR1A = 0; TCCR1C = 0; byte n = 1; // clksys / 1 = 1 // clksys / 8 = 2 // clksys / 64 = 3 // clksys / 256 = 4 // clksys / 1024 = 5 // [CS12:CS10] TCCR1A = (1 << COM1A1) | (1 << WGM11); TCCR1B = (1 << WGM12) | n; OCR1A = 500; interrupts(); } void loop() {}
В этом режиме счетный регистр TCNT1 имеет разрядность 9 бит. При совпадении значений счетного регистра TCNT1 и регистра сравнения OCR1A, происходит изменение состояния выхода OC1A (D9), при достижении счетным регистром TCNT1 максимального значения (511) происходит сброс регистра и изменение состояния выхода OC1A (D9).
Частота PWM в этом режиме определяется:
Fpwm = f sys / (N * (1 + TOP))
где TOP = 511
Fpwm = 32 000 000 / (1 * (1 + 511)) = 62500 Hz
Режим 10 бит
void setup() { pinMode(D9, OUTPUT); noInterrupts(); TCNT1 = 0; TCCR1A = 0; TCCR1C = 0; byte n = 1; // clksys / 1 = 1 // clksys / 8 = 2 // clksys / 64 = 3 // clksys / 256 = 4 // clksys / 1024 = 5 // [CS12:CS10] TCCR1A = (1 << COM1A1) | (1 << WGM11) | (1 << WGM10); TCCR1B = (1 << WGM12) | n; OCR1A = 500; interrupts(); } void loop() {}
В этом режиме счетный регистр TCNT1 имеет разрядность 10 бит. При совпадении значений счетного регистра TCNT1 и регистра сравнения OCR1A, происходит изменение состояния выхода OC1A (D9), при достижении счетным регистром TCNT1 максимального значения (1023) происходит сброс регистра и изменение состояния выхода OC1A (D9).
Частота PWM в этом режиме определяется:
Fpwm = f sys / (N * (1 + TOP))
где TOP = 1023
Fpwm = 32 000 000 / (1 * (1 + 1023)) = 31250 Hz
Режим PCPWM
ШИМ с фазовой коррекцией (PCPWM-режим) немного отличается от режима FPWM. В нем так же как FPWM режим работы определяется несколькими регистрами, а в частности регистром захвата ICR1 и регистром сравнения OCR1A. Счетный регистр TCNT1 начинает отсчет от 0 до значения установленного в регистре ICR1, но при равенстве значений регистра захвата и счетного регистра не происходит сброс счетного регистра, счетный регистр начинает отсчет в обратную строну, то есть от значения установленного в регистре ICR1 до 0. При этом при равенстве регистра сравнения и счетного регистра происходит изменение состояния выхода таймера OC1A (D9), как при прямом счете счетного регистра и при обратном.
При этом значение регистра ICR1 меняет частоту ШИМ сигнала, а значение регистра OCR1A фазу, при условии что значение регистра ICR1 всегда больше значения регистра OCR1A.
void setup() { pinMode(D9, OUTPUT); noInterrupts(); TCNT1 = 0; TCCR1A = 0; TCCR1C = 0; byte n = 1; // clksys / 1 = 1 // clksys / 8 = 2 // clksys / 64 = 3 // clksys / 256 = 4 // clksys / 1024 = 5 // [CS12:CS10] TCCR1A = (1 << COM1A1) | (1 << WGM11); TCCR1B = (1 << WGM13) | n; ICR1 = 1000; OCR1A = 100; interrupts(); } void loop() {}
При этом частота ШИМ сигнала рассчитывает по следующей формуле:
Fшим = f_sys / (N * TOP * 2)
где TOP это значение регистра ICR1, которое может быть в пределах от значения регистра OCR1A+1 до 65535. Если значение регистра ICR1 равно 65535, то таймер работает в режиме 16 бит, если значение ниже 65535, то таймер работает с пониженной разрядностью.
Если ICR1 = 1000, а предделитель установлен на 1, частота ШИМ равна:
Fшим = 32 000 000 / (1 * 1000 * 2) = 16000 Hz
В режиме PCPWM доступны режимы работы таймера 8, 9 и 10 бит. При этом регистр ICR1 не используется, максимальное значение счетного регистра TCNT1 определяется разрядностью режима работы таймера.
Пример работы таймера в режиме фазовой коррекцией, 8 бит:
void setup() { pinMode(D9, OUTPUT); noInterrupts(); TCNT1 = 0; TCCR1A = 0; TCCR1C = 0; byte n = 1; // clksys / 1 = 1 // clksys / 8 = 2 // clksys / 64 = 3 // clksys / 256 = 4 // clksys / 1024 = 5 // [CS12:CS10] TCCR1A = (1 << COM1A1) | (1 << WGM10); TCCR1B = n; OCR1A = 10; interrupts(); } void loop() {}
Пример работы таймера в режиме фазовой коррекцией, 9 бит:
void setup() { pinMode(D9, OUTPUT); noInterrupts(); TCNT1 = 0; TCCR1A = 0; TCCR1C = 0; byte n = 1; // clksys / 1 = 1 // clksys / 8 = 2 // clksys / 64 = 3 // clksys / 256 = 4 // clksys / 1024 = 5 // [CS12:CS10] TCCR1A = (1 << COM1A1) | (1 << WGM11); TCCR1B = n; OCR1A = 500; interrupts(); } void loop() {}
Пример работы таймера в режиме фазовой коррекцией, 10 бит:
void setup() { pinMode(D9, OUTPUT); noInterrupts(); TCNT1 = 0; TCCR1A = 0; TCCR1C = 0; byte n = 1; // clksys / 1 = 1 // clksys / 8 = 2 // clksys / 64 = 3 // clksys / 256 = 4 // clksys / 1024 = 5 // [CS12:CS10] TCCR1A = (1 << COM1A1) | (1 << WGM11)| (1 << WGM10); TCCR1B = n; OCR1A = 20; interrupts(); } void loop() {}
В таймере используются два регистра сравнения для канала А и канала B, что дает возможность одновременно управлять работой выходов Timer_1.
Основное условие для правильной работы такого режима в том, что значение регистра OCR1B должно быть больше значения регистра OCR1A.
Ниже показан пример позволяющий изменять длительность импульса по двум выходам одновременно в режиме FPWM.
Выходы Timer_1 это OC1A и OC1B, что соответствует выходам D9 и D10.
void setup() { pinMode(D9, OUTPUT); pinMode(D10, OUTPUT); noInterrupts(); TCNT1 = 0; TCCR1A = 0; TCCR1C = 0; byte n = 1; // clksys / 1 = 1 // clksys / 8 = 2 // clksys / 64 = 3 // clksys / 256 = 4 // clksys / 1024 = 5 // [CS12:CS10] TCCR1A = (1 << COM1A1) | (1 << COM1B1) | (1 << WGM11); TCCR1B = (1 << WGM13) | (1 << WGM12) |n; ICR1 = 54000; OCR1A = 1000; OCR1B = 50000; interrupts(); } void loop() {}
Если подключить подключить светодиоды (через резисторы 200 Ом) к выхода D9 D10, то яркость свечения каждого светодиода будет зависть от значения регистров OCR1A и OCR1B.
Аналогично работает таймер в режиме PCPWM:
void setup() { pinMode(D9, OUTPUT); pinMode(D10, OUTPUT); noInterrupts(); TCNT1 = 0; TCCR1A = 0; TCCR1C = 0; byte n = 1; // clksys / 1 = 1 // clksys / 8 = 2 // clksys / 64 = 3 // clksys / 256 = 4 // clksys / 1024 = 5 // [CS12:CS10] TCCR1A = (1 << COM1A1) | (1 << COM1B1) | (1 << WGM11); TCCR1B = (1 << WGM13) |n; ICR1 = 54000; OCR1A = 1000; OCR1B = 50000; interrupts(); } void loop() {}
Ниже показан пример работы таймера в режиме CTC, используются оба канала А и В, а так же используется регистр захвата ICR1.
В данном режиме значение регистра OCR1B может быть больше значения регистра OCR1A и наоборот.
В одном цикле работы счетного регистра TCNT1 максимальное значение которого ограничено регистром ICR1, происходит три прерывания.
Ниже показан скетч демонстрирующий работу такого режима:
unsigned long times; void setup() { Serial.begin(9600); noInterrupts(); TCNT1 = 0; TCCR1A = 0; TCCR1C = 0; byte n = 5; // clksys / 1 = 1 // clksys / 8 = 2 // clksys / 64 = 3 // clksys / 256 = 4 // clksys / 1024 = 5 // [CS12:CS10] TCCR1B = (1 << WGM13) | (1 << WGM12) | n; TIMSK1 = (1 << ICIE1) | (1 << OCIE1A) | (1 << OCIE1B); OCR1A = 40000; OCR1B = 1000; ICR1 = 65535; interrupts(); } void loop() {} ISR(TIMER1_COMPA_vect) { Serial.print("a = ");Serial.println(millis()-times); } ISR(TIMER1_COMPB_vect) { Serial.print("b = ");Serial.println(millis()-times); times=millis(); } ISR(TIMER1_CAPT_vect) { Serial.print("T = ");Serial.println(millis()-times); times=millis(); Serial.println(); }
Как выше сказано, в примере используется три прерывания и для каждого использован свой обработчик прерывания. В каждом обработчике прерывания для демонстрации работы таймера фиксируется время прерывания, сначала для канала B, потом для канал А и в конце время прерывания вызванного регистром захвата ICR1, после происходит обнуление счетчика времени.
Как видно на скриншоте на одном таймере можно использовать три обработчика прерывания и в каждом будет исполняться свой код.
В заключении хотелось бы отметь, что в статье описаны далеко не все возможности таймеров, а только коротко основные режимы.