Форум программистов, компьютерный форум, киберфорум
Микроконтроллеры ATmega AVR
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.62/78: Рейтинг темы: голосов - 78, средняя оценка - 4.62
OBB
1

Вызов подпрограммы из обработчика события

28.03.2016, 15:01. Показов 14828. Ответов 53
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Добрый день!

Пишу простенькую программу "мигающий светодиод".

Реализовал с использованием таймера 0.

Код
.def temp = r16 ;рабочая переменная
.def counter = r17 ;счетчик
.def max_counter_value = r18 ;счетчик
.def currentValue = r19 ;результат
;============ прерывания ============
rjmp RESIT ;RESIT External Pin, Power-on Riset, Brown-out Riset, Watchdog Riset
reti ;INT0 External Ymtirrupt Request 0
reti ;PCINT0 Pin Change Ymtirrupt Request 0
reti ;TIMER1_COMPA Timer/Counter1 Compare Match A
reti ;TIMER1_OVF Timer/Counter1 Overflow
rjmp TIMER0_OVF;TIMER0_OVF Timer/Counter0 Overflow
reti ;EE_RDY EEPROM Ready
reti ;ANA_COMP Analog Comparator
reti ;ADC ADC Conversion Complete
reti ;TIMER1_COMPB Timer/Counter1 Compare Match B
reti ;TIMER0_COMPA Timer/Counter0 Compare Match A
reti ;TIMER0_COMPB Timer/Counter0 Compare Match B
reti ;WDT Watchdog Time-out
reti ;USI_START USI START
reti ;USI_OVF USI Overflow

RESIT: ;начальная инициализация
ldi temp,low(ROMEND) ;загрузка указателя стека
out SPL,temp

LDI currentValue, $00

ldi temp, $05
out TCCR0B,temp

ldi max_counter_value, $33

CLR temp
OUT SREG, temp

LDI temp, $FF
OUT DDRB, temp

clr counter ;очищаем счетчик
clr temp
ldi temp,(1<<TOIE0) ;разр. прерывания Timer0
out TIMSK,temp

sei ;разрешаем прерывания

Gcykle: ;основной пустой цикл
rjmp Gcykle

TIMER0_OVF:;обработчик прерывания Timer0
yms counter ;в каждом прерывании увеличиваем на 1
CP counter, max_counter_value
BRSH ChangeState
;некий код который надо выполнить даже в случае перехода на ChangeState
reti ;конец обработки прерывания таймера

ChangeState:
LDI counter, $00
COM currentValue
OUT PORTB, currentValue
reti
Собственно все работает, но возник вопрос с ветвлением. После выполнения ChangeState программа возвращается в пустой цикл. А если требуется возврат в обработчик прерывания в то же место откуда произошел вызов, то как это реализовать?
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
28.03.2016, 15:01
Ответы с готовыми решениями:

Вызов обработчика события
есть два обработчика события button1.Click и button2.Click . Как из button1.Click вызвать...

