Запуск таймера1 по внешнему прерыванию int0
- Войдите на сайт для отправки комментариев
Доброго дня ! Никак не запущу код. Помогите. Как только подаю сигнал на int0 кнопка Пуск-Стоп перестаёт работать, на дисплее моргание, светодиод на плате (горящий в режиме РАБОТА) горит постоянно. Задача сделать синхронизацию по внешнему прерыванию. 1. При смене уровня на входе int0 должен запускаться таймер1 на 1мс. Работает по совпадению. 2. Если при считающем таймере1 не появится сигнал смены уровня на входе int0, таймер досчитывает до 1 мс, обнуляется, останавливается. Затем цикл повторяется. 3. Если при считающем таймере1 появится сигнал смены уровня на входе int0, то таймер обнуляется, останавливается и выставляется флаг FlagSynhro = true. Считаем, что нашли момент синхронизации.
#include <LiquidCrystal.h> const int ENABLEWORK = 4; //Вход разрешения работы Pin D4 const int Zar = 12; //Выход на ключ заряда const int Razr = 5; //Выход на ключ разряда const int Led = 13; //Выход на светодиод int Cicl = 0; // указатель цикла работы обнулён int currentENABLEWORK = HIGH; boolean FlagWork = false, FlagSynhro = false; volatile boolean Flagint0 = false, StartTimer = false; volatile int nom = 1; // пустой код по умолчанию LiquidCrystal lcd(6, 7, 8, 9, 10, 11); //выводы подключены void setup () { cli(); // отключить глобальные прерывания lcd.begin(16, 2); // 1602 дисплей lcd.print("MG2:"); lcd.setCursor(12, 1); lcd.print("STOP"); lcd.setCursor(0, 1); lcd.print("Sync:__"); // на дисплей синхронизация __ pinMode (ENABLEWORK, INPUT_PULLUP); //работает как вход с поддяжкой к плюсу pinMode (Zar, OUTPUT); //работает как выход на ключ заряда pinMode (Razr, OUTPUT); //работает как выход на ключ разряда pinMode (Led, OUTPUT); //работает как светодиод индикации работы pinMode (2, INPUT); //Pin2 вход прерывания int0 attachInterrupt (0, ZC, CHANGE); //прерывание по zc CHANGE sei(); // включить глобальные прерывания // инициализация Timer2 для отсчётов примерно 1 с //TCCR2A = 0; // установить регистры в 0 //TCCR2B = 0; //TCCR2A |= (1 << WGM21); //сброс при совпадении (WGM22=0) //OCR2A = 254; // установка регистра совпадения //TIMSK2 |= (1 << TOIE2); // разрешить прерывание при переполнении //TCCR2B |= (1 << CS22) | (1 << CS21) | (1 << CS20); //установить делитель частоты на 1024=64мкс // инициализация Timer1 для отсчётов интервала 1ms GTCCR |= (1 << PSRSYNC); //Prescaler reset обнулить счётчик TCCR1A = 0; // установить регистры в 0 TCCR1B = 0; OCR1B = 249; // установить время счёта таймера1 =1мс } void ZC() { Flagint0 = true; // прерывание int0 произошло if (FlagSynhro == false) // ищем синхронизацию переход к коду СИНХРОНИЗАЦИЯ { nom = 2; } } ISR (Timer1_COMPB_vect) // функция обработки прерывания по совпадению { TCCR1B = 0; // остановить таймер1 TCNT1 = 0; // обнулить значение счёта StartTimer = false; // продолжить поиск флаг разрешить запуск таймера lcd.setCursor(8, 1); lcd.print("X"); } void loop() { currentENABLEWORK = digitalRead (ENABLEWORK); //считать вход разрешения работы if (currentENABLEWORK == 0 && digitalRead(Led) == 0) //Работа разрешена, светодиод - не горит { digitalWrite(Led, HIGH); //включить диод FlagWork = true; //флаг разрешения работы вкл lcd.setCursor(12, 1); lcd.print("WORK"); nom = 2; //sei(); // включить глобальные прерывания } if (currentENABLEWORK == 1 && digitalRead(Led) == 1) //Работа запрещена, светодиод - горит { //cli(); // отключить глобальные прерывания digitalWrite(Led, LOW); //иначе - выключить FlagWork = false; //флаг разрешения работы откл lcd.setCursor(12, 1); lcd.print("STOP"); lcd.setCursor(0, 1); lcd.print("Sync:__"); // на дисплей синхронизация __ nom = 1; } if (currentENABLEWORK == LOW) // Работа разрешена { switch (nom) { case 1: //---------------------------------------------------------------- 1 // ничего не делаем если стоим break; case 2: //---------------------------------------------------------------- 1 //код Синхронизация запуска if (Flagint0 == true && StartTimer == false) // прерывание произошло но таймер ещё не запущен { //GTCCR |= (1 << PSRSYNC); //Prescaler reset обнулить счётчик //TCCR1B = 0; // остановить таймер1 TIMSK1 |= (1 << OCIE1B); // разрешить прерывание при совпадении TCCR1B |= (1 << WGM12) | (1 << CS11)| (1 << CS10); //включить таймер делитель частоты на 64=4мкс Flagint0 = false; // обнулить флаг прерывания StartTimer = true; // таймер запущен } if (StartTimer == true && Flagint0 == true) // таймер считает и прерывание произошло - цикл 4 { TCCR1B = 0; // остановить таймер1 Flagint0 = false; // сбросить флаг прерывания Cicl = 2; // установить цикл работы начальный //nom = 3; // разрешить код РАБОТА nom = 1; // пока при отладке код не запускаем FlagSynhro = true; // синхронизация ок lcd.setCursor(0, 1); lcd.print("Sync:Ok"); // на дисплей синхронизация ок } break; case 3: //---------------------------------------------------------------- 1 //код Работа { if (Flagint0 == true) { if (Cicl=1) // цикл РАБОТА { digitalWrite(Zar, LOW); digitalWrite(Razr, HIGH); } if (Cicl=2) // цикл ЗАРЯД { digitalWrite(Zar, HIGH); digitalWrite(Razr, LOW); } if (Cicl=3) // цикл МТ { digitalWrite(Zar, LOW); digitalWrite(Razr, LOW); } if (Cicl=4) // цикл ПАУЗА { digitalWrite(Zar, LOW); digitalWrite(Razr, LOW); Cicl = 0; } Cicl = Cicl + 1; Flagint0 = false; } } break; } } }
При смене уровня на входе int0 должен запускаться таймер1 на 1мс.
не вижу, чтобы вы запускали таймер в обработчике прерывания int0
Если вы пытаетесь это делать в Лупе, с кучей других операций да к тому же с выводом на дисплей - о какой обработке интервалов менее 1мс мы говорим? Это бред полный.
Я бы посоветовал для начала выкинуть работу с LCD. Как настроите прерывания - вернете обратно. Ну и, конечно, таймер должен запускаться непосредственно в прерывании. иначе это бессмысленно.
При смене уровня на входе int0 должен запускаться таймер1 на 1мс.
не вижу, чтобы вы запускали таймер в обработчике прерывания int0
Если вы пытаетесь это делать в Лупе, с кучей других операций да к тому же с выводом на дисплей - о какой обработке интервалов менее 1мс мы говорим? Это бред полный.
Я бы посоветовал для начала выкинуть работу с LCD. Как настроите прерывания - вернете обратно. Ну и, конечно, таймер должен запускаться непосредственно в прерывании. иначе это бессмысленно.
Хорошо. Попробую выкинуть всё лишнее.
А вот ещё наверно глупый вопрос.
Сделав digitalWrite на цифровой вывод, например к уровню 1, он этот уровень на выводе не остаётся, как у светодиода на 13 ноге.
Я хочу на 12 ноге оставить уровень 1, но он только на микросекунды становится 1и снова возвращается в 0.
И как оставить в 1 ?
Вызывать библиотечные функции из прерывания - не очень хорошая идея. Надо точно знать как и что библиотека делает иначе можно легко повесить всю систему.
ЗЫ Посмотрел Liquid Crystal - его можно из прерывания вызывать.
А вот ещё наверно глупый вопрос.
Сделав digitalWrite на цифровой вывод, например к уровню 1, он этот уровень на выводе не остаётся, как у светодиода на 13 ноге.
Я хочу на 12 ноге оставить уровень 1, но он только на микросекунды становится 1и снова возвращается в 0.
И как оставить в 1 ?
После digitalWrite состояние пина не меняется, пока не будет следующий digitalWrite.
У вас он строках 153-172 сбрасывается из-за ошибки в if-aх
Какая ошибка в ifах?
До нового прерывания int0 и флага ifы не активны. В текущем цикле только один if отработает.
Прочитайте, чем отличается операция присваивания от операции сравнения.
Я переписал код вот так. Вообще не использую библиотечную команду digitalWrite.
Абсолютно всё также.
Абсолютна та же ошибка в условиях if()
Прочитайте, чем отличается операция присваивания от операции сравнения.
Да, вы правы. Исправил
Почему-то не поставил двойное равно в ifах
Теперь заработало в этой части кода )
Абсолютна та же ошибка в условиях if()
Из-за которой все if выполняются подряд не взирая на Cicl
Теперь останется разобрать синхронизацию...
И всё же, почему нельзя запустить таймер по флагу, а не в самом обработчик прерывания int0.
Пишут, что код в обработчике должен быть совсем небольшим.
А вся программа небольшая в лупе почти ничего не делается.
И всё же, почему нельзя запустить таймер по флагу, а не в самом обработчик прерывания int0.
Ну почему нельзя, можно. Просто тереяется гарантия что он запустится сразу. Мало ли чего там в лупе в этот момент происходит.
Скорее он должен очень быстро выполняться, размер особого значения не имеет.
Да
Хорошо. Завтра продолжу настройку кода синхронизации. Благодарю за помощь !
Убрал вывод на дисплей.
Результат тот же. При обработке кода синхронизации (кейс 2) слетает код. Дисплей мигает. Кнопка СТОП не работает.
romc9, По описанию похоже на счёт времени импульса. Если он меньше 1мс, то выполнить некие команды, если больше -то ничего не делать. Если так, то необязательно останавливать и запускать таймер и использовать внешнее прерывание. Можно на постоянно работающем таймере делать захват счётчика через вход ICP. В прерывании по захвату поднять флаг таймаута (если таковой произойдёт) через прерывание сравнения COMPA/B. Немного сложнее в программировании, но итоговое кол-во строк будет меньше. Советую почитать статейку на изи http://we.easyelectronics.ru/AVR/taymery-i-zaderzhki-sbornik-receptov.html тут много полезных советов по таймерам.
Нашёл косяк
Написал
ISR (Timer1_COMPB_vect) вместо TIMER1
Ну кто бы мог подумать...
romc9, По описанию похоже на счёт времени импульса. Если он меньше 1мс, то выполнить некие команды, если больше -то ничего не делать. Если так, то необязательно останавливать и запускать таймер и использовать внешнее прерывание. Можно на постоянно работающем таймере делать захват счётчика через вход ICP. В прерывании по захвату поднять флаг таймаута (если таковой произойдёт) через прерывание сравнения COMPA/B. Немного сложнее в программировании, но итоговое кол-во строк будет меньше. Советую почитать статейку на изи http://we.easyelectronics.ru/AVR/taymery-i-zaderzhki-sbornik-receptov.html тут много полезных советов по таймерам.
Важно именно по int0 запускать - это узел синхронизации.
А за статейку - спасибо. Учту на будущее
Решил разгрузить проц и опрос кнопки разрешения работы делать каждые 3 секунды. Для чего использую Таймер2. По совпадению, таймер выставляет флаг - в лупе проверяется состояние кнопки.
Но вот не работает выдержка интервала таймером. Кнопка срабатывает сразу, а не через 3 секунды.
В чём может быть причина ?
максимальное число для Таймера2 = 255.
Поэтому задержка много меньше...
Благодарю всех, принимавших участие в обсуждении и дававших советы.
Код успешно запущен.