пятница, 15 марта 2013 г.

Прерывания


Использование прерываний

Прерывания обычно используют для задач, которые должны быть выполнены автоматически при наступление какого либо внешнего воздействия. Например, считывание значения энкодера (датчика угла) или реакция на действия пользователя.
Так, если вы хотите считывать значения энкодера без использования прерываний, то написать программу, которая бы не пропускала ни одного импульса, практически невозможно, такая программа должна будет практически все время считывать значения с датчика, чтобы не пропусть импульс. На другие операции просто не останется процессорного времени. Это же относится и к другим датчикам, выдающим короткий импульс. В таких задачах использования внешних прерываний позволяет разгрузить процессор для других операций и не пропустить ожидаемый сигнал. (С) Оф сайт ардуино

Большинство контроллеров Arduino умеют обрабатывать до двух внешних прерываний. Но есть и контроллеры с более развитыми возможностями:
Boardint.0int.1int.2int.3int.4int.5
Uno, Ethernet23
Mega25602321201918
Leonardo3201
Due(see below)
The Arduino Due board has powerful interrupt capabilities that allows you to attach an interrupt function on all available pins. You can directly specify the pin number in attachInterrupt(). 

Для того, чтобы воспользоваться прерыванием, нужно в разделе setup выполнить команду вида
attachInterrupt(0, blink, CHANGE);
0 - 0е прерывание(см. таблицу выше), в моем случае подключаюсь на 3ю DIGITAL ногу
blink - имя процедуры, где будет выполняться код прерывания
CHANGE - режим обработки прерывания.

Допустимо использование следующих констант:
LOW вызывает прерывание, когда на порту LOW
CHANGE прерывание вызывается при смене значения на порту, с LOW на HIGH и наоборот
RISING прерывание вызывается только при смене значения на порту с LOW на HIGH
FALLING прерывание вызывается только при смене значения на порту с HIGH на LOW

Для изучения прерываний придумал простенькую задачку. 
В основном цикле мигаем встроенным светодиодом. При нажатии на кнопку, будем зажигать диод и фиксировать его в этом состоянии. при отпускании кнопки - возвращаемся в ту точку цикла, где остановились и продолжаем мигать диодом

Код:

int btnPin = 3;
int ledPin = 13;
// Ключевое слово volatile было разработано для отключения компиляторной оптимизации,
// которая могла бы привести к неверной работе кода в мультипоточном окружении.
// К примеру: если переменная базового типа объявлена как volatile, то компилятору не разрешается кэшировать ее в регистре -
// распостраненная оптимизация, которая может привести к непредсказуемым результатам,
// если данная переменная используется в нескольких потоках.
volatile boolean signal = false;

void setup()
{
  // INPUT_PULLUP - Притягивает вывод к +5V, чтобы зафиксировать стабильный сигнал на выводе
  // В разомкнутом состоянии кнопки фиксируем 1
  pinMode(btnPin, INPUT_PULLUP);
  // Цепляем прерывание на ногу 3(int.0), в моем случае(плата - Leonardo)
  // Режим прерывания - по фронту на спад (когда 1 переходит в 0),
  // используем этот режим, т.к. при замыкании кнопки вывод притягивается к земле
  attachInterrupt(0, led, FALLING);
}

void loop()
{
    // Мигаем встроенным диодом
    digitalWrite(ledPin, HIGH);
    delay(500);
    digitalWrite(ledPin, LOW);
    delay(500);
}

void led()
{
  // Читаем сигнал с кнопки. Вывод притянут к +5
  // Таким образом в разомкнутом состоянии фиксируем 1, в замкнутом - 0
  // Инвертируем сигнал с 0 в 1 и наоборот
  signal = !digitalRead(btnPin);
  // Пока кнопка нажата, зажигаем диод,
  // отпускаем кнопку - возвращаемся в цикл loop
  while (signal == HIGH)
  {
    digitalWrite(ledPin, signal);
    signal = !digitalRead(btnPin);
  }
}

1 комментарий: