OBB
|
|
1 | |
Вызов подпрограммы из обработчика события28.03.2016, 15:01. Показов 14828. Ответов 53
Метки нет (Все метки)
Добрый день!
Пишу простенькую программу "мигающий светодиод". Реализовал с использованием таймера 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 |
28.03.2016, 15:01 | |
Ответы с готовыми решениями:
53
Вызов обработчика события Вызов обработчика события. Ручной вызов обработчика события Косвенный вызов DoEvents() из обработчика события? |
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 |
Сообщение от Пагранист
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
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
0
|
0 / 0 / 0
Регистрация: 06.12.2016
Сообщений: 3,044
|
|
29.03.2016, 07:27 | 11 |
Сообщение от Пагранист
0
|
1 / 1 / 0
Регистрация: 09.08.2014
Сообщений: 96
|
|
29.03.2016, 08:52 | 12 |
Сообщение от dymyurk1978
Вы так и не дали конкретного ответа по поводу процитированной мною вашей фразы.
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 |
Сообщение от Пагранист
Код
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 Код
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
Т.е. должна быть следующая последовательность условие выполняется 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 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
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
Сообщение от dymyurk1978
0
|
0 / 0 / 0
Регистрация: 06.12.2016
Сообщений: 3,044
|
|
29.03.2016, 16:17 | 19 |
Сообщение от Пагранист
В твоем примере rcall. Это лишний вызов в прерывании. У меня же переходы. И автору решать, как ему поступать в соответствии с его задачей.
Сообщение от Пагранист
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 // Код
ChangeState: LDI counter, $00 COM currentValue OUT PORTB, currentValue reti // Здесь выдернули адрес возврата, куда возвращаться? Срыв программы.
0
|
29.03.2016, 16:30 | |
29.03.2016, 16:30 | |
Помогаю со студенческими работами здесь
20
Вызов единственного обработчика события при переопределении Вызов обработчика события после вывода изображения на оси Вызов обработчика кнопки из другого обработчика. Создание объекта-события и обработчика события Выход из обработчика события Создание обработчика события Подключение обработчика события Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |