Как долго должен длиться цифровой импульс, чтобы его можно было прочитать?

serial loop digital-in

У меня есть следующий действительно простой код. На каждой итерации он будет считывать первый вывод, и если он высокий - выполняйте последовательный ввод. Затем проделайте то же самое со вторым штифтом. Красиво и просто, работает во время моих тестов.

Меня беспокоит то, что (в производстве) цифровой импульс, который я получаю (и пытаюсь воспроизвести во время тестирования), будет слишком быстрым для чтения arduino. Так, например, условие гонки может быть следующим:

  1. Первый вывод низкий, Считайте первый вывод - результат низкий.
  2. Первый вывод теперь высокий, Считайте второй вывод - результат низкий.
  3. Первый штифт теперь снова низкий, Прочитайте первый штифт - результат снова низкий (пропустил "высокий")

Насколько это "крайний случай"? Беспокоюсь ли я о чем-то, что здесь, скорее всего, не будет проблемой? В производстве каждый отдельный импульс будет представлять значительное количество продукта (я умножаю его в другом месте), поэтому даже пропуск одного может сбить мои данные.

boolean count1High = false;
boolean count2High = false;
int count1 = 7;
int count2 = 8;
int a = 1;
void setup() {
  pinMode(count1, INPUT);
  pinMode(count2, INPUT);
  Serial.begin(9600);
}

void loop()
{
  if (digitalRead(count1) == HIGH)
  {
    if (!count1High)
    {
      count1High = true;
      a++;
      Serial.println(a); 
    }
  }
  else 
  {
    count1High = false;
  }

  if (digitalRead(count2) == HIGH)
  {
    if (!count2High)
    {
      count2High = true;
      a++;
      Serial.println(a); 
    }
  }
  else 
  {
    count2High = false;
  }
}

ИЗМЕНИТЬ:

Я знаю, что лучшим подходом здесь может быть подключение прерывания, но мне посоветовали избегать последовательного ввода-вывода из прерываний, я не вижу здесь альтернативы.

, 👍1


3 ответа


1

Именно по этой причине были изобретены прерывания. Они могут реагировать намного быстрее, чем простое цифровое считывание. Под "большим количеством" я подразумеваю порядки величины.

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

Таким образом, вы не пропустите этот импульс, пока обрабатывается другой импульс.

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

,

0

Это зависит от того, откуда поступает сигнал, и от другого кода в вашем скетче.

Как правило, скетч слишком быстр для механического переключателя, и вам приходится его отменять.

Если ваш страх потерять события реалистичен, прерывания-это правильный путь. Но ISR-это какой-то совершенно особый код: вы не сделаете ничего, кроме сбора информации о том, что произошло событие. И вы должны утверждать, что ваш основной скетч не будет мешать ISR.

,

1

Как объясняется в ответе Майенко, вы должны обнаруживать импульсы от прерывания и выводить результат из обычного кода. Однако вместо того, чтобы просто устанавливать флаг в обработчике прерываний, я предлагаю вам вместо этого подсчитайте импульсы внутри обработчика. Это сделает обработчик немного медленнее, чего часто хочется избежать. Однако дополнительные накладные расходы действительно невелики, и вы получаете возможность считать не только короткие импульсы, но и импульсы, расположенные на близком расстоянии друг от друга.

Однако есть кое-что, о чем следует помнить при совместном использовании переменной между кодом прерывания и обычным кодом. Если переменная не может быть прочитана в одной инструкции процессора (что имеет место в случае int на Плата на основе AVR), существует некоторый риск того, что значение изменится в середине вашего чтения. Чтобы устранить эту проблему, вам необходимо отключить прерывания при чтении переменной из обычного кода.

Вот реализация этой стратегии, подчеркивающая этот момент:

const uint8_t intPin1 = 2;
const uint8_t intPin2 = 3;

// This is volatile because it is shared between interrupt context
// and regular code.
volatile unsigned int sharedCount = 0;

// Interrupt handler.
void countPulse() { sharedCount++; }

// A variable shared with interrupt context should be accessed from
// regular code with interrupts disabled, in order to avoid race
// conditions.
unsigned int getCount() {
    noInterrupts();
    unsigned int countCopy = sharedCount;
    interrupts();
    return countCopy;
}

void setup() {
    pinMode(intPin1, INPUT);
    pinMode(intPin2, INPUT);
    attachInterrupt(digitalPinToInterrupt(intPin1), countPulse, RISING);
    attachInterrupt(digitalPinToInterrupt(intPin2), countPulse, RISING);
    Serial.begin(9600);
}

void loop() {
    static unsigned int previousCount = 0;
    unsigned int count = getCount();
    if (count != previousCount) {
        Serial.println(count);
        previousCount = count;
    }
}

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

,