AVR:Прерывания
Что такое прерывания и с чем его едят?
Прерывание это событие при котором процессор приостанавливает выполнение основной программы и переходит на подпрограмму обработки прерывания.
Что такое подпрограмма обработки прерывания?
Это подпрограмма которая выполняется при возникновении прерывания.
При каких событиях происходят прерывания?
События при которых происходят прерывания указаны таблице векторов прерываний в даташите.
Вот пример таблицы для мега16
# | Адресс | Разрешение прерывания | Запрос рерывания | Событие |
---|---|---|---|---|
1 | $0002 | INT0 (GICR) | INTF0 (GIFR) | INT0 Внешнее прерывание 0 |
2 | $0004 | INT1 (GICR) | INTF1 (GIFR) | INT1 Внешнее прерывание 1 |
3 | $0006 | OCIE2 (TIMSK) | OCF2 (TIFR) | TIMER2 COMPARE Совпадение таймера счетчика 2 |
4 | $0008 | TOIE2 (TIMSK) | TOV2 (TIFR) | TIMER2 OVERFLOW Переполнение таймера счетчика 2 |
5 | $000A | TICIE1 (TIMSK) | ICF1 (TIFR) | TIMER1 CAPTURE Захват таймера счетчика 1 |
6 | $000C | OCIE1A (TIMSK) | OCF1A (TIFR) | TIMER1 COMPARE A Совпадение А таймера счетчика 1 |
7 | $000E | OCIE1B (TIMSK) | OCF1B (TIFR) | TIMER1 COMPARE B Совпадение В таймера счетчика 1 |
8 | $0010 | TOIE1 (TIMSK) | TOV1 (TIFR) | TIMER1 OVERFLOW Переполнение таймера счетчика 1 |
9 | $0012 | TOIE0 (TIMSK) | TOV0 (TIFR) | TIMER0 OVERFLOW Переполнение таймера счетчика 0 |
10 | $0014 | SPIE (SPCR) | SPIF (SPSR) | SPI STC Передача по SPI завершена |
11 | $0016 | RXCIE (UCSRB) | RXC (UCSRA) | USART RXC Прием по USART завершен |
12 | $0018 | UDRIE (UCSRB) | UDRE (UCSRA) | USART UDRE Готовность регистр данных USART |
13 | $001A | TXCIE (UCSRB) | TXC (UCSRA) | USART TXC Передача по USART завершеа |
14 | $001C | ADIE (ADCSRA) | ADIF (ADCCSRA) | ADC Преобразование ADC завершено |
15 | $001E | EERIE (EECR) | EE RDY Готовность EEPROM | |
16 | $0020 | ACIE (ACSR) | ACI (ACSR) | ANA COMP прерывание от аналогового компаратора |
17 | $0022 | TWIE (TWCR) | TWINT (TWCR) | TWI Прерывания от TWI |
18 | $0024 | INT2 (GICR) | INTF2 (GIFR) | INT2 Внешнее прерывание 2 |
19 | $0026 | OCIE0 (TIMSK) | OCF0 (TIFR) | TIMER0 COMPARE 0 Совпадение -
таймера счетчика 0 |
20 | $0028 | SPMIE(SPMCR) | SPM RDY Готовность SPM |
Для чего нужна эта таблица?
В этой таблице находятся адресса векторов прерываний (команды перехода с адрессом начала подпрограммы прерывания). Каждый вектор находится по определенному адрессу таблицы. Фактически при возникновении прерывания процессор переходит на адресс таблицы векторов соответствующий этому прерыванию. Так как по этому адрессу находится команда перехода на подпрограмму, процессор может определить какую именно подпрограмму ему выполнять при возникновении прерывания. Так же в этой таблице указаны флаги разрешения прерывания и флаги запроса прерывания. В скобках указаны регистры в которых они находятся.
Для чего нужны эти флаги?
При установке флага разрешения мы разрешаем необходимое нам прерывание, флаги запроса прерывания устанавливаются аппаратно при наступлении прерывания и сбрасываются при переходе на подпрограмму обработки прерывания,эти флаги также можно сбросить программно. Следует не забывать, что при разрешении прерывания необходимо устанавливать флаг I регистра SREG для глобального разрешения прерываний.
Можно простой примерчик или как то на пальцах обьяснить?
Можно, вот простой примерчик подсчета количества прерываний INT0 и выводом результата в порт В.
<source lang="asm">
- Подсчет количества прерываний INT0
- Результат выводится в порт В
- Подключение файла обьявления имен регистров ATmega8
.include "c:\...\m16def.inc"
.cseg .org 0
- ------------------ Вектора прерываний ---------------------------
jmp PROG ;Вектор перехода на начало программы jmp SUBI_INT0 ;Вектор перехода на подпрограмму прерывания INT0
- -----------------------------------------------------------------
.org $30
- Начало программы
PROG: ;PROG
ldi R16,high(RAMEND) ;Инициализация стека out SPH,R16 ldi R16,low(RAMEND) out SPL,R16
- Инициализация INT0
;INT.SenseControl=FallingEdge ldi R16,(0<<ISC00)|(1<<ISC01) ;Условие прерывания - спадающий фронт сигнала out MCUCR,R16 ldi R16,(1<<INT0) ;INT.Enable=1 Разрешаем прерывание INT0 out GICR,R16
- Обнуление регистра R20 и установка порта В на вывод
ldi R20,$00 ;R20=$00 ldi R16,$FF ;DDRB=$FF out DDRB,R16 sei ;Разрешаем прерывания глобально I=1
- Конец программы (бесконечный цикл)
END_PROG: ;END PROG
rjmp END_PROG
- -----------------------------------------------------------------
- Начало подпрограммы обработки прерывания от INT1
;SUBI INT0
SUBI_INT0: ;Сохраняем регистры R16,SREG в стеке
push R16 in R16,SREG push R16 inc R20 ;R20+$01 out PORTB,R20 ;PORTB=R20
pop R16 ;Востанавливаем регистры out SREG,R16 pop R16 reti ;END SUBI
- -----------------------------------------------------------------
</source>
А теперь на пальцах смотрим на симуляторе что происходит. Нажимаем пошаговое выполнение пока строка выполнения не будет крутиться в бесконечном цикле по команде rjmp END_PROG.
После чего подаем лог. 0 на вывод INT0 нажав переключатель.
Потом нажимаем опять пошаговое выполнение и ВИДИМ, ПРОИСХОДИТ ЧУДО. Стока выполнения перещается на адресс $0002($0004) (в таблице адресс вектора указывается в словах, а в симуляторе адрессация в байтах) в котором находиться команда перехода rjmp INT0 на начало подпрограммы INT0. После чего происходит выполнение подпрограммы INT0.
Хорошо,а что произойдет если мы разрешим допустим два прерывания, и события при которых они наступят произойдут в один и тот же момент времени?
Для этого и нужна таблица векторов прерываний, чем меньше адресс вектора тем выше приоритет этого прерывания по отношению к другим. Допустим одновременно наступили два прерывания INT0 и INT1, тогда сначала будет выполненена подпрограмма обработки INT0, а после подпрограмма обработки INT1.
А если во время выполнения подпрограммы обработки прерывания, наступит другое, более высокое по приоритету, что тогда?'
При наступлении любого прерывания флаг глобального разрешения прерываний I регистра SREG сбрасывается в 0 и до его установки любые другие прерывания не выполняются. Соответственно при выполнении подпрограммы другое прерывание не будет выполено до установки бита I в 1 или команды reti (выход из подпрограммы с установкой бита I в 1).
Значит, если во время выполнения подпрограммы обработки прерывания, наступит другое, оно не будет выполнено?
Нет, все разрешенные прерывания будут выполнены (кроме тех, у которорых не предусмотрен флаг запроса прерывания), но уже не сразу после наступления события, а в порядке их преоритетности. Для этого и служат флаги запроса прерываний (смотрите таблицу) При наступлении прерывания устанавливается флаг, который сигнализирует процессору о наступлении события и не сбрасывается, до тех пор пока процесссор не перейдет на подпрограмму обработки этого прерывания.
А если прерываний будет много и процессор не будет успевать их обрабатывать. Например дважды возникнет одно и тоже прерывание до того как он успевает обработать предыдущее?
Если одно и тоже прерывание наступает раньше, чем успевает обрабатываться в подпрограмме, в таких случаях нужно стараться писать подпрограммы обработки прерываний как можно коротче и с наибольшей скоростью их выполнения.
А для чего значения рабочих регистров и регистра SREG заносятся в стек в начале подпрограммы прерывания и извлекаются из стека в конце?
Так как мы не знаем в какой момент времени может наступить прерывание, подпрограмма прерывания может изменить значения регистров если она использует теже регистры что и основная программа. Тоже касается и значения регистра SREG так как в нем хранятся значения флагов сравнения и арифметических операций, а условие выполняется процессором за две команды. То есть выполнение условия после первой команды может быть прервано прерыванием и изменено значение регистра SREG подпрограммой прерывания, соответственно после возврата из прерывания условие при выполнении второй команды в основной программе может быть выполнено неверно.
См. также
Автор: bodja
E-Mail: bodja74@mail.ru
WWW: http://telepribor.narod.ru/
Профиль на электрониксе: bodja74