Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Переход из прерывания
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
Георгий
Как сделать переход к определенному месту программы из программы прерывания. Мне нужно из прерывания по таймеру, при достижении определенного значения счетчика Counter переходить в определенное место программы. На ассемблере решалось просто, искусственно восстанавливаю стек и делаю переход к метке. А В ИАР как это сделать?
GxOST
это делается просто: в прерывании модифицируется флажок типа volatile, а в основном цикле программы он проверяется
dxp
Цитата(Георгий @ Feb 20 2006, 18:55) *
Как сделать переход к определенному месту программы из программы прерывания. Мне нужно из прерывания по таймеру, при достижении определенного значения счетчика Counter переходить в определенное место программы. На ассемблере решалось просто, искусственно восстанавливаю стек и делаю переход к метке. А В ИАР как это сделать?

Точно так же - напишите низкоуровневую функцию манипуляции контекстами на асме, а вызывайте ее из С. Вообще-то, это что-то RTOS'ом попахивает. smile.gif
Георгий
Цитата
это делается просто: в прерывании модифицируется флажок типа volatile, а в основном цикле программы он проверяется

Это не подходит.
Цитата
Точно так же - напишите низкоуровневую функцию манипуляции контекстами на асме, а вызывайте ее из С

То есть без асма не обойтись? Весь проблем, как из асма перейти к метке внутри функции main.? Как сделать метку видимой для других?
Уточню свою задачу. Функция чтения в цикле опрашивает порт. Если через какое то время порт не ответил, функция должна передать управление в начало программы, но не в самое начало, а туда , где начальные условия уже выставлены и необходимо попытаться реанимировать устройство, подключенное к порту, отправив ему сброс.
Пока применяю WDT, но он делает полный сброс, к устройствам, подключенным к порту, проходят броски.
Rst7
Могут помочь стандартные функции setjmp и longjmp.

#include "setjmp.h"
jmp_buf redo_point;

__interrupt void foo1(void)
{
...
longjmp(&redo_point,1); //Тут будет переход на оператор за setjmp

}



main
{

....
setjmp(&redo_point); //Устанавливаем точку длинного перехода


}
defunct
Цитата(Георгий @ Feb 20 2006, 15:21) *
где начальные условия уже выставлены и необходимо попытаться реанимировать устройство, подключенное к порту, отправив ему сброс.

офомить в виде функции это место и просто вызвать при необходимости

Если нужно забить гвоздь, то не надо изобретать велосипед, надо просто взять молоток и забить гвоздь.
Георгий
Дело в том, что после сброса устройства, программа должна начать все практически сначала. Если бы можно ограничиться функцией, так бы и сделал. Нужен именно переход в начало программы, но не в самое.
dxp
Цитата(Георгий @ Feb 21 2006, 17:27) *
Дело в том, что после сброса устройства, программа должна начать все практически сначала. Если бы можно ограничиться функцией, так бы и сделал. Нужен именно переход в начало программы, но не в самое.

Непонятно, откуда такое суровое требование - обнулять работу программы при отсутствии сигнала в каком-то порте. Да еще и не совсем обнулять, а частично. Неужели нельзя как-то штатно эту ситуацию обрабатывать? Ну нет сигнала - это, да, событие, которое трубует обработки (как и многие другие события в системе). Зачем работу программы-то рушить? Целостность работы нарушать...
Aleks17
Не понимаю чем не устраивает вариант с volatile флагом. Самым удобный и разумный на мой взгляд.

Вообще оператор goto (про него идёт речь?) в любой книжке про программистов рекомендуется забыть как страшный сон (там же и приводятся аргументы почему).
Георгий
Вся работа программы зависит от ответа устройства, опрос его может быть из разных мест, если после каждого вызова каждой функции проверять флаг, а потом делать многоуровневый откат к началу программы, это тоже не выход. Устройство может быть выдернуто в любой момент, и обнаружение ведется по прерыванию, это нормально. Но уходить надо в определенную точку из прерывания. Я не совсем еще понимаю логику работы ИАРа, но, наверно, как то можно подменить адрес возврата из прерывания на адрес этой точки. Может longjmp это и делает?
Aleks17
Иными словами, Вам необходимо перейти к началу какого-то алгоритма при достижении определенного условия. А нельзя это сделать так:

