Правильное включение таймеров T2, T3, T4, T5
- Войдите на сайт для отправки комментариев
Здравствуйте! Прошу помощи по работе Таймеров на Arduino Mega. Вопрос в том, что могу ли я, например, в обработчике прерывания переполнения Таймера_2 отключить работу Т2 и включить в работу Таймер Т3? Хочу, чтобы код работал следующим образом: циклически цепочкой работают по очереди таймеры 2, 3, 4, 5.
1) Таймер_2 работает, моргает PORTC_4 пару раз, отображает светодиодом на пине PORTC_0 свою работу.
2) В прерывании переполнения Таймер_2 выключаем TCCR2B = 0x00; TIMSK2 = 0x00; , гасим светодиод PORTC_0. В этом же прерывании включаем Таймер_3, зажигаем светодиод PORTC_1, отображающий работу Таймера_3, моргаем уже PORTC_5...
3) Далее по кругу T3 --> T4; T4 --> T5; T5 --> T2; .......
В моём коде работает только Таймер Т2,(светится только диод PORTC_0, моргает только PORTC_4) я так понимаю Т3 не инициализируется в обработке прерывания Т2.
Прилагаю код:
#include "Main_Var.h" ISR(TIMER2_OVF_vect) {// вкл диод индикатирующий работающий Таймер_2 PORTC &= ~(1 << 0); count_led++; // ********* блок моргания PORTC_4 ********* if (count_led == 183) count_led = 0; if (count_led < 90) {PORTC |= (1 << 4);} else PORTC &= ~(1 << 4); // блок отслеживания переполнения переменной count_T2, // выключения Таймера_2 и // последующего включения Таймера_3 count_T2++; if (count_T2 == 550) // {count_T2 = 0; TCCR3B = 0x01; // clk/1 TIMSK3 = 0x01; // вкл Таймер_3 TCCR2B = 0x00; // откл TIMSK2 = 0x00; // Таймер_2 count_led = 0; // ВЫКЛ диод отображающий работающий Таймер_2 PORTC |= (1 << 0); } } ISR(TIMER3_OVF_vect) {// вкл диод индикатирующий работающий Таймер_3 PORTC &= ~(1 << 1); count_led++; // ********* блок моргания PORTC_5 ********* if (count_led == 183) count_led = 0; if (count_led < 90) PORTC |= (1 << 5); else PORTC &= ~(1 << 5); // блок отслеживания и выключения Таймера_3 и // последующего включения Таймера_4 count_T3++; if (count_T3 == 550) {count_T3 = 0; TCCR4B = 0x01; TIMSK4 = 0x01; TCCR3B = 0x00; TIMSK3 = 0x00; count_led = 0; // ВЫКЛ диод индикатирующий работающий Таймер_3 PORTC |= (1 << 1); } } ISR(TIMER4_OVF_vect) {PORTC &= ~(1 << 2); count_led++; if (count_led == 183) count_led = 0; if (count_led < 90) PORTC |= (1 << 6); else PORTC &= ~(1 << 6); count_T4++; if (count_T4 == 550) {count_T4 = 0; TCCR5B = 0x01; TIMSK5 = 0x01; TCCR4B = 0x00; TIMSK4 = 0x00; count_led = 0; PORTC |= (1 << 2); } } ISR(TIMER5_OVF_vect) {PORTC &= ~(1 << 3); count_led++; if (count_led == 183) count_led = 0; if (count_led < 90) PORTC |= (1 << 7); else PORTC &= ~(1 << 7); count_T5++; if (count_T5 == 550) {count_T5 = 0; TCCR2B = 0x06; TIMSK2 = 0x01; TCCR5B = 0x00; TIMSK5 = 0x00; count_led = 0; PORTC |= (1 << 3); } }
Пункт 2 чуток неверно написал...
В прерывании ISR(TIMER2_OVF_vect) откл T2, вкл T3 и уже в ISR(TIMER3_OVF_vect) зажигаем PORTC_1 и моргаем PORTC_5
Не наблюдаю описания переменных.
И вообще, я даже написал так
Далее должен работать Таймер Т3, но этого не происходит - горит диод только PORTC_0, отображающий работу Таймера Т2...
Это файл Main_Var.h
Во-первых - volatile утеряно, во-вторых - посмотрите, каково максимальное значение для восьмибитной переменной.
Точно, теперь всё работает!!! Спасибо большое за помощь! А то у меня чуток опыта не хватает, тормоз происходит на "детских ошибках" )
Ну и как count_T2 может стать равен 550 если максимум на что он способен это 255?
Теперь у меня ещё один вопрос по Таймерам... Допустим написал такую функцию:
Допустим, моя же ситуация с моим кодом, приведённым выше, один таймер выкл/вкл другой таймер.
Насколько я понимаю, командой TCCR1B = 0x00; я отключаю тактирование Таймера Т1, --> Т1 останавливается.
1) Регистры TCNT1H и TCNT1L остаются в тех значениях, до которых они досчитались, верно? Теперь при следующем включении Таймера Т1 отсчёт начинается с этих значений? Тогда мне нужно принудительно обнулять эти регистры?
Командой TIMSK1 = 0x00; я отключаю возможность вызова обработчика прерывания по переполнению Т1.
2) Если я не выполняю эту команду (TIMSK1 = 0x00;) И, допустим, во время выполнения какого-нибудь обработчика прерывания (например ISR(TIMER3_COMPA_vect)) установился флаг переполнения Таймера Т1, то после выполнения обработчика ISR(TIMER3_COMPA_vect) запустится обработчик ISR(TIMER1_OVF_vect). Тогда, чтобы этого не произошло, я принудительно сбрасываю флаг TOV1 командой TIFR1 |= (1 << 0);. Я правильно понимаю это всё?
Спасибо!
1) Регистры TCNT1H и TCNT1L остаются в тех значениях, до которых они досчитались, верно? Теперь при следующем включении Таймера Т1 отсчёт начинается с этих значений? Тогда мне нужно принудительно обнулять эти регистры?
Положим, что значение регистров после остановки таймера можно проверить и убедиться насчёт того, в каком положении они застывают.
Однако, в ходе экспериментов в Correct Phase PWM mode у меня сложилось впечатление, что при запуске таймера счёт всегда начинается с BOTTOM. Но никаких документальных подтверждений этому факту я пока не видел.
Строго говоря - поведение определяется тем состоянием TIMSKn, которое было до момента, когда не был выполнен его сброс.
А так - всё звучит логично.
Строго говоря - поведение определяется тем состоянием TIMSKn, которое было до момента, когда не был выполнен его сброс.
Немного не понял Вашу мысль, можно по-подробнее... Моя в простом понимании TOV1 = 1, будет обработчик, TOV1 = 0, обработчика не будет.
Мысль проста - если где-то и когда-то (вне функции "остановки") TOV был разрешён (или запрещён), а TIMSKn его не замаскировало (не выполнено TIMSKn = 0x00), то его состояние определяется тем моментом, когда последний раз изменялся регистр TIMSK.
Провёл эксперимент с о счётчиком таймера:
Начинает идти с того момента, на котором остановили тактирование: