Помогите разобраться с работой прерываниями и таймерами
- Войдите на сайт для отправки комментариев
Пнд, 22/06/2015 - 17:39
Понадобился пид регулятор, быстренько скидал из валявшихся ардуинки мини и какого-то термосопротивления от чайника-термоса. Все работало, пока работал блок питания 12в 25А. а когда блок крякнул, решил обойтись без него, а с помощью симистора и фазного вместо шим регулятора. Потому, как всегда хотелось попробовать, да и с прерываниями, когда-то надо начинать разбираться, вот и начал пробовать. Но столкнулся с непонятной мне проблемой: даже не запуская прерывание, перестаёт работать ком порт. При запуске монитора порта пишет одну кракозюльку и молчит зараза. Подскажите, куда рыть или ткните носом в ошибки. Спасибо.
/*После импульса запуска на PD0(INT0) срабатывает прерывание, запоминает время и запускает timer2 на tcnt циклов. При достижении этого времени вектор ISR(TIMER1_OVF_vect)выдает импульс на ноге tir (PB7)длительностью 30 миллисекунд и останавливает таймер до следующего прерывания INT0.*/ #include <Arduino.h> byte tcntValue = 10; unsigned int tcnt, pause = 30; #define synh PD0 //синхро импульс перехода через 0 #define tir PB7 //импульс управление симистором //------------------------------------------------------------------ //------------------------------------------------------------------Срабатывает при синхро импульсе ISR(INT0_vect) // Функция обработки прерывания INT0 { TCCR1B = (0<<CS12)|(1<<CS11)|(1<<CS10); // настраиваем делитель tcnt = TCNT1; //выставляем начальное значение TCNT1 TCNT1 = tcnt + tcntValue; } //------------------------------------------------------------------ //------------------------------------------------------------------Через нужное время включает тиристор ISR( TIMER1_OVF_vect ) { PORTB |= ( 1 << tir ); //Передний фронт отпирающего импульса симистора //delayMicroseconds(pause); //Длительность отпирающего импульса PORTB &= ~( 1 << tir ); //Задний фронт отпирающего импульса симистора TCCR1B = TCNT1 = 0; //остановка и обнуление таймера 0 } //------------------------------------------------------------------ //------------------------------------------------------------------ void setup() { Serial.begin(9600); Serial.println("1"); //---------------------------//настраиваем порты для управления симистора DDRB = ( 1 << tir ); // настраиваем tir на выход PORTB &= ~( 1 << tir ); //гасим светодиод DDRD &= ~_BV(synh); //вход детектора нуля PORTD |= _BV(synh); //с подтягивающим резистором для питания транзистора оптрона Serial.println("2"); //------------------------------------------------------------------ //---------------------------//настраиваем внешнее прерывание MCUCR |= _BV(ISC00); //внешнее прерывание 0 по любому изменению уровня EIMSK &= ~ (1 << INT0); // Запретить прерывание (так как следующая команда устанавливает режим INT0_SENSE_LOW_LEVEL) EICRA &= ~ (1 << ISC00) | (1 << ISC01); // Обнуляем биты ISC00 и ISC01 в регистре EICRA EICRA |= 1; EIMSK |= (1 << INT0); //разрешаем внешнее прерывание 0 Serial.println("3"); //------------------------------------------------------------------ //---------------------------//настраиваем прерывание на таймер TCCR2B = (0<<CS12)|(1<<CS11)|(1<<CS10); // настраиваем делитель //SREG|=(1<<7); // Глобальное разрешение прерываний. TIMSK2 |= (1<<TOIE2); // разрешаем прерывание по переполнению таймера tcnt = TCNT2; //выставляем начальное значение TCNT2 TCNT2 = tcntValue + tcnt; // выставляем начальное значение TCNT2 // разрешение прерываний INT0 и INT1 Serial.println("4"); EIMSK = (1<<INT2); // выставляем бит общего разрешения прерываний //*/ Serial.println("Hi"); //Настраиваем ноги камня DDRC = 255; DDRB = 255; } void loop() { Serial.println("Press button"); }
не понятно. В процедуре обработчика у вас пользуется 1-й таймер, а в коде setup() - 2-й. И ещё нигде не увидел в какой режим ставятся оба счетчика (TCCR1A, TCCR2A) ... так надо?
Извините, этот пример выдирал из уже написанной программы, а так как начал использовать в начале timer1, а потом решил перейти на
timer2, то правил уже прямо в коментах на сайте, ну и как всегда проглядел. А режим таймера - это мой косяк, исправил, но ничего не изменилось.
Какой у вас контроллер?
Было все собранно на ардуино мини, а отладку делаю (чтобы не разбирать) на мега2560.
Читаю описание меги 2560 на этом-же сайте:
Что-то всё это меня совсем в заблуждение ввело. Если ипользую interrupt то INT0, а если через регистры то INT2. Или как всё это понимать, и к какой наге прикручивать synh ? Во путаница, кто знает, как правильно?
Эт вы круто... отладка на одном камне а работать будет на другом? О.о
не в первой, постоянно так делаю, а чего тут такого. мега 2560 одна, а мини по необходимости сам делаю.
Ну даже не знаю. Как бы атмега328 и атмега2560 это конечно avr. Но как бы это разные камни.
Давай на этом заморачиваться не будем, это моя проблема (вообще не проблема). А сделаем на меги2560, чтобы всё работало. Лучше с кодом помогите, 3-й день голову грею.
И вообще не мега328, а мега8 :))
Если закоментировать 58 строку, то
Serial
.print
начинает работать как надо. Какая связь прерывания и порта?????Да эту строку. В порт посыл сразу идёт как надо, но вся моя фазная регулировка не работает, а с разкомментированной строкой вроде (смотрю осциллографом) как работает. Или или, а хочу, чтобы всё работало.
Внимательно посмотрите на свою 58 строку и на строку из #12 сообщения.
Ну и зачем такое советовать? Что 58-я строка, что строка в сообщении №12 - абсолютно идентичны. :)
Может посоветовать сравнить пару 44, 47 ... с одной 58 строкой? :)
Не, дело не в этом, комментирую эту строку, получаю сообщения в порт как надо, а нет - только единичку.
= и |= менял, бестолку.
Логически: этот регистр разрешает прерывания, я разрешаю только INT2. Как прирывание INT2 может влиять на работу ком порта? Или если судить из сообщения №5, это не INT2, a INT0. И ещё,
какое прерывание использует (если использует)?
Serial
Посмотрел в даташит. Ответ - "легко". Wiring, инициализируя Serial на меге, активирует ВСЕ 4 USART. посмотрите внимательно на тексты при компиляции скетчей: и легко обнаружите компиляцию файлов Serial0, ..1, ..2, ..3. Только вот как раз ваше INT2 - это одна из ног одного из USART.
Как думаю, что активируя прерывание "ручками" скорее всего надо ещё прописывать ноги в правильные режимы в setup() после отработки стандартного init()... или @выбросить" wiring.c (init() - лежит в ней и смотреть чего там происходит с ногами USART-ов надо в нем)...
Набрал попкорна и уселся смотреть как ща тут великий архат разрулит.
Сейчас видимо побежал на другой форум консультироваться. :)
Ну и зачем такое советовать? Что 58-я строка, что строка в сообщении №12 - абсолютно идентичны. :)
Может посоветовать сравнить пару 44, 47 ... с одной 58 строкой? :)
и
при это выше делается следующее
Не, дело не в этом, комментирую эту строку, получаю сообщения в порт как надо, а нет - только единичку.
= и |= менял, бестолку.
Писалось это когда то для атмеги328
и даже работало.
А и еще, тут реализовывал компенсацию детекции перехода через ноль оптроном, так что для вашего оптрона с резисторами она скорее всего будет другой.
maksim Спасибо за пример. Если вы не против, взял его за основу. Дополнил коментами для понимания, если не трудно, прочитайте - правильно я понимаю ваш код. Serial работает, а остальное узнаю, когда переделаю на mega8 и вставлю в свою прогу.
Не, немного не так, включение перепутано с выключением. Прерывание срабатывает по заднему фронту (falling).
Дело в том, что сисмистор нельзя закрыть в любой момент, а открыть можно. У него есть такая характеристика как "ток залипания", то есть при определенном токе симистор просто не закрывается. Поэтому регулирование происходит так, что срезается передняя часть синусоиды, а не задняя. Ловим 0, сначала держим симистор закрытым, открываем и закрываем при переходе через 0.
То есть:
1. Симистор закрыт;
2. Поймали фронт перехода через ноль, а точнее задний фронт с оптрона, наступающий чуть позже, чем сам переход;
3. Отсчитали нужное время ,по совпадению COMPA открыли симистор;
4. Закрыли симистор при переходе через 0 по совпадению COMPB.
И так по кругу.
Я так понимаю, здесь в порт запишется 0 PORTB |= 1<<TRIAC; //выключили симистор
а здесь - единица PORTB &= ~(1<<TRIAC);//включили симистор
а как железо работает, я знаю. Мне бы только программки писать научиться :))
Нет, не правильно понимаете, все наоборот. Как оно работает написано выше.
Вот эта t (без учета того, что 0 детектируется чуть позже) и есть COMPA (cur_dim), и именно по истечению этой t симстор открывается (включается) PORTB |= 1<<TRIAC;
Такие диаграммы я могу нарисовать и для 3-х фазного, и даже для 6 фазного регулирования, и понимаю, что для чего, просто выражение PORTB |= 1<<0;
мне кажется, что в порт запишет 0, или у вас на опто паре, которая управляет симистором, светодиод к +5в подвешан?
Ровно наоборот, выражение:
PORTB |= 1<<const;
читается как 1 сдвинуть влево на const бит, и добавить к значению в порту. То бишь, "установить 1 в бите const не меняя остальных битов порта"
:)
просто выражение PORTB |= 1<<0; мне кажется, что в порт запишет 0, или у вас на опто паре, которая управляет симистором, светодиод к +5в подвешан?
Нет, запишет в PB0 единицу. Чтобы было понятней, можно записать так:
PORTB |= 1<<PB0; (установить PB0 в единицу)
PORTB &= ~(1<<PB0); (сбросить PB0 в ноль)
Если совсем всё непонятно - читайте про битовые операции и сдвиг.
Извините, точно сдвигаем на ноль и выставляем 1, а я по запарке читал - сдвигаем на 1 и выставляем 0.
Для проверки и настройки, если вход с выходом соединить и изменить немного прогу, будет работать?
у меня чего-то не работает.
Ну вы бы тогда хотябы схему с номиналами показали.
А при таком раскладе схемки никакой нет, есть кусок провода с PB0 до PD1. надо только вручную запустить кандюком кратковременно на +5в, срабатывает прерывание, запускает таймер, таймер через заданное время моргает портом, и тем самым снова запускает прерывание. Но если к проводу подцепить осциллограф, то все временные циклы можно подглядеть, если все работает.
А работает всё это странно. ||||__||||__|||| Это по умолчанию, если уменьшаем cur_dim, увеличивается количество импульсов. Если изменяем TCNT1, то всё пропадает и не запускается, и всегда показывает частоту 161 герц. Делителем частота меняется. Я так понимаю, изменяя cur_dim, должно плавно меняться расстояние между импульсами, и не должно быть пауз. Или не так?
Это вы уже херней какой то занимаетесь, не будет так оно работать. Тогда уж если хотите проверить как оно работает, запустите на другом таймере или другой дуине генератор импульсов на 100 Гц и смотрите осцилографом что будет идти на симистор.
Можно и генератор, а в чем разница? И так работает.