main()

{

Init();

do {MyStart()} while (1);

}



void MyStart()

{

if (Error)

return;

}
Георгий
Не совсем так, так было бы просто. if Error может возникнуть в любом месте, в том числе и вов вложенных несколько раз функциях.
Rst7
Цитата(Георгий @ Feb 21 2006, 14:24) *
Вся работа программы зависит от ответа устройства, опрос его может быть из разных мест, если после каждого вызова каждой функции проверять флаг, а потом делать многоуровневый откат к началу программы, это тоже не выход. Устройство может быть выдернуто в любой момент, и обнаружение ведется по прерыванию, это нормально. Но уходить надо в определенную точку из прерывания. Я не совсем еще понимаю логику работы ИАРа, но, наверно, как то можно подменить адрес возврата из прерывания на адрес этой точки. Может longjmp это и делает?


setjmp запоминает в jmpbuf все необходимые регистры (в том числе Y, SP, PC) в точке вызова этой функции.

longjmp все это загружает обратно и возвращается по записанному в jmpbuf PC. Т.е. то, что надо.
dxp
Цитата(Георгий @ Feb 21 2006, 18:24) *
Вся работа программы зависит от ответа устройства, опрос его может быть из разных мест, если после каждого вызова каждой функции проверять флаг, а потом делать многоуровневый откат к началу программы, это тоже не выход. Устройство может быть выдернуто в любой момент, и обнаружение ведется по прерыванию, это нормально. Но уходить надо в определенную точку из прерывания.

Ну и зачем делать откат в начало? Пусть себе программа работает, если выдернули устройство, то программа переходит в один режим, если вставили, то в другой. Зачем что-то обнулять? Заведите переменную, обозначающую режим и проверяйте ее. Вот прикинье - вставили/вынули USB дивайс, винда перегрузилась - хорошо это? smile.gif

Цитата(Георгий @ Feb 21 2006, 18:24) *
Я не совсем еще понимаю логику работы ИАРа, но, наверно, как то можно подменить адрес возврата из прерывания на адрес этой точки. Может longjmp это и делает?

Логики IAR'а тут никакой нет - он действует в рамках Стандарта языков С/С++. longjmp действительно может реализовать такое, но все-таки, имхо, это не путь. Имхо, чего-то не того в дизайне проги. Вы бы чуть подробнее изложили преметную область, может чего и посоветовать удалось бы.
defunct
Цитата(Георгий @ Feb 21 2006, 15:12) *
Не совсем так, так было бы просто. if Error может возникнуть в любом месте, в том числе и вов вложенных несколько раз функциях.

?
ну и что? транслируйте эту ошибку "на верх" там и обрабатывайте.
Георгий
Что то инет у меня глючит, начинаю отвечать , отрубается.
Транслировать наверх получется сложнее, чем сделать один переход из одной функции прерывания. Функций чтения много, и они могут быть и на втором и на третьем уровне. Это сколько проверо по дороге надо делать.

Цитата
Ну и зачем делать откат в начало? Пусть себе программа работает, если выдернули устройство, то программа переходит в один режим, если вставили, то в другой. Зачем что-то обнулять? Заведите переменную, обозначающую режим и проверяйте ее. Вот прикинье - вставили/вынули USB дивайс, винда перегрузилась - хорошо это?

Тут больше аналогия с другим просится - если выдернуть системный винт, то чем винде еще заниматься, как не перезагружаться в цикле и определять подключен винт или нет.
defunct
Цитата(Георгий @ Feb 21 2006, 15:43) *
Функций чтения много, и они могут быть и на втором и на третьем уровне. Это сколько проверо по дороге надо делать.

Вот и плохо что много. Должна быть одна функция чтения, в которой обрабатываются ошибки связи с устройством. т.е. разделите программу на уровни не по вложенности, а по характеру действий хотя бы на канальный, транспортный(в вашем случае сразу сеансовый) и прикладной. см. модель http://www.citforum.ru/nets/switche/osi.shtml.
Георгий
Поправляюсь - функция чтения естественно одна. Но вызываеться она может с разных уровней. Но отсутствие устройства все рано определяется возникновением прерывания, и логично из него уйти в начало. Этим сейчас WDT занимается, но он делает полный сброс.
defunct
Цитата(Георгий @ Feb 21 2006, 15:52) *
Поправляюсь - функция чтения естественно одна. Но вызываеться она может с разных уровней.

мало ли откуда она вызывается? главное чтобы функция чтения производила разбор протокола работы с устройством, и обрабатывала ошибки связи, а на верхний уровень передавала только правильно распознанные данные.

Цитата
Но отсутствие устройства все рано определяется возникновением прерывания, и логично из него уйти в начало. Этим сейчас WDT занимается, но он делает полный сброс.

В прерывании установить флаг ошибки устройства, который заблокирует например функцию чтения. Разблокировать этот флаг может например, функция "реанимации" устройства, которая будет вызываться пока флаг ошибки устройства установлен.
Георгий
Нет, уж я лучше оставлю все как есть. Иначе из-за одного перехода придется переписывать всю программу, менять все функции на булевые, чтобы корректно откатываться наверх. У меня эта прога была сначала написана на ассемблере, и там переход из прерывания в начало программы решал все проблемы. А перевел на Си и столкнулся с этой бякой.
defunct
Цитата(Георгий @ Feb 21 2006, 16:11) *
Нет, уж я лучше оставлю все как есть.

вероятно, это правильное решение. WDT всяко надежнее манипуляций со стеком и неправильного использования прерываний.

Цитата
Иначе из-за одного перехода придется переписывать всю программу, менять все функции на булевые, чтобы корректно откатываться наверх. У меня эта прога была сначала написана на ассемблере, и там переход из прерывания в начало программы решал все проблемы. А перевел на Си и столкнулся с этой бякой.

Менять пришлось бы только функцию чтения...
_artem_
Внутри одной функции переход с одной позиции в другую может только через явные операторы goto, break continue или посредством других конструкций языка программирования если таковые есть или же перезагрузкой самого контроллера. Мне ваша логика непонятна - хотите ли вы совершать какие то действия после того как команда отправлена или не желаете ждать ответа от команды и проверять результат на правильность или на что то другое?

Для вашего случая (не знаю слово рецидив подходит или нет )) ) можно вот что предложить :
- выделить одну переменную для значения результата
- в самом начале main сохранить контекст setjmp()
- все инициализации переменных и констант выделить в отдельную функцию и вызвать ее до сохранения сохранения контекста в main(), причем переменная результата тоже инитиализируется там .
- в прерывании где обнаруживается ошибка - вызывается программа инициализации переменных
- затем в том же прерывании присваивается значение результата
- и в том же прерывании переходится на контекст сохраненый при загрузке .
- в main() сразу после сохранения контекста ввести условие в соответствии с переменной результата

То есть вы програмным путем делаете контролируемую загрузку с контролем инициализации переменных, что позволяет вам определить был ли это reset или переход по ошибке. Конечно можно было просто перейти на вектор прерывания reset но будет неоднозначность значения переменной результата - на случай если состояние оперативной памяти на время загрузки неопределенно.

Но поверьте мне - овчинка не стоит выделки ...
Георгий
Цитата
Менять пришлось бы только функцию чтения...
И все вызывающие ее функции. Они тоже должны вернуть наверх ошибку.
Вечером дома посидел, подумал. Наверно, так оно и следует делать в о общем случае. (По крайней мере, когда пишу драйвера, там сплошь проверки условий и возврат булева результата). Но когда пишешь супер компактный код, приходится жертвовать некоторыми принципами.

"Правильная" проверка флагов и откат по ошибке наверх увеличили программу почти на 200 байт. И глубина стека возросла.

Вариант с longjmp тоже оказался не походящим - jmp_buf отъедает 21 байт от ОЗУ (из 128). На стек уже не остается.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.