Настраиваем внешние прерывания микроконтроллера ATmega8
Выводы INT0 и INT1
Регистр GICR
Для разрешения внешних прерываний используется регистр GICR.
Регистр MCUCR
Регистр MCUCR задаёт условие, при котором будет вызвано внешнее прерывание.
Биты ISC00 и ISC01 используются для настройки INT0. Биты ISC10 и ISC11 используются для настройки INT1.
Настройка INT0
| ISC01 | ISC00 | Условие срабатывания INT0 |
|---|---|---|
| 0 | 0 | Низкий логический уровень на входе INT0 |
| 0 | 1 | Любое изменение логического уровня |
| 1 | 0 | Ниспадающий фронт |
| 1 | 1 | Возрастающий фронт |
Для входа INT1 принцип настройки аналогичный, только используются биты ISC11 и ISC10.
Глобальное разрешение прерываний
Кроме разрешения конкретного INT0 или INT1, необходимо глобально разрешить работу прерываний.
Для этого можно использовать функцию:
sei();
Или установить соответствующий бит регистра SREG:
SREG |= (1 << 7);
Проверяем работу прерываний
Для проверки подключим два светодиода к выводам PD0 и PD1. Две кнопки подключим к PD2 и PD3, то есть к входам INT0 и INT1.
Дополнительно к выводу PD4 подключим третий светодиод. Он будет мигать каждые 500 мс, показывая, что основной цикл программы продолжает выполняться независимо от обработки внешних прерываний.
Программный код
#define F_CPU 4000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
void init_interrupt(void);
void int_pcb(void);
/* Светодиод HL1 — PD0 */
#define HL1_on PORTD |= (1 << PD0)
#define HL1_off PORTD &= ~(1 << PD0)
/* Светодиод HL2 — PD1 */
#define HL2_on PORTD |= (1 << PD1)
#define HL2_off PORTD &= ~(1 << PD1)
/* Светодиод HL3 — PD4 */
#define HL3_on PORTD |= (1 << PD4)
#define HL3_off PORTD &= ~(1 << PD4)
/* Прерывание INT0 — вывод PD2 */
ISR(INT0_vect)
{
HL1_on;
HL2_off;
}
/* Прерывание INT1 — вывод PD3 */
ISR(INT1_vect)
{
HL2_on;
HL1_off;
}
int main(void)
{
init_interrupt();
int_pcb();
while (1)
{
HL3_on;
_delay_ms(500);
HL3_off;
_delay_ms(500);
}
}
void init_interrupt(void)
{
/*
Разрешаем INT0 и INT1
*/
GICR |= (1 << INT0) |
(1 << INT1);
/*
INT0 и INT1 срабатывают
при любом изменении логического уровня
*/
MCUCR |= (1 << ISC00) |
(1 << ISC10);
/*
Глобально разрешаем прерывания
*/
sei();
}
void int_pcb(void)
{
/*
PD2 и PD3 — входы.
Включаем внутренние подтягивающие резисторы.
*/
PORTD = 0b00001100;
/*
PD0, PD1 и PD4 — выходы
*/
DDRD = 0b00010011;
}