Чтобы вызвать прерывание от внешнего источника, на соответствующей ножке МК нужно создать необходимые электрические условия. Например, прерывание можно вызвать изменением потенциала с высокого на низкий. При этом, чтобы был вызван обработчик, прерывания в МК, необходимы следующие условия:
- прерывания должны быть разрешены глобально (бит I в регистре SREG должен быть установлен);
- конкретное прерывание должно быть разрешено (установлен соответствующий прерыванию бит в регистре GIMSK).
Низкий уровень на входе INT0, передний фронт импульса, задний фронт импульса или любые изменения на INT0 могут (по выбору программиста) вызвать прерывание. Необходимое поведение задается с помощью битов ISC01 и ISC00 регистра MCUCR.
ISC01 | ISC00 | Описание |
---|---|---|
0 | 0 | Низкий уровень на INT0 генерирует прерывание. |
0 | 1 | Любое изменение на INT0 генерирует прерывание. |
1 | 0 | Прерывание возникает по заднему фронту на INT0. |
1 | 1 | Прерывание возникает по переднему фронту на INT0. |
В МК ATiny26 есть только одно внешнее прерывание INT0. Далее речь будет идти о нем.
Прерывания в МК автоматически запрещаются при входе в обработчик - бит I в регистре SREG сбрасывается. Чтобы разрешить вложенные прерывания, его нужно установить программно с помощью команды sei. Когда производится выход из прерывания (reti), бит автоматически устанавливается.
Также сбрасывается бит INT0 в регистре GIFR. Его можно сбросить и программно, записав единицу. Этот бит устанавливается автоматически, когда возникают электрические условия для прерывания. Если при этом бит I и/или бит INT0 в GIMSK сброшены, обработчик прерывания не будет вызван.
Если в период, когда прерывание запрещено, хотя бы однажды возникнут электрические условия для прерывания, и бит INT0 в регистре GIFR установится в единицу, то когда прерывание будет разрешено, автоматически запустится его обработчик.
Как было сказано выше, GIMSK сбрасывается записью единиц. Но единица, записанная программно, именно сбрасывает GIMSK и не может стать причиной вызова обработчика.
Я написал программу, которая по возникновению прерывания INT0 запрещает это прерывание и устанавливает таймер на 4 с. По истечении времени прерывание снова разрешается. При этом в одном случае перед разрешением прерывания я сбрасываю GIMSK, а в другом - нет. На видео будет показано, что во втором случае, если во время задержки нажать на кнопку, бит INT0 в GIMSK установиться в единицу, а по окончании задержки снова будет вызван обработчик прерывания.
Первый вариант (со сбросом GIMSK перед разрешением прерываний):
.device ATiny26 .include "tn26def.inc" .def temp = r16 .def Delay_count = r17 .def GIFR_var = r18 .def Interrupt = r19 rjmp RESET ; Reset handler rjmp EXT_INT0 ; IRQ0 handler reti; rjmp PIN_CHANGE ; Pin change handler reti; rjmp TIM1_CMP1A ; Timer1 compare match 1A reti; rjmp TIM1_CMP1B ; Timer1 compare match 1B reti; rjmp TIM1_OVF ; Timer1 overflow handler rjmp TIM0_OVF ; Timer0 overflow handler reti; rjmp USI_STRT ; USI Start handler reti; rjmp USI_OVF ; USI Overflow handler reti; rjmp EE_RDY ; EEPROM Ready handler reti; rjmp ANA_COMP ; Analog Comparator handler reti; rjmp ADC ; ADC Conversion Handler ; TIM0_OVF: rcall OUT_DEBUG; dec Delay_count brne TIMER_NOT_END ;stop timer clr temp out TCCR0, temp ;allow external interrupt INT0 ldi temp, (1<<INT0) out GIMSK, temp ;the flag can be cleared by writing a logical one to it. ;ldi temp, (1<<INT0) ;clear GIFR ldi temp, $FF out GIFR, temp ldi Interrupt, 0b00000000 rcall OUT_DEBUG; TIMER_NOT_END: reti EXT_INT0: ldi Interrupt, 0b00000001 rcall OUT_DEBUG; ;disallow INT0 interrupt clr temp out GIMSK, temp rcall START_TIMER reti START_TIMER: ldi Delay_count, 255 ldi Temp, 0b00000011 out TCCR0, Temp ;start timer ret; OUT_DEBUG: in GIFR_var, GIFR rol GIFR_var rol GIFR_var or GIFR_var, Interrupt out PORTA, GIFR_var ret RESET: ldi r16, RAMEND ; Main program start out SP, r16 ldi Interrupt, 0b00000000 ;set all A port contacts to OUT mode ldi temp, 0b11111111 out DDRA, temp ;pull-up resistor ldi temp, 0b00000010 out PORTB, temp /* ISC01 ISC00 Description 0 0 The low level of INT0 generates an interrupt request. 0 1 Any change on INT0 generates an interrupt request. 1 0 The falling edge of INT0 generates an interrupt request. 1 1 The rising edge of INT0 generates an interrupt request. */ ldi temp, (1<<ISC01) out MCUCR, temp ;allow external interrupt INT0 ldi temp, (1<<INT0) out GIMSK, temp ;allow timer 0 interrupt ldi temp, (1<<TOIE0) out TIMSK, temp sei MAIN_CYCLE: rjmp MAIN_CYCLE
На видео верхний диод зажигается, когда запускается обработчик прерывания и выключается по окончании задержки. Второй диод показывает бит INT0 в GIFR.
Я не буду приводить весь текст программы. Чтобы получить второй вариант (без сброса GIMSK перед разрешением прерываний) нужно просто закомментировать соответствующие строки.
;ldi temp, $FF ;out GIFR, temp
В конце ролика ерунду сказал. Естественно, вызывается не прерывание, а обработчик.
Комментариев нет:
Отправить комментарий