Можно ли автоматически вызывать функцию при изменении ввода?

В настоящее время мой эскиз проверяет входной вывод каждый раз вокруг основного цикла. Если он обнаруживает изменение, он вызывает пользовательскую функцию для ответа на него. Вот код (обрезанный до необходимого):

int pinValue = LOW;

void pinChanged ()
{
    //...
}

void setup ()
{
    pinMode (2, INPUT);
}

void loop ()
{
    //Чтение текущего входа
    int newValue = digitalRead (2);

    //Изменен ли вход?
    if (newValue! = pinValue) {
        pinValue = newValue;
        pinChanged ();
    }
}

К сожалению, это не всегда корректно работает для очень коротких изменений на входе (например, короткие импульсы), особенно если loop () работает немного медленно.

Есть ли способ заставить Arduino обнаружить изменение ввода и вызвать мою функцию автоматически?

21 голос | спросил Peter Bloomfield 20 FebruaryEurope/MoscowbThu, 20 Feb 2014 04:42:53 +0400000000amThu, 20 Feb 2014 04:42:53 +040014 2014, 04:42:53

3 ответа


27

Вы можете сделать это, используя внешние прерывания. Однако большинство Arduinos поддерживают это только на ограниченном количестве контактов. Подробную информацию см. В документации по attachInterrupt () .

Предполагая, что вы используете Uno, вы можете сделать это следующим образом:

void pinChanged ()
{
    //...
}

void setup ()
{
    pinMode (2, INPUT);
    attachInterrupt (0, pinChanged, CHANGE);
}

void loop ()
{
}

Это вызовет pinChanged () всякий раз, когда обнаружено изменение внешнего прерывания 0. На Uno, которое соответствует выходу GPIO 2. Внешняя нумерация прерываний отличается на других платах, поэтому важно для проверки соответствующей документации.

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

Также важно отметить, что никакие другие прерывания не будут выполняться во время вашего ISR. Это означает, что все, что полагается на прерывания (например, основные функции delay () и millis ()), могут не работать должным образом внутри него.

Наконец, если вашему ISR необходимо изменить любые глобальные переменные в эскизе, их обычно следует объявлять как volatile, например:

volatile int someNumber;

Это важно, потому что он сообщает компилятору, что значение может неожиданно измениться, поэтому следует быть осторожным, чтобы не использовать устаревшие копии /кеши.

ответил Peter Bloomfield 20 FebruaryEurope/MoscowbThu, 20 Feb 2014 04:42:53 +0400000000amThu, 20 Feb 2014 04:42:53 +040014 2014, 04:42:53
5

Любое состояние изменения на любом выводе, сконфигурированном как цифровой вход, может создать прерывание. В отличие от уникальных векторов для причин прерывания по INT1 или INT2, функция PinChangeInt использует общий вектор, а затем Interrupt Service Routine (aka ISR) для этого вектора необходимо затем определить, какой контакт изменился.

К счастью библиотека PinChangeInt делает это легко.

PCintPort :: attachInterrupt (PIN, burpcount, RISING); //присоединяем прерывание PinChange к нашему контакту на переднем фронте
//(RISING, FALLING и CHANGE работают с этой библиотекой)
//и выполняем функцию burpcount при изменении этого вывода
ответил mpflaga 24 FebruaryEurope/MoscowbMon, 24 Feb 2014 18:36:05 +0400000000pmMon, 24 Feb 2014 18:36:05 +040014 2014, 18:36:05
0

Если вы хотите обнаружить напряжение, передающее пороговое значение , а не просто HIGH или LOW, вы можете использовать аналоговый компаратор. Пример эскиза:

 volatile boolean triggered;

ISR (ANALOG_COMP_vect)
  {
  triggered = true;
  }

void setup ()
  {
  Serial.begin (115200);
  Serial.println («Начал»);
  ADCSRB = 0; //(Отключить) ACME: Включить мультиплексор аналогового компаратора
  ACSR = бит (ACI) //(Clear) Аналоговый флаг прерывания компаратора
        | бит (ACIE) //Включено прерывание аналогового компаратора
        | бит (ACIS1); //ACIS1, ACIS0: выбор режима прерывания аналогового компаратора (триггер по фронту падения)
   } //конец настройки

void loop ()
  {
  если (срабатывает)
    {
    Serial.println («Triggered!»);
    triggered = false;
    }

  } //конец цикла

Это может быть полезно для таких вещей, как световые детекторы, где вам может потребоваться обнаружить изменение от (скажем) от 1 В до 2 В на входе.

Пример схемы:

введите описание изображения здесь>> </p>

<p> Вы также можете использовать блок ввода-вывода на процессоре, который будет помнить точное время определенных входов, сохраняя текущий счетчик таймера /счетчика 1. Это позволяет вам сохранить точный (ну, почти точный) момент, который событие интереса произошло, вместо того, чтобы вводить задержку (возможно, несколько микросекунд), прежде чем ISR можно использовать для захвата текущего времени. </p>

<p> Для критически важных приложений времени это может дать несколько повышенную точность. </p>

<p> Пример приложения: <a href= Поверните свой Arduino в тестер конденсатора

ответил Nick Gammon 1 J000000Wednesday15 2015, 05:27:55

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132