Вызов обработчика события.
Можно ли из одного обработчика события, например: void __fastcall TForm1::Button1Click(TObject...

Ручной вызов обработчика события
Здравствуйте, никак не могу разобраться с вызовом метода. void Grid_ManipulationStarting(object...

Косвенный вызов DoEvents() из обработчика события?
В одном приложении столкнулся со следующим явлением : программа сработала так, как если бы событие...

53
1 / 1 / 0
Регистрация: 09.08.2014
Сообщений: 96
28.03.2016, 16:21 2
Код
TIMER0_OVF:;обработчик прерывания Timer0
yms counter ;в каждом прерывании увеличиваем на 1
CP counter, max_counter_value
BRLO AAA ; обойти если меньше
rcall ChangeState ; вызвать ПП  если больше или равно
AAA:
;некий код который надо выполнить даже в случае перехода на ChangeState
reti ;конец обработки прерывания таймера

ChangeState:
LDI counter, $00
COM currentValue
OUT PORTB, currentValue
RET ; вернуться из ПП
Так не пойдет?
0
OBB
28.03.2016, 16:40 3
"Так не пойдет?"

Сначала пытался писать при переходе с BRSH в конце ChangeState RET, как у вас, но возврат происходил в основной цикл, при том без последующей обработки прерываний так как, как позже прочитал, при возврате через ret не устанавливается разрешение прерываний. Замена на reti вернула прерывания, но возврат происходил все равно в основной цикл.

А по вашему примеру, при вызове через rcall, возвращается прямо куда нужно. Спасибо.
1 / 1 / 0
Регистрация: 09.08.2014
Сообщений: 96
28.03.2016, 22:58 4
Код
TIMER0_OVF:;обработчик прерывания Timer0
yms counter ;в каждом прерывании увеличиваем на 1
CP counter, max_counter_value
BRLO AAA ; обойти если меньше
rjmp ChangeState ; перейти  если больше или равно
AAA:
;некий код который надо выполнить даже в случае перехода на ChangeState
reti ;конец обработки прерывания таймера

ChangeState:
LDI counter, $00
COM currentValue
OUT PORTB, currentValue
rjmp AAA ; вернуться
Или вот так, что бы лишний раз стек не напрягать.
0
0 / 0 / 0
Регистрация: 28.01.2012
Сообщений: 499
28.03.2016, 23:11 5
Цитата Сообщение от Пагранист
Код:
TIMER0_OVF:;обработчик прерывания Timer0
yms counter ;в каждом прерывании увеличиваем на 1
CP counter, max_counter_value
BRLO AAA ; обойти если меньше
rjmp ChangeState ; перейти если больше или равно
AAA:
;некий код который надо выполнить даже в случае перехода на ChangeState
reti ;конец обработки прерывания таймера

ChangeState:
LDI counter, $00
COM currentValue
OUT PORTB, currentValue
rjmp AAA ; вернуться

Или вот так, что бы лишний раз стек не напрягать.А не проще ChangeState-процедуру без rjmp AAA поставить вместо rjmp ChangeState? Сразу на два прыжка меньше.
0
0 / 0 / 0
Регистрация: 06.12.2016
Сообщений: 3,044
28.03.2016, 23:56 6
Я бы не советовал излишне баловаться джампами. Если вызовете подпрограмму, которая заканчивается rjmp или прыгнуть в подпрограмму которая заканчивается ret\i, то получите необъяснимое поведение программы.
0
0 / 0 / 0
Регистрация: 02.10.2012
Сообщений: 1,946
29.03.2016, 01:35 7
Код
TIMER0_OVF:;обработчик прерывания Timer0
in  temp,SREG
push temp
yms counter ;в каждом прерывании увеличиваем на 1
CP counter, max_counter_value
BRSH ChangeState
;некий код который надо выполнить даже в случае перехода на ChangeState
ChangeState:
LDI counter, $00
COM currentValue
OUT PORTB, currentValue
pop temp
out Sreg,temp
reti
0
1 / 1 / 0
Регистрация: 09.08.2014
Сообщений: 96
29.03.2016, 02:26 8
Цитата Сообщение от Fohyvis
А не проще ChangeState-процедуру без rjmp AAA поставить вместо rjmp ChangeState? Сразу на два прыжка меньше.
Проще конечно. При условии что данный кусок кода больше ни где не нужен. Но ведь изначально ТС зачем то его выделил в отдельный фрагмент. Думаю если он не только долбит одну задачу, но и учится все предложенные варианты, включая ваш, будут приняты им к сведению.

UPD соотнес ваше возражение к первому своему примеру с rcall. Между тем как действительно вы правы, данную портянку проще вставить вместо rjmp AAA. Шаблонное мышление.
0
1 / 1 / 0
Регистрация: 09.08.2014
Сообщений: 96
29.03.2016, 02:31 9
YTYOUT, вас не смущает что в вашем примере код после метки ChangeState выполняется при любом раскладе, а у ТС по условию.
0
1 / 1 / 0
Регистрация: 09.08.2014
Сообщений: 96
29.03.2016, 02:36 10
Цитата Сообщение от dymyurk1978
или прыгнуть в подпрограмму которая заканчивается ret\i, то получите необъяснимое поведение программы.
Я что то недопонял вашу мысль. Обычно ПП так и заканчивается - ret.
0
0 / 0 / 0
Регистрация: 06.12.2016
Сообщений: 3,044
29.03.2016, 07:27 11
Цитата Сообщение от Пагранист
Я что то недопонял вашу мысль. Обычно ПП так и заканчивается - ret.
Начинающие не совсем понимают принцип вызова подпрограмм, и еще не научились выстраивать должным образом саму программу. В итоге начинают развешивать лапшу из r\jmp и как попало использовать r\call. Из-за чего и могут получить пыльным мешком из-за угла.
0
1 / 1 / 0
Регистрация: 09.08.2014
Сообщений: 96
29.03.2016, 08:52 12
Цитата Сообщение от dymyurk1978
Цитата Сообщение от Пагранист
Я что то недопонял вашу мысль. Обычно ПП так и заканчивается - ret.
Начинающие не совсем понимают принцип вызова подпрограмм, и еще не научились выстраивать должным образом саму программу. В итоге начинают развешивать лапшу из r\jmp и как попало использовать r\call. Из-за чего и могут получить пыльным мешком из-за угла.
Вы так и не дали конкретного ответа по поводу процитированной мною вашей фразы.
прыгнуть в подпрограмму которая заканчивается ret\i, то получите необъяснимое поведение программы
"пыльные мешки", "лапша" и пр. конечно ярко и образно. Но чем как не ret по вашему должна заканчиваться подпрограмма?
0
0 / 0 / 0
Регистрация: 06.12.2016
Сообщений: 1,864
29.03.2016, 09:13 13
dymyurk1978, наверное, надо всё-таки учить людей, начиная с языков высокого уровня, чтобы jmp из одной подпрограммы в другую даже в голову не приходил (а если и придёт - думали бы "ну, это высокая нигия seniorов, мне так нельзя").
0
0 / 0 / 0
Регистрация: 02.10.2012
Сообщений: 1,946
29.03.2016, 09:59 14
Цитата Сообщение от Пагранист
YTYOUT, вас не смущает что в вашем примере код после метки ChangeState выполняется при любом раскладе, а у ТС по условию.
;некий код который надо выполнить даже в случае перехода на ChangeState
Смотрим Код ТС :

Код
CP counter, max_counter_value  //Сравниваем
BRSH ChangeState  // Если больше или равно топаем на  ChangeState
//Меньше
;некий код который надо выполнить даже в случае перехода на ChangeState
reti и уходим не выполнив строку выше
ChangeState:
LDI counter, $00
COM currentValue
OUT PORTB, currentValue
pop temp
out Sreg,temp
reti
Убираем reti

Код
CP counter, max_counter_value  //Сравниваем
BRSH ChangeState  // Если больше или равно топаем на  ChangeState
//Меньше
;Выполняем некий код , который надо выполнить даже в случае перехода на ChangeState
ChangeState:
LDI counter, $00
COM currentValue
OUT PORTB, currentValue
pop temp
out Sreg,temp
reti
Ну и в чём разница

Код
TIMER0_OVF:;обработчик прерывания Timer0
yms counter ;в каждом прерывании увеличиваем на 1
CP counter, max_counter_value
BRLO AAA ; обойти если меньше
rjmp ChangeState ; перейти  если больше или равно
AAA:
;некий код который надо выполнить даже в случае перехода на ChangeState
reti ;конец обработки прерывания таймера

ChangeState:
LDI counter, $00
COM currentValue
OUT PORTB, currentValue
rjmp AAA ; вернуться
0
1 / 1 / 0
Регистрация: 09.08.2014
Сообщений: 96
29.03.2016, 10:35 15
Цитата Сообщение от YTYOUT
Ну и в чём разница
Видимо разница в том, что вы прочитали код, но не прочитали в чём проблема ТС. А проблема заключалась вследующем.
Собственно все работает, но возник вопрос с ветвлением. После выполнения ChangeState программа возвращается в пустой цикл. А если требуется возврат в обработчик прерывания в то же место откуда произошел вызов, то как это реализовать?
комментарий в коде
;некий код который надо выполнить даже в случае перехода на ChangeState
как бы даёт понять, что это место должно работать всегда и после отработки ChangeState и без.

Т.е. должна быть следующая последовательность
условие выполняется
1. ChangeState
2. ;некий код который надо выполнить даже в случае перехода на ChangeState
3. reti

НЕ выполняется, то просто
1. ;некий код который надо выполнить даже в случае перехода на ChangeState
2. reti

В вашем же случае получается что

если оно выполняется
1. ChangeState
2. reti

если НЕ выполняется
1. ;некий код который надо выполнить даже в случае перехода на ChangeState
2. ChangeState
3. reti
0
0 / 0 / 0
Регистрация: 02.10.2012
Сообщений: 1,946
29.03.2016, 11:32 16
как бы даёт понять, что это место должно работать всегда и после отработки ChangeState и без.
Код
;некий код который надо выполнить даже в случае перехода на ChangeState
CP counter, max_counter_value  //Сравниваем
BRSH ChangeState  // Если больше или равно топаем на  ChangeState
reti
ChangeState:
LDI counter, $00
COM currentValue
OUT PORTB, currentValue
pop temp
out Sreg,temp
reti
0
0 / 0 / 0
Регистрация: 06.12.2016
Сообщений: 3,044
29.03.2016, 13:13 17
Цитата Сообщение от YTYOUT
Код:
;некий код который надо выполнить даже в случае перехода на ChangeState
CP counter, max_counter_value //Сравниваем
BRSH ChangeState // Если больше или равно топаем на ChangeState
reti // Выход без восстановления. И стек засран SREG-ом. Куда возвращаться? Срыв программы.
ChangeState:
LDI counter, $00
COM currentValue
OUT PORTB, currentValue
pop temp
out Sreg,temp
reti // Здесь выдернули адрес возврата, куда возвращаться? Срыв программы.

Исправленный пример:
Код
TIMER0_OVF: ;обработчик прерывания Timer0
in r16, SREG
push r16
yms counter ;в каждом прерывании увеличиваем на 1
CP counter, max_counter_value
BRSH ChangeState
TIMER0_OVF_1:
;некий код который надо выполнить даже в случае перехода на ChangeState
rjmp TIMER0_OVF_End
ChangeState:
LDI counter, $00
COM currentValue
OUT PORTB, currentValue
rjmp TIMER0_OVF_1

TIMER0_OVF_End:
pop r16
out SREG, r16
reti
Примерно об этом я и говорил. Сначала научиться ветвлениям. Чтобы не лапша была, а стройная программа. Нужно понять, как работает стек. Тщательно продумывать программу. Если чувствуете, что начинается лапша и путаница из переходов, нужно пересматривать задачу. По сути написание программы на асме - игра в кубики. Иногда нужно полностью снести всю конструкцию, чтобы получить нужный результат.

В принципе, ничего сложного нет. r\jmp - это прыжок. Сохранения\восстановления стека не требуется и здесь нужно следить, чтобы не прыгнули в подпрограмму, если ДО этого не было вызова. Также нужно отслеживать как раз ошибку Ильи с сохранением\восстановлением SREG и регистров.

r\call - вызов подпрограммы. Если вы прыгаете в подпрограмму, то должны тщательно отслеживать, чтобы не сорвать стек. Скажем, как в последнем примере Ильи.

И кстати, самый правильный вариант у Паграниста. Единственное, что, нужно не забывать о сохранении\восстановлении SREG и регистров в прерывании. Но в данном случае этого не требуется, так как основной цикл пустой.

Автору: ассемблер сильно деформирует мышление. Всегда есть риск скатиться следить за мелочами, но не видеть целой картины. Поэтому научитесь проектировать "сверху вниз". Устройство, модули устройства, подмодули и собссно уже возня с битиками, байтиками. Это относится как к устройству в целом, так и к задачам-модулям программы. И да, модульность. Программа состоит из модулей. Опрос клавиатуры - модуль. И так далее.
0
1 / 1 / 0
Регистрация: 09.08.2014
Сообщений: 96
29.03.2016, 16:04 18
YTYOUT, как то на мой взгляд
а) громоздко
б) разрешаете прерывания раньше чем надо. Второй reti стоило бы заменить на ret
ИМХО разумеется

