суббота, 16 марта 2013 г.

Обработка прерываний в C

Команды для работы с прерываниями:
  • #include <avr/interrupt.h> - подключение библиотеки работы с прерываниями
  • cli() - запрет прерываний
  • sei() - разрешение прерываний
  • ISR() - функция обработки прерываний (более подробно)
Прежде всего, для работы с прерываниями, в коде программы необходимо подключить библиотеку "interrupt.h" и разрешить как глобальные, так и необходимые нам прерывания. В первом примере будет рассмотрено прерывание по переполнению таймера T0. При поступлении запроса на прерывание от таймера каждый раз будет выполнен сдвиг разрядов порта B влево. В результате чего мы получим бегущую волну, которая будет работать вне зависимости от того, какую программу выполняет микроконтроллер. При этом следует учесть то, что микроконтроллер работает от внутреннего тактового генератора частотой 8 МГц, и ножки предназначенные для подключения кварцевого резонатора, которые также являются двумя старшими разрядами порта B свободны. В связи с этим можно задействовать все 8 разрядов порта B. Если же Вы будете работать от внешнего тактового генератора, то задействовать можно будет лишь 6 младших разрядов порта B.
Рисунок 1 - Схема подключения
Итак, если тактовая частота внутреннего генератора равна 8 МГц, а переполнение таймера наступает каждый 256 такт, то выбираем значение предделителя таймера, равное CLK/1024, получаем прерывание примерно каждые 33 миллисекунды. Этого вполне достаточно чтобы увидеть бегущую волну. Теперь, когда мы определились с задачей и параметрами, можно приступать к написанию программы:

#include <avr/io.h> //подключаем стандартную библиотеку ввода/вывода
#include <avr/interrupt.h> //подключаем библиотеку работы с прерываниями

ISR(TIMER0_OVF_vect) //программа обработки прерывания по переполнению таймера
{
if (PORTB==0x00) // если в порту B все разряды пусты, устанавливаем нулевой разряд в 1
PORTB = 0x01;
else //иначе просто сдвигаем разряд при поступлении очередного прерывания
PORTB = PORTB << 1;
}

int main(void) //основная программа
{
DDRB=0xFF; //конфигурируем порт B как выход
//конфигурирование таймера T0
TCCR0A = 0b00000000; //обычный режим таймера
TCCR0B = 0b00000101; //режим предделителя CLK/1024
TIMSK0 = 0b00000001; //разрешаем прерывания по переполнению
sei(); //разрешаем глобальные прерывания

    while(1); //любой текст программы для микроконтроллера
}

Также разрешить или запретить глобальные прерывания можно редактированием регистра SREG:

SREG |= (0b10000000); //разрешаем глобальные прерывания
SREG &= ~(0b10000000); //запрещаем глобальные прерывания