прерывание и возврат к началу цикла
- Войдите на сайт для отправки комментариев
Втр, 02/06/2015 - 10:48
Добрый день, уважаемые форумчане!
У меня такой вопрос: можно ли реализовать возврат к началу цикла програмы после снятия внешнего прерывания? Т.е.выход из подпрограммы прерывания в начало основного цикла loop(). Нигде решения не нашел. Спасибо.
Как правило такая постановка задачи - не корректный способ решить её.
Выход из прерывания происходит в точку, где произошло это прерывание.
Выход из прерывания происходит в точку, где произошло это прерывание.
Чё не коректная. Такое прерывание называется РЕСЕТ.
Ресет это
не только ценный мехещё и вызов setup()Да простят меня боги программирования и прогрессивная мировая общественность, но может быть оператор goto ? (http://arduino.ru/Reference/Goto) Ну, если уж совсем никак иначе..
setup можно обойти выяснив что мы туда попали не из-за пропадания-включения питания.
Ещё lehak давно об этом писАл.
Ну а переход можно сделать разрешив WDT
"Мы" тут все пытаемся оседлать сферического коня в вакууме, не зная задачи, потому можно сделать как угодно и при перезагрузке можно определить по какой причине мы перезагружены, и обойти setup тоже можно, только чаще всего задача не стОит, чтобы из пушки по воробьям палить, разве что если скушно и из спортивного интереса. Можно и при выходе из прерывания восстановить флаги и подменить в стеке адрес выхода на любой нужный адрес, только зачем такой хардкод нужен?
Всем спасибо) Опробывал return. Ничего так ,вроде, работает.
Схема такая:
Вот вот, как всё просто ;)
Нахрена мерседес если ездить только на огород за картошкой :)
А ещё очередная загадка, когда судя по комментариям intPin должен быть пином 2, а реально, пин 0. Эхх..
Да нет же) Это не пин , это номер прерывания. Прерывание "0", а пин для прерывания действительно задействован "2". Кстати, плата ардуино Уно.
Не разглядел вчера в темноте :)
В таком случае название странное, слово pin сбило с толку.
Ну в общем да) Так будет короче и понятнее)
Здравствуйте друзья!
Небольшое вступление. Сразу же прошу прощения и сообщаю что в написании программ МК я лох педальный. На самом деле у меня вторая радиолюбительская категория и с микросхемами на обычной логике никаких проблем нет. С монтажом пайкой и прошивкой МК тоже все в порядке.
Читаю книги, смотрю видео но не всегда там есть ответы. Вообщем в большей степени для обучения и возможно для дальнейшего применения на мотоцыкле делаю стробоскоп с двумя светододами и с несколькими режимами моргания.
В программе все просто до безобразия. Прерывание от кнопки с каждым нажатием прибавляет по единице к одной переменной. Потом в цикле с помощью if смотрим чему равна переменная и в зависимости от этого выполняется то или иное.
Собственно все работает, режимы переключаются светодиоды моргаю так как задумано... Но так как после прерывания выполнение продолжается именно с того места откуда оно было вызвано то режимы переключаются не сразу.
Там в некоторых режимах работает for и вот пока он не закончиться визуально режим не переключится, хоть переменная и обновилась. Вообщем друзья, как мне победить это? Что бы переключалось мгновенно, в независимости от того где остановилась программа.
Единственным я вижу это как то после прерывания прыгать на начало цикла, почему собственно и написал сюда. Экспериментировал и return и continue и даже с goto но что то ничего не получается. Может изначально сделать как то иначе? Подскажите примерно по какому пути идти чтобы решить такую задачу? Я дальше сам допетрю.
Спасибо всем большушие!
Вот код
Избавляться от delay. Основной цикл должен выполняться хотя бы за 100 миллисекунд.
Это по принципу как в Blink без delay?
Немного не понятно то что проверка if с долгим режимом все равно будет завершаться после обработки прерывания... Если даже вместо delay будет что то другое, то if должна сначала зевершится.
Вот посмотрите, я Вам на бросал первые 3 режима и 8й для первого светодиода остальное, если подойдет, сделаете по аналогии
vosara
Спасибо за совет и за скетч!
Немного странно прада работает, то нормально, а то инвертируються LOW и HIGH на выходах, то есть когда ненада горит, а когда нада тухнет. Но суть с millis я уловил, спасибо, буду пробовать.
Но для начала я нашел более простой способ решения моей проблеммы.
Может кому понадобиться.
В длогих циклах for я поставил if проверку и если переменная сменилась то делается выход из цикла for (while, switch) командой break. Полагаю что и continue тоже подойдет, то есть будет прыгать на следующюу итерацию (правда не проверял).
Вообщем может быть с точки зрения профи реализация кривая, но эффект достигнут.
Будем пробовать и иные варианты.
Спасибо всем.
А ведь это ОЧЕНЬ НУЖНЫЙ вопрос!!!
Например, у меня, в loop-е, идет опрос температурных датчиков по шине OneWare Это может длиться 5 и более сек. Библиотека для DS18B20, имеет внутри себя delay(), которые НЕ охота выискивать, а потом модифицировать...( Далее, по нажатию на кнопку, нужно включать backlght на дисплее. В результате, нажимаем кнопку, срабатывает аппаратное прерывание, включение (lcd.backlight), в функции аппаратного прерывания не работает...(. Поэтому, можно ждать и 3 и 5 сек, пока закончится опрос датчиков, и backlight сработает, а это НУ совсем не по пацански...) Вывод, нужно, наплевав на все, по аппаратному прерыванию, переходить в начало loop-а, за последствия отвечаю сам...) kisoft, предложил блестящую идею, в функции прерывания, подменить адрес возврата не в то место откуда она вызвалась, а на начало Loop-а.
Вот как теперь это реализовать без подробнейшего изучения микропроцессора?
Выйти из прерывания в начало loop это идеально. Но я вот такого варианта не нашел. Да и судя по описанию функции прерывания такое невозможно, все равно вернеться туда же откуда где loop остановился.
В любом случае я проблему связанную с этим у себя решил, работает отлично. Видимо не всегда нужно мыслить логично.
Кончайте ересь разводить. Если возникла потребность выйти из прерывания в заданую точку - архитектура дерьмо, нада делать новую. Ибо вы сделаете мегакостыль, который вызовет малопрогнозируемое количество гемороя. Потому так:
1. В принципе это реализуемо, но в прикладных программах не используется, в ОС используется например вытесняющая многозадачность.
2. Новичек-любитель это не напишет грамотно, надо читать даташит, разбиратся с сохранением в стек при прерывании, заменять в нем нужные значения ручками на ещё более нужные ;) корректировать указатель стека так, чтоб размер стека был таким же как и при приходе в эту точку естественным путем.
3. Профи с таким подходом связыватся не будет, нафиг надо через столб прыгать, если обойти много проще, и яйца целее ;)
ПС. либу которая 5 секунд держит управление - сразу в топку. Либы под ардуину - полная хрень, за что не возьмись. Увы.
Да, согласен с Logik, будем считать это ересью...)
Нужный тут только один вопрос: если не охота выискивать, в том числе православно-верные библиотеки, разбираться в работе устройства, которое Вы программируете (и как понимаю в надежде потом запродать результат своей лени) .. то нафига вы вообще взялись за Ардуино?
Ардуино - ИСКЛЮЧИТЕЛЬНО учебная поделка в целях ОБУЧЕНИЯ. Никакая её часть не может применяться в готовом изделии. Это как из детского конструктора сваять подъемный кран и удивляться, что "дачка не строится, а кран валится".
Лично я, хочу сделать охлаждающую камеру до 16-18 градусов. Для расстойки теста для хлеба. Для этой цели - ардуино идеальный вариант (а реально, больше не на чем), и действительно, выискивать классные библиотеки, неохота. Алгоритм камеры - не сложен. А по поводу "учебной поделки в целях обучения" - не согласен, все-таки 16 миллионов операций в секунду - спутник можно обсчитывать...)
:) dangol, у вас ключевая мысля в этом самом "неохота". Никакая "охлаждающая камера" не требует алгоритма с нарушением цепочки возвратов хода выполнения. Задачи такого рода возникают только на очень сложных асинхронных алгоритмах и имеющих критические секции исполнения .. то есть требующие реальной многозадачности. Но это - далеко не ваш случай. Не надо что-то "выискивать". Все что вам требуется - это нормально прописать алгоритм, что вам явно тоже "неохота", об чем и спич.
Для начала, ознакомьтесь с книжкой Паронджанова "Занимательная информатика" и вопрос создания правильного алгоритма отпадет. Моему 10-и летнему отпрыску - помогло, думаю и вам тоже поможет.
Так что получается, нет никакого известного способа возвращения из цикла к началу Loop()?
Сам столкнулся с такой необходимостью. Из-за условий эксплуатации и конструкции корпуса возможно временное отключение панели с дисплеем на I2C шине. При проверке выяснилось, что от многократного издевательского воздействия(отключения-подключения провода SCL), если попасть на неопределённый момент вывода информации на экран, программа зависает. Но продолжает свою работу вектор прерываний ISR (WDT_vect). Понять в нём, что программа зависла - легко, но вот попасть бы из него куда-нибудь кроме точки зависания очень бы хотелось.
Да простят меня боги программирования и прогрессивная мировая общественность, но может быть оператор goto ? (http://arduino.ru/Reference/Goto) Ну, если уж совсем никак иначе..
Что касается GOTO, он позволяет перемещаться только внутри обработки прерывания, если метку поместить в Loop, а goto в прерывании, компилятор говорит, что метка не объявлена :(
Полноценный ресет не подходит, ибо используются короткозамкнутые контакты реле, всё безвозвратно блокирующие (обезопасивающий костыль на случай выхода МК из строя, так как условия эксплуатации немного варварские), и при перезагрузке уже всё равно будет, в каком состоянии МК, так как всё равно нужно вмешательство персонала. Хотелось бы иметь функцию самостоятельного выхода МК из зависшего состояния. (Грешу на цикл в библиотеке дисплея)
P.S. Похоже дело не в цикле. Попробовал asm("JMP 0"); Реле не отпадают, зато переменные обнуляются, а это кажется поправимо. Но беда в другом: когда код доходит до взаимодействия с устройствами на шине I2C, снова зависает. Зато превосходно продолжает работать код внутри ISR (WDT_vect). Помогает только аппаратный сброс :( Хрень какая-то...
Dessan07 - если программа действительно зависла, единственный выход это полный РЕСЕТ. Если вас это не устраивает - проектируйте устройство так, чтобы оно не зависало. Вообще. частое срабатывание ватчдога - признак криворукости программиста.
Ватчдог сам по себе и не срабатывал (если речь о перезагрузке им), он вообще для своевременного опроса датчиков. Програмный перезапуск при помощи asm("JMP 0"); в ватчдоге происходит осознанно, если после долгого насилования шины I2C loop() встаёт колом, и дополнительный код в ватчдоге определяет, что циклы не считаются. Дальнейшие тесты показали, что после програмного перезапуска при обращении к шине I2C происходит повторное зависание, причем пробовал при програмном перезапуске отключать поочерёдно куски кода, обращающиеся и к индикатору, и к дислею, без разницы, только доходит до любого из них, снова колом. Если их при перезапуске полностью отключить, всё работает отлично.
Dessan07 - приведите код, вместе посмеемся.
Пока по вашему описанию выходит, что в прерывание ватчдога вы запихнули почти весь loop() . Так не делают. почти любая работа с шинами данных требует, в свою очередь, использования прерываний и из ватчдога это работать не будет и не должно. Переходя из ватчдога по произвольному адресу - вы рушите стек возврата. Кроме того, переход по нулевому адресу не чистит регистры и оперативку - поэтому неудивительно, что после этого у вас снова все зависает.
В общем, покажите код. Совершенно неясно, например, нафига датчики опрашивать по ватчдогу - есть же общепринятые механизмы через обычные таймеры и прерывания.
:) хотел повырезать массивы кода перед отправкой, оставив нужное, но если уж и смеяться, то над всем полностью и не доделанным :)
Нет никакого всего loop() в ватчдоге, лишь два далласа и контроль независания. (Да, согласен, что лучше их по таймеру опрашивать, но на данном этапе такой пример попался, и после этого мне хотелось обкатать ватчдог, чтобы понять что это вообще такое.
За инфу про регистры и оперативку спасибо. Теперь ясно, а то удивлялся, почему еще не разрешенный после програмного перезапуска ватчдог продолжает работать :) Наверное перед ресетом буду в незанятые пины сохранять самые нужные однобитные переменные :D
Крофьизглаз.
DetSimen, Можно пожалуйста топ 3 нюанса, которые сильнее всего режут глаз?
ну как я и предполагал :(
В прерывании (строка 553 и далее) вы используете работу с OneWire шиной и с Сериалом. И то и другое использует прерывания и внутри другого прерывания нормально работать не будет. Вообще, внутри вектора прерывания полагается размещать только простой и быстрый код - прочитать регистр, сбросить счетчик, выставить флаг. Все остальное делается в основной программе.
остальной код не смотрел
Сериал (да и вообще ниже 573 строки)
573
573
используется только когда программа уже зависла.Вы меня конечно убедили перенести OneWire в loop, согласен, что так себе затея была...
Но... Оно же на практике всё работает. Температура на экране актуальная. Если не насиловать провод SCL, оно без проблем функционирует. Сейчас попробую вообще убрать ватчдог из кода, ради эксперимента, но почти уверен, что все равно смогу повесить плату.
Можно тихо, в уголочке, сказать, что для обработки исключительных ситуёвин в ентих Сях предусметрены хитрые функции setjump() и longjump()? Куды их совать - подстажет ...нет, не порнхаб, но Гугль всеблагой! И можно не мастурбировать левой пяткой через среднее ухо.
Отрезал код кусок за куском, пока не оставил это. И оно всё ещё зависает, если дёргать SCL
wdrakula, За setjump() и longjump() спасибо, попробую, судя по описанию то, что изначально и искал :). Правда, как выяснилось, в моём случае оно не поможет, но я рад, что появился ответ на основной вопрос темы, который тут задали еще в 2015 году :)
Отрезал код кусок за куском, пока не оставил это. И оно всё ещё зависает, если дёргать SCL
тут тебе слишком глубоко копать притется, это в I2C библиотеке ...ну не то, что проблемы, но недочеты.
Выход простой, без "глубокого бурения" - использовать вочдог. Но нужно помнить о сложностях и перезаписи бутлоадера.
Там было не обсуждение, а глум, что естественно. Мы - програмисты - злы и циничны. Все, кто глумился, я тебе ставлю 100 к 1, знали про лонг джамп. ;)))) Это на уровне букваря в С.
Так что получается, нет никакого известного способа возвращения из цикла к началу Loop()?
Что касается GOTO, он позволяет перемещаться только внутри обработки прерывания, если метку поместить в Loop, а goto в прерывании, компилятор говорит, что метка не объявлена :(
Впрочем, думаю, можно поступить следующим образом:
При первом заходе в loop() считать указатель стека, подняться на один уровень вверх (т.е. до вызова loop()) и запомнить его.
Если надо откуда угодно вернуться к началу loop(), записать в указатель стека запомненное значение и вызвать loop(). По идее еще нужно при каждом входе в loop() разрешать прерывания. Как-то так.
Ой, извиняюсь, там я некорректно написал. Цикл находится где-то в недрах библиотеки, функции которой используются в loop() при работе с I2С дисплеем. Работоспособным оказывается только срабатывающий раз в секунду кусочек кода в вотчдоге, и вот из этого прерывания хотелось бы прекращать заглючившую деятельность и возобновлять работу программы. Так же основная задача для меня побороть не именно это зависание, а вообще любое, какое может случиться в процессе выполнения программы (при этом нет гарантии, что температура в помещении не станет отрицательной, или что в устройство не уронят отвёртку, не будут через года физически отваливаться датчики и т.д., плюс ненадёжный источник питания и вибрации), если при этом прерывание будет в состоянии функционировать. При этом нельзя ронять некоторые контакты реле.
Ну тогда - обычная перезагрузка по "вотчдогу". А если нужно сохранять некоторый набор переменных, записывать его в EEPROM, а в setup() - читать необходимое.
Контакты реле можно зафиксировать 595 регистром.