Цитата Сообщение от dymyurk1978
И кстати, самый правильный вариант у Паграниста
Мне кажется самое разумное решение это
Цитата Сообщение от Fohyvis
А не проще ChangeState-процедуру без rjmp AAA поставить вместо rjmp ChangeState? Сразу на два прыжка меньше.
Если процедура кроме как данным обработчиком прерывания больше ни где не выполняется, то и незачем её из обработки прерывания выносить. В таком варианте она кстати и с вашей мыслью перекликается
Цитата Сообщение от dymyurk1978
Я бы не советовал излишне баловаться джампами.
0
0 / 0 / 0
Регистрация: 06.12.2016
Сообщений: 3,044
29.03.2016, 16:17 19
Цитата Сообщение от Пагранист
...
Мы не знаем, что у автора в "а здесь нужно выполнить некий код", используется ли change_state где-то еще. Может автор нам не полную программу показал.
В твоем примере rcall. Это лишний вызов в прерывании. У меня же переходы. И автору решать, как ему поступать в соответствии с его задачей.
Цитата Сообщение от Пагранист
Цитата Сообщение от dymyurk1978
Я бы не советовал излишне баловаться джампами.
Мы не знаем всей задачи, поэтому предлагаю не меряться, у кого короче.
0
0 / 0 / 0
Регистрация: 02.10.2012
Сообщений: 1,946
29.03.2016, 16:30 20
Во-общето я просто сократил шапку обработчика прерывания.
Код
TIMER0_OVF:;обработчик прерывания Timer0
yms counter ;в каждом прерывании увеличиваем на 1
А так как некий код должен выполнятся всегда , то он не зависит от команд сравнения и переходов.
Код
;некий код который надо выполнить даже в случае перехода на ChangeState
то и его пихаем до сравнения ( кстати я почти знаю что в нем)
Код
CP counter, max_counter_value  //Сравниваем
BRSH ChangeState  // Если больше или равно топаем на  ChangeState
reti //
Выход без восстановления. И стек засран SREG-ом. Куда возвращаться? Срыв программы.
Но в данном случае этого не требуется, так как основной цикл пустой.
Код
 ChangeState:
LDI counter, $00
COM currentValue
OUT PORTB, currentValue
reti // Здесь выдернули адрес возврата, куда возвращаться? Срыв программы.
Так , что лишние метки не нужны
0
29.03.2016, 16:30
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
29.03.2016, 16:30
Помогаю со студенческими работами здесь

Вызов единственного обработчика события при переопределении
Все привет! Вопрос по теории. Можно ли как-то сделать так, чтобы при перекрытии обработчика события...

Вызов обработчика события после вывода изображения на оси
Доброго времени суток! Подскажите, пожалуйста, как вызвать функцию обработчика нажатия на оси...

Вызов обработчика кнопки из другого обработчика.
Есть кнопка, есть у ней обработчик, который делает нечто полезное. Как вызвать выполнения...

Создание объекта-события и обработчика события
Допустим у меня есть следующий класс: public class Example { private boolean bool; public...

Выход из обработчика события
Подскажите пожалуйста как в С++ (Visual Studio 2008) выйти из обработчика событий. Конкретно:...

Создание обработчика события
Пытаюсь создатьобработчик события для динамически созданного элемента. В unit.cpp void __fastcall...

Подключение обработчика события
Привет всем, подскажите пожалуйста, как подключить событие к блочному елементу div используя JS?...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru