|
Как перейти к началу функции по внешнему прерыванию?, подробнее внутри |
|
|
|
Aug 15 2008, 13:30
|
Местный
  
Группа: Свой
Сообщений: 413
Регистрация: 15-12-06
Пользователь №: 23 563

|
Господа есть код в CodeVision примерно такой: Код void loop() { for (i=0;i<360;i++) { ................. }
}
void afterINT() { ..... }
void main () { while (1==1) { ...... loop(); ..... } } Как сделать чтобы по внешнему прерыванию от пина AVR функция loop завершала свою работу? выполнялась функция afterINT(), после чего вновь запускалась функция loop(). Пишу в CodeVision, но буду рад примеру и в WinAVR. И еще - в ATMEGA32 INT0, INT1 и INT2 чемн-ниьбудь отличаются?
|
|
|
|
|
 |
Ответов
|
Aug 17 2008, 17:42
|
Профессионал
    
Группа: Свой
Сообщений: 1 719
Регистрация: 13-09-05
Из: Novosibirsk
Пользователь №: 8 528

|
Цитата(zltigo @ Aug 17 2008, 18:10)  Рассуждай токмо о том, о чём понятия твои тебе сие дозволяют. Так: не зная законов языка ирокезского, можешь ли ты делать такое суждение по сему предмету, которое не было бы неосновательно и глупо? (с) Козьма Прутков. Афоризмы  Понятия дозволяют. Я законы языка ирокез С ещё на PDP-11 изучал. И с работой setjmp/longjmp тогда же разбирался. Цитата(aaarrr @ Aug 17 2008, 18:14)  Замечательно. А вы умеете готовить программы, которые будут нормально работать при вываливании из любой точки после прерывания в другую? Чтобы из любой - это гораздо сложнее. Но Вас же не удивляет что любая (некооперативная) RTOS может передать управление другому процессу после того как текущий был прерван прерыванием? Разбираемый сейчас случай попроще будет. Требуется поведение программы типа "всё бросить и вернуться на заранее подготовленные позиции", как раз для такого эти функции и предназначены. В популярных учебниках тему setjmp/longjmp предпочитают не затрагивать, вот народ про них почти ничего и не знает. Попробую рассказать что знаю, с некоторыми упрощениями. Функция setjmp() всего лишь запоминает в специальном буфере содержимое нескольких регистров, указатель стека и счётчик команд (адрес возврата, лежащий в стеке). Эта информация потом, при исполнении longjmp(), позволяет восстановить состояние программы таким, словно только что произошел возврат из setjmp(). Отличается только возвращаемое значение, setjmp() возвращает 0, а longjmp() возвращает свой второй аргумент. Это позволяет понять откуда попало управление в этот раз. Разумеется, восстанавливается далеко не всё, скажем если программа успела изменить глобальные переменные то эти изменения не будут откачены назад, ну так это-то уже в руках программиста, и он может это предусмотреть, если бывает нужно "прибрать за собой". Поскольку longjmp() переставляет указатель стека на прежнее место, то существует естественное ограничение на её применение: состояние той части стека, которая существовала на момент возврата из setjmp() не должно изменяться до выполнения longjmp(). Другими словами, не должно быть выхода из функции или блока, содержащего setjmp(). А с учетом архитектуры AVR и имеющейся реализации этих функций не вижу никаких препятствий для примения longjmp() прямо из обработчика прерывания. Реализацию в CodeVision надо проверить, но скорее всего и там будет работать. Примерно так (для IAR): Код jmp_buf jbuf;
int foo() { if( setjmp( jbuf ) ) { // исполняется только после перехода по longjmp() //если переход делать прямо из обработчика, то прерывания останутся запрещёнными __enable_interrupt(); afterINT(); } else { // исполняется после возврата из setjmp() }
for(;;) { loop(); //........ } }
#pragma vector=INT0_vect __interrupt void INT0_isr(void) { longjmp( jbuf, 1); }
--------------------
Russia est omnis divisa in partes octo.
|
|
|
|
Guest_@Ark_*
|
Aug 18 2008, 13:37
|
Guests

|
Цитата(SSerge @ Aug 17 2008, 21:42)  ... Разбираемый сейчас случай попроще будет. Требуется поведение программы типа "всё бросить и вернуться на заранее подготовленные позиции" ... Интересно, как Вы собираетесь обрабатывать ситуацию с вложенными прерываниями, которая в общем случае теоретически возможна? Ведь тогда, номинально, нужно возвращаться не вашу программу, а в обработчик другого прерывания. Если заменить адрес возврата или сделать прямой переход, то обработка другого прерывания останется незавершенной, с неизвестными последствиями. Причем, так как ситуация довольно редкая, "скорее всего все будет работать". Но с редкими и непредсказуемыми "глюками" где-то совсем в другом месте , причину которых потом практически невозможно найти...
|
|
|
|
|
Aug 18 2008, 15:25
|
Местный
  
Группа: Участник
Сообщений: 336
Регистрация: 7-03-07
Из: Петербург
Пользователь №: 25 961

|
Прежде всего, спасибо всем за возможность освежить знания о setjmp/longjmp. Как всегда, когда имеешь дело с чем-то выходящим за пределы контекста С, выясняется, что от процессора к процессору и от компилятора к компилятору, алгоримт работы таких компонент может варьироваться. Я просмотрел три варианта setjmp/longjmp, в TI CCS для ARM и С6000, и в очень старом компиляторе MS QuickC 2.5 для 16 бит x86. QC мспользует setjmp/longjmp в своем примере для обработки прерывания по ошибке FPU, тогда как нарямую, без дополнительного кода, использовать setjmp/longjmp внутри прерывания ARM или С6000 нельзя. Конечно, если дополнить код ISR (или setjmp/longjmp), то нет никаких препятствий для использования setjmp/longjmp внутри прерывания. В любом случае, setjmp/longjmp были в первую очередь созданы для обхода правил передачи управления установленных языком С. Где не хватает возможностей высокого уровня надо использовать низкоуровневые средства. Цитата(@Ark @ Aug 18 2008, 16:37)  Интересно, как Вы собираетесь обрабатывать ситуацию с вложенными прерываниями, которая в общем случае теоретически возможна? Ведь тогда, номинально, нужно возвращаться не вашу программу, а в обработчик другого прерывания. Если заменить адрес возврата или сделать прямой переход, то обработка другого прерывания останется незавершенной, с неизвестными последствиями. Причем, так как ситуация довольно редкая, "скорее всего все будет работать". Но с редкими и непредсказуемыми "глюками" где-то совсем в другом месте , причину которых потом практически невозможно найти... Все эти опасения (как и те, которые следуют из некоторой неопределенности постановки задачи у автора треда), конечно нужно принять во внимание. И, соответствующим образом, обработать. Например, усложнение алгоритма, вызванное возможной вложенностью, обходится при помощи счетчика вложенности прерываний (надеюсь, что никого этим не удивил), и так далее. Для меня удивительным оказалось то, что сама постановка задачи (может быть, с точки зрения эстетики и не самая красивая, но уж точно непротиворечивая) вызвала такую бурную дискуссию. -- AN
|
|
|
|
Guest_@Ark_*
|
Aug 18 2008, 17:28
|
Guests

|
Цитата(AndrewN @ Aug 18 2008, 19:25)  ... Все эти опасения (как и те, которые следуют из некоторой неопределенности постановки задачи у автора треда), конечно нужно принять во внимание. И, соответствующим образом, обработать. Например, усложнение алгоритма, вызванное возможной вложенностью, обходится при помощи счетчика вложенности прерываний... Вы, возможно, не поняли о чем речь, или я плохо сформулировал. Счетчик тут не поможет. Речь идет не об одном и том же прерывании, а о прерывании работы другого обработчика прерываний. Например, обработчик прерывания в каком-нибудь драйвере ОС, может запрещать прерывания только в своей критической части кода. А дальше - они разрешены, хотя сама процедура обработки прерывания еще не завершена. И вот, в этот неподходящий момент, может возникнуть ваше прерывание, после которого вы не возвращаете управление. Работа драйвера будет нарушена. P.S. На такие "грабли" лучше не наступать. Замучеетесь искать причину...
|
|
|
|
|
Aug 18 2008, 19:06
|
Местный
  
Группа: Участник
Сообщений: 336
Регистрация: 7-03-07
Из: Петербург
Пользователь №: 25 961

|
Цитата(@Ark @ Aug 18 2008, 20:28)  Вы, возможно, не поняли о чем речь, или я плохо сформулировал. Счетчик тут не поможет. Речь идет не об одном и том же прерывании, а о прерывании работы другого обработчика прерываний. Например, обработчик прерывания в каком-нибудь драйвере ОС, может запрещать прерывания только в своей критической части кода. А дальше - они разрешены, хотя сама процедура обработки прерывания еще не завершена. И вот, в этот неподходящий момент, может возникнуть ваше прерывание, после которого вы не возвращаете управление. Работа драйвера будет нарушена. P.S. На такие "грабли" лучше не наступать. Замучеетесь искать причину... Конечно, такая вложенность вполне возможна. И в таком случае в ISR, которая выполняет, назовем это так, "необычный" возврат, счетчик вложенности > 1, и ISR должна должна выполнить наиболее подходящие действия. Возможно, что нужно переделать логику у всех возможных ISR - некий аналог планировщика, который осуществляет только два вида выхода из прерывания - или обычный возврат или "необычный" возврат на начало loop() . Другой пример: в исходной задаче говорится, что переход на начало loop() из прерывания (т.е. из ISR, обрабатывающей прерывание от соответствующего устройства) должен происходить в том случае, если была прервана сама подпрограмма loop(), если я не ошибаюсь. Это значит, что ISR должна анализировать такое событие, т.е. еще один флаг, на этот раз бинарный. Вероятно, автору придется помучится, а как же без этого? С другой стороны, существует отличная от нуля вероятность, что это мы тут мучаемся (бесплодно...), а заказчик автора имел ввиду совершенно другой алгоритм, или вопрос был сформулирован совсем уж плохо. Кто знает?.. Если исходить из общей формулировки задачи реального времени, я склоняюсь в пользу последнего. В самом деле, если прерывания приходят так часто, что loop() вообще никогда не имеет возможности довести свои вычисления до конца, что эквивалентно тому, что управляющие действия никогда не будут осуществлены. Возможна ли такая крайность? Возможно, что и нет, что только иногда loop() не будет успевать завершиться до следующего прерывания и, поэтому, выбран алгоритм, который вместо буферизации запросов использует алгоритм своего рода "забывания" о предыдущем, неисполненном запросе. Про ОС очень хорошее замечание. Сейчас мне кажется, что исходную задачу можно решить с помощью двух процессов, один управляющий, который или запускает или снимает с исполнения (фактически, перезапускает) второй процесс, который производит вычисления и управляет внешним устройством. Я подробно о таком способе пока не думал. -- AN
|
|
|
|
Сообщений в этой теме
Зверюга Как перейти к началу функции по внешнему прерыванию? Aug 15 2008, 13:30 GDI ЦитатаКак сделать чтобы по внешнему прерыванию от ... Aug 15 2008, 13:38 Зверюга Цитатапрерывания, или вам надо чтобы после прерыва... Aug 15 2008, 13:46 GDI Можно в цикле что внутри loop() проверять некий фл... Aug 15 2008, 14:00 AHTOXA Можно в прерывании подменять адрес возврата. Но эт... Aug 15 2008, 14:14 bzx Цитата(AHTOXA @ Aug 15 2008, 18:14) Можно... Aug 15 2008, 16:14 rezident В plain Си функция не может перезапустить саму себ... Aug 15 2008, 15:01 Kuzmi4 2 Зверюга
ЦитатаА все-таки?
0 от 1 отличаются вро... Aug 15 2008, 15:01 Зверюга ЦитатаТолько не забудьте присвоить переменной флаг... Aug 15 2008, 16:00 zltigo Цитата(Зверюга @ Aug 15 2008, 18:00) Так ... Aug 15 2008, 16:16 rezident Цитата(Зверюга @ Aug 15 2008, 22:00) Так ... Aug 15 2008, 16:27 Зверюга Цитата{ cntr--;
}
Эта строчка "от балды... Aug 15 2008, 16:57 rezident Цитата(Зверюга @ Aug 15 2008, 22:57) Эта ... Aug 15 2008, 17:17  zltigo Цитата(rezident @ Aug 15 2008, 19:17) ...... Aug 15 2008, 17:49   rezident Цитата(zltigo @ Aug 15 2008, 23:49) грамо... Aug 15 2008, 19:42    zltigo Цитата(rezident @ Aug 15 2008, 21:42) ...... Aug 15 2008, 20:53     rezident Цитата(zltigo @ Aug 16 2008, 02:53) Масло... Aug 15 2008, 21:18      zltigo Цитата(rezident @ Aug 15 2008, 23:18) ..м... Aug 15 2008, 22:05      Aesthete Animus Цитата(rezident @ Aug 16 2008, 01:18) К т... Aug 15 2008, 23:12       rezident Цитата(Aesthete Animus @ Aug 16 2008, 05... Aug 15 2008, 23:34 Зверюга Спасибо, теперь я разобрался. Это точно для CodeVi... Aug 15 2008, 17:37 zltigo Цитата(rezident @ Aug 16 2008, 01:34) ОК.... Aug 16 2008, 08:58 rezident Цитата(zltigo @ Aug 16 2008, 14:58) Э... ... Aug 16 2008, 12:17  zltigo Цитата(rezident @ Aug 16 2008, 14:17) Я н... Aug 16 2008, 12:35 aaarrr Цитата(rezident @ Aug 16 2008, 16:17) Я н... Aug 16 2008, 12:36 rezident Цитата(aaarrr @ Aug 16 2008, 18:36) Так з... Aug 16 2008, 12:40  zltigo Цитата(rezident @ Aug 16 2008, 14:40) Доб... Aug 16 2008, 12:52   rezident Цитата(zltigo @ Aug 16 2008, 18:52) Для н... Aug 16 2008, 13:23    aaarrr Цитата(rezident @ Aug 16 2008, 17:23) Пос... Aug 16 2008, 13:43    zltigo Цитата(rezident @ Aug 16 2008, 15:23) А в... Aug 16 2008, 13:52 SSerge Вообще-то для таких "фокусов" придуманы ... Aug 16 2008, 21:20 aaarrr Цитата(SSerge @ Aug 17 2008, 01:20) Вообщ... Aug 16 2008, 21:43  SSerge Цитата(aaarrr @ Aug 17 2008, 04:43) Не дл... Aug 17 2008, 11:03   zltigo Цитата(SSerge @ Aug 17 2008, 13:03) Вот к... Aug 17 2008, 11:10   aaarrr Цитата(SSerge @ Aug 17 2008, 15:03)
Вы и... Aug 17 2008, 11:14 aaarrr Цитата(SSerge @ Aug 17 2008, 21:42) Чтобы... Aug 17 2008, 22:00 zltigo Цитата(SSerge @ Aug 17 2008, 19:42) Требу... Aug 17 2008, 22:15   aaarrr Цитата(AndrewN @ Aug 18 2008, 19:25) Для ... Aug 18 2008, 15:31 GDI не кажется что за спором вы забыли одну важную вещ... Aug 18 2008, 10:04 MMos Недавно в одной ветке, я обмолвился, что пишу на а... Aug 19 2008, 08:25 SSerge Цитата(MMos @ Aug 19 2008, 15:25) Почитал... Aug 19 2008, 09:08 zltigo Цитата(MMos @ Aug 19 2008, 10:25) В ассем... Aug 19 2008, 09:21 MMos Я суть темы понял так: при наступлении некоего соб... Aug 19 2008, 10:19 aaarrr Цитата(MMos @ Aug 19 2008, 14:19) Я суть ... Aug 19 2008, 10:25  MMos Цитата(aaarrr @ Aug 19 2008, 12:25) Не по... Aug 19 2008, 10:36 aaarrr Я тоже много лет программирую на ассемблерах (если... Aug 19 2008, 10:53 MMos Язык, на котором пишет программист, для меня не яв... Aug 19 2008, 11:16  Herz Цитата(MMos @ Aug 19 2008, 13:16) Язык, н... Aug 19 2008, 12:02   zltigo Цитата(Herz @ Aug 19 2008, 14:02) А что, ... Aug 19 2008, 13:34 SysRq Как вариант, функцию loop можно сделать полностью ... Aug 19 2008, 22:19 Dog Pawlowa Цитата(SysRq @ Aug 20 2008, 01:19) Как ва... Aug 20 2008, 05:54
3 чел. читают эту тему (гостей: 3, скрытых пользователей: 0)
Пользователей: 0
|
|
|