Микроконтроллеры, АЦП, память и т.д Темы касающиеся микроконтроллеров разных производителей, памяти, АЦП/ЦАП, периферийных модулей... |
08.07.2007, 18:21
|
|
Прохожий
Регистрация: 08.07.2007
Сообщений: 2
Сказал спасибо: 0
Сказали Спасибо 0 раз(а) в 0 сообщении(ях)
|
Обработка прерываний.
Я думаю на вопросы по прерываниям отвечали уже не раз, но я не смог найти на свой.
Пусть имеется следующая программа:
1)Функция Авария. При переходе к ней запускается бесконечный цикл в котором происходит сигнализация, а также сброс флагов прерывания, и остановка таймер-счетчика.
2)Функция обработки прерывания по переполнению таймер-счетчика, в которой вызывается функция Авария.
Вопрос первый.
Если я сбрасываю флаг прерывания при его выполнении. Прерывание будет считаться оконченым и не будет мешать обработке других прерываний? Корректно ли это?
Вопрос второй.
Как грамотно при выполнении прерывания после его окончания, вернуться не к месту, где была прервана оснавная программа, а перейти в желаемую точку. К примеру прерывание возникло в цикле, а после его выполнения необходимо из цикла выйти.
Как это ораганизовать на СИ для WINAVR?
Я понимаю что можно ввести в цикл дополнительное условие... Но если циклов много?
Возможно ли использовать метки или что-то подобное им?
Буду признателен за ответы.
|
|
|
|
09.07.2007, 11:45
|
|
Вид на жительство
Регистрация: 05.09.2006
Сообщений: 360
Сказал спасибо: 0
Сказали Спасибо 3 раз(а) в 3 сообщении(ях)
|
Команда возврата из прерывания RETI восстанавливает указатель адреса из стека плюс сбрасывает служебные флаги контроллера прерываний. Для того чтобы вернуться из прерывания в другую точку программы (на определенную метку) нужно заменить адрес возврата в стеке на нужный. Для этого восстанавливаем из стека два байта, например выполняем два раза команду
POP R16
POP R16
Данные (адрес с которого вызвано прерывание) игнорируем. Теперь записываем в стек адрес возврата на метку и даем команду выхода из прерывания. Для этого выполняем команды
LDI R16,Low(Label)
PUSH R16
LDI R16,High(Label)
PUSH R16
RETI
Не помню какая очередность записи байтов в стек, сначала младший, потом старший (как написано здесь) или наоборот. Проверьте сами. Переложить на С думаю сможете.
Удачи.
|
|
|
|
09.07.2007, 18:32
|
|
Прописка
Регистрация: 15.10.2006
Сообщений: 130
Сказал спасибо: 0
Сказали Спасибо 2 раз(а) в 1 сообщении
|
Re: Обработка прерываний.
Сообщение от Tibo
|
Если я сбрасываю флаг прерывания при его выполнении. Прерывание будет считаться оконченым и не будет мешать обработке других прерываний? Корректно ли это?
|
Вполне. Только правильнее будет наверно сказать
что прерывание будет обработано до конца,
а при следующем обращении уже не вызовется
(думаю речь идет о бите разрешения прерывания?)
Сообщение от Tibo
|
Как грамотно при выполнении прерывания после его окончания, вернуться не к месту, где была прервана оснавная программа, а перейти в желаемую точку. К примеру прерывание возникло в цикле, а после его выполнения необходимо из цикла выйти.
Я понимаю что можно ввести в цикл дополнительное условие... Но если циклов много?
Возможно ли использовать метки или что-то подобное им?
|
Ну использовать какую либо глобальную переменную-флаг все равно придется.
А выходить из глубоких циклов
если все дело происходит в какой либо функции
можно при помощи return
Код:
|
int flag = 0;
func()
{
for(i=0; i‹n; i++)
{
....
for(j=0; j‹m; j++)
{
....
if(flag) return;
}
}
} |
|
|
|
|
09.07.2007, 19:13
|
|
Гражданин KAZUS.RU
Регистрация: 27.07.2006
Сообщений: 659
Сказал спасибо: 0
Сказали Спасибо 4 раз(а) в 4 сообщении(ях)
|
Если вам доступен стек,то можно выйти куда угодно,но лучше этого не делать.Любой просчет приведет к сбою программы.Вы не слишком усердствуете?Кроме того вам придется отслеживать глубину стека и решать куда нужно выйти.Кстати стек придется править.
|
|
|
|
09.07.2007, 21:57
|
|
Почётный гражданин KAZUS.RU
Регистрация: 19.01.2007
Сообщений: 1,747
Сказал спасибо: 2
Сказали Спасибо 46 раз(а) в 35 сообщении(ях)
|
Вы затронули очень серьезный вопрос, с точки зрения программирования: "В фон-неймановской архитектуре единая область памяти используется, в том числе, и для реализации стека. При этом снижается производительность устройства, так как одновременный доступ к различным видам памяти невозможен. В частности, при выполнении команды вызова подпрограммы следующая команда выбирается после того, как в стек будет помещено содержимое программного счетчика.
В гарвардской архитектуре стековые операции производятся в специально выделенной для этой цели памяти. Это означает, что при выполнении программы вызова подпрограмм процессор с гарвардской архитектурой производит несколько действий одновременно.
Необходимо помнить, что МК обеих архитектур имеют ограниченную емкость памяти для хранения данных. Если в процессоре имеется отдельный стек и объем записанных в него данных превышает его емкость, то происходит циклическое изменение содержимого указателя стека, и он начинает ссылаться на ранее заполненную ячейку стека. Это означает, что после слишком большого количества вызовов подпрограмм в стеке окажется неправильный адрес возврата. Если МК использует общую область памяти для размещения данных и стека, то существует опасность, что при переполнении стека произойдет запись в область данных либо будет сделана попытка записи загружаемых в стек данных в область ОЗУ." Я полностью согласен с EVGENIY1962, что стек лучше "руками" не трогать. А для нормальной работы стека правильно расставить приоритеты прерываний, осуществить контроль заполнения стека и при угрозе переполнения отказывать в обработке малозначительным процессам(ставить в очередь, если возможно).
|
|
|
|
10.07.2007, 07:31
|
|
Вид на жительство
Регистрация: 05.09.2006
Сообщений: 360
Сказал спасибо: 0
Сказали Спасибо 3 раз(а) в 3 сообщении(ях)
|
В программах на ассемблере состояние стека легко контролируется. И потом можно запоминать и состояние стека в переменной, а перед выходом восстанавливать указатель на адрес возврата. Я согласен, что это не совсем "правильно", но вполне возможно. "Правильней" создать переменную, в которую при обработке прерывания будет записываться признак или флаг, обзовите как угодно, а втеле программы эта переменная анализируется и происходит ветвление программы.
Но во-первых, обработчик прерываний вызывается из неопределенного места программы и возврат из прерывания произойдет в ту же неизвестную точку. Во-вторых обработка ветвлений занимает достаточно много времени и оно меняется от значения анализируемой переменной. А если человеку необходима немедленная реакцияна на событие?
Конечно все зависит от правильного (уже без кавычек) построения алгоритма программы. Выходить из прерывания описанным мной методом не рекомендуется при сложной программе. И не из-за стека, а из-за неопределенного состояния портов, переменных. Т.е. нужно уходить в процедуру реинициализации контроллера. Я думаю что в случае ухода на обработку критической ошибки, после которой следует процедура инициализации всего или рестарт программы это оправдано.
Я применял такой метод ветвления в теле прграммы (не при выходе из прерывания) с целью сократить время на обработку ветвлений при их большом количестве. К тому же, как я писал выше, это время не зависит от проверяемого значения. Строится таблица переходов в виде массива слов, где значение с индексом 0 является адресом на который нужно уходить если значение переменной равно 0 и т.д. Если кому интересно могу подробней описать.
Мой знакомый коллега использовал такой же метод и при выходе из прерывания. Все у него работает.
Не надо бояться, следует опасаться.
Конечно за стеком нужно следить, особенно при работе в Си.
Удачи.
|
|
|
|
10.07.2007, 10:46
|
|
Прохожий
Регистрация: 17.11.2006
Сообщений: 1
Сказал спасибо: 0
Сказали Спасибо 0 раз(а) в 0 сообщении(ях)
|
Для обработки ошибок в WINAVR лучше использовать
функции setjmp и longjmp модуля ‹setjmp.h›,
пример использования приведен в
WinAVRdocavr-libcavr-libc-user-manual.
|
|
|
|
10.07.2007, 12:27
|
|
Гражданин KAZUS.RU
Регистрация: 27.07.2006
Сообщений: 659
Сказал спасибо: 0
Сказали Спасибо 4 раз(а) в 4 сообщении(ях)
|
Сообщение от bamu
|
Для обработки ошибок в WINAVR лучше использовать
функции setjmp и longjmp модуля ‹setjmp.h›,
пример использования приведен в
WinAVRdocavr-libcavr-libc-user-manual.
|
Согласен.GOTO проще и безопаснее CALL.Про авр не знаю но в мелких пиках до стека прото так не добраться.
|
|
|
|
10.07.2007, 12:33
|
|
Гражданин KAZUS.RU
Регистрация: 04.08.2006
Сообщений: 911
Сказал спасибо: 28
Сказали Спасибо 180 раз(а) в 139 сообщении(ях)
|
В основном Вам ответили.
Про прерывания я соглашусь с double_dash. Это найболее коректный ответ на мой взгляд.
По выходу.
Действительно бывают такие ситуации (обычно аварийные) когда из любого места программы (в том числе из прерывания) лучше выйти в конкретное место. Обработчика аварии. Во всяком случае я такое делал. Как и другие я выполнял это на ассемблере. В добавление тех способов что вам перечислии (1. подсовывание адреса в стэк и возврат, 2. сброс стека и прямой переход) я добавлю ещё один. Инициализация стека и прямой переход. В принципе 1 и 3 способ можно реализовать на IAR C. С GCC к сожелению не знаком. Но я рекомендовал бы сделать следующее (если другим способом - ну никак)
По аварии выходить на JMP 0. А при инициализации проверять как мы попали в место старта. В этом случае у вас гарантированно будет всё нормально со всеми вашими переменными и стеками. (в смысле они инициализируются) Теже которые нельзя трогать необходимо разместить в сегменте неинициализированных.
Короче совтовый вариант WDT.
|
|
|
|
10.07.2007, 13:18
|
|
Вид на жительство
Регистрация: 05.09.2006
Сообщений: 360
Сказал спасибо: 0
Сказали Спасибо 3 раз(а) в 3 сообщении(ях)
|
Сообщение от SasaVitebsk
|
По аварии выходить на JMP 0. А при инициализации проверять как мы попали в место старта. В этом случае у вас гарантированно будет всё нормально со всеми вашими переменными и стеками. (в смысле они инициализируются) Теже которые нельзя трогать необходимо разместить в сегменте неинициализированных.
Короче совтовый вариант WDT.
|
Вариант с аппаратным WDT или вызовом его срабатывания из программы - "5". При этом инициализируются все регистры микроконтроллера. Вариант же GOTO из прерывания на точку старта, даже если Вы всю периферию и переменные проинициализировали, в т.ч. указатель стека, может привести к неприятным последствиям. Пример, в MSC-51 имеется служебный недоступный регистр обработчика прерываний, который устанавливается вначале обработки прерывания и сбрасывается только командой RETI (этим она и отличается от команды RET) или системой сброса. Пока триггер не сбросится, обработки прерываний не будет. К сожалению про этот триггер мало написано в даташите. Не уверен, есть-ли такое в AVR, скорее нет. Но я бы не рискнул выходить из прерывания без RETI, или проверил бы.
Удачи.
|
|
|
|
Ваши права в разделе
|
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения
HTML код Выкл.
|
|
|
Часовой пояс GMT +4, время: 16:22.
|
|