Это для ассемблера , а не для Си - в Си прямое управление стеком штука весьма для спецов... У меня в Си недостаточный уровень. А под асмом весьма много в старых проектах примеров было... Кстати... Измерение времени я б таки по pulseln() c внешней обвязкой (перемычками) и прерыванием соорудил... У топикстартера похоже не АВРка, а LGT - там лучше без вычитывания даташитов в "отсебятину" не влазить...
Заголовок сообщения: Re: Вопрос по программированию задержки внутри прерывания
Добавлено: Сб янв 11, 2025 15:32:17
Друг Кота
Карма: 5
Рейтинг сообщений: 61
Зарегистрирован: Ср сен 30, 2020 16:51:47 Сообщений: 4621 Откуда: РФ
Рейтинг сообщения:0
Попытался сделать задержку после обработки прерывания:
if (intFlag) { intFlag = false; // сбрасываем флаг startDelay = !intFlag; // присваиваем значение переменной Serial.println("Interrupt!"); Serial.println(startDelay); }
static unsigned long previousMillis = 0; // Переменная для хранения предыдущего времени const long interval = delayFront; // Интервал в миллисекундах unsigned long currentMillis = millis(); // Получаем текущее время
// Если прошло необходимое количество времени и флаг прерывания сброшен, то включаем цифровой выход 3
if ((currentMillis - previousMillis == interval) and (startDelay = true)) { digitalWrite(3, HIGH); }
Когда стоит задача внешнее прерывании, а потом выставить пин и задержка в десятки, сотни мс, то алгоритм такой: В обработчике внешнего прерывания отключить это прерывание. Чтобы наверняка, ещё флаг внешнего прерывания пристукнуть, выставляем порт. Если основной цикл пробегается достаточно быстро (я не знаю ваш проект, насколько загружен основной цикл), то выставляем флаг, что эй, я импульс поймал, в основном цикле мы это флаг увидели, выставляем требуемую задержку. Если же основной цикл загружен, то после выставления пина, выставляем нужную задержку. В прерывании таймера, когда время вышло, сбрасываем пин. Даём по шапке флагу внешнего прерывания, включаем внешнее прерывания. Все начинается заново. Ждем внешнее прерывание.
Последний раз редактировалось Demiurg Сб янв 11, 2025 16:48:09, всего редактировалось 1 раз.
if ((currentMillis - previousMillis == interval) and (startDelay = true)) { digitalWrite(3, HIGH); }
Разделите на куски
Код:
if (startDelay == true) { if (millis() - previousMillis >= interval) { digitalWrite(3, HIGH); } }
Главное >= , а не == Не всегда словишь миллисекунду.
Добавлено after 17 minutes 25 seconds: startDelay должна быть volatile. А в прерывании, надо запомнить время старта. prevMillis = millis();
И учтите, что если следующий вызов прерывания, наступит раньше, чем закончится ожидание, перед выключением, то задержка начнётся заново, как бы отодвинется по времени.
Последний раз редактировалось codenamehawk Сб янв 11, 2025 17:19:28, всего редактировалось 2 раз(а).
Interrupt handler: Вход в прерывание: set_bit (TIFR, EXT_FLG); // Для верности прибиваем флаг внешнего прерывания. clr_bit (TIMSK, EXT_FLG); // Отключаем внешнее прерывание.
Два варианта. Если основной цикл быстро крутится. set_bit (PORTx, PIN); // Выставляем пин. set_bit (FLAGS, FLG_EI_YA_IMPULS_POIMAL); В основном цикле проверяем этот флаг, ставим нужную задержку. Крутимся дальше, походу проверяем вышло ли время. Если вышло: clt_bit (PORTx, PIN); // Сбрасываем пин. set_bit (TIFR, EXT_FLG); // Для верности прибиваем флаг внешнего прерывания. set_bit (TIMSK, EXT_FLG); // Включаем внешнее прерывание. Все начинается заново. Ждём импульс.
Если основной цикл тяжёлый. Там же в обработчике прерывания: set_bit (PORTx, PIN); // Выставляем пин. Настраиваем, включаем таймер. Ждём в прерывании таймера, когда закончится задержка. clt_bit (PORTx, PIN); // Сбрасываем пин. set_bit (TIFR, EXT_FLG); // Для верности прибиваем флаг внешнего прерывания. set_bit (TIMSK, EXT_FLG); // Включаем внешнее прерывание.
Советую посмотреть в сторону программных таймеров. А также поиграться с аппаратными таймерами. Поделать разные тестовые задачи. Чтобы вы научились работать с аппаратными таймерами. Всякие генераторы, мигалки.
Имелись ввиду аппаратные таймеры начинки МК. Но там надо весьма аккуратно действовать, дабы не навредить - Т1 иТ2 отвечают за исполнение некоторых функций референса.
С аппаратными таймерами я знаком. Например, я делал таймеры на CD4541 и на CD4060 делал.
Нее.. Аппаратные таймеры, это которые в МК настраиваются при помощи регистров и работают автономно, не зависимо от программы. А программные, это тупо цикл прокручивается энное количество раз. За счёт программы.
Под аппаратными таймерами я имел в виду таймеры МК AVR. TIMER0, 1,2 и так далее. Не микросхемы. А таймеры внутри МК. Программные таймеры. Интернет. Поисковики. Пояснение. Аппаратных таймеров у МК AVR раз два и обчелся. А если нам нужно 10-20 таймеров? Как быть? Времянки единицы мс, десятки, сотни, секунды и так далее. Тут как раз и используются программные таймеры. Как пример. Советую прочитать цикл статей Татарчевского. Тут начало.
В отношении ардуино с АВРками обычно ставится вторая точка на системном таймере и от нее уже все остальные псевдопараллельные счетчики: настройка инициализации (в результате прерывание раз в 1мС)
А ничего что analogWrite может использовать таймер0 и OCR0A в частности? Зачем лезть к железу (особенно если не понимаешь!), когда Ардуино тебе уже предоставляет средства для работы со временами? От микросекунд до long(!) миллисекунд!
Выводы D5,D6 - T0 ~980Hz Выводы D9,D10 - T1 ~490Hz Выводы D3,D11 - T2 ~490Hz Есть из чего выбирать (где можно игнорировать использование). Зачем и что используется - это уже вопрос конкретной задачи и предпочтений.
Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 17
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения