Подсчет импульсов с прерыванием

Я пытался подсчитать импульсы прямоугольной волны с частотой 12 500 Гц, чтобы активировать выходной сигнал. Вот код, который у меня есть до сих пор. Когда Arduino сбрасывается, он выводит 315 в последовательный порт за 25 мс. 315 x 40 = 12 600. Мне кажется, все работает отлично.

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

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

volatile int IRQcount;
int pin = 2;
int pin_irq = 0; //IRQ that matches to pin 2

void setup() {
   // Put your setup code here, to run once:
  Serial.begin (9600);
  attachInterrupt(pin_irq, IRQcounter, RISING);
  delay(25);
  detachInterrupt(pin);
  Serial.print(F("Counted = "));
  Serial.println(IRQcount);
}

void IRQcounter() {
  IRQcount++;
}

void loop() {
  // Put your main code here, to run repeatedly:
}

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

Counted = 441
Counted = 442
Counted = 441
Counted = 441
Counted = 441

Теперь я хочу получить тот же результат, но повторяя снова и снова. Таким образом, если сигнал пропадает, я могу отключить выход (НИЗКИЙ). При наличии сигнала на выходе будет высокий уровень.

Я попытался переместить прерывание присоединения в void loop, чтобы оно повторилось. Вот как это выглядит.

volatile int IRQcount;
int pin = 2;
int pin_irq = 0; //IRQ, соответствующий контакту 2

void setup() {
  // Поместите сюда код установки для однократного запуска:
  Serial.begin (9600);
}

void IRQcounter() {
   IRQcount++;
}

void loop() {
  // Поместите сюда ваш основной код для многократного запуска:

  attachInterrupt(pin_irq, IRQcounter, RISING);
  delay(25);
  detachInterrupt(pin);
  Serial.print(F("Counted = "));
  Serial.println(IRQcount);
}

Возврат, который я получаю, обновляется автоматически, но «счетчик» вместо того, чтобы каждый раз начинать с 0, начинается с предыдущего счетчика. Так он становится все больше и больше. Я хочу вернуть постоянное значение, которое представляет мой сигнал 12 500 Гц, чтобы только он и запускал мой вывод.

Counted = 442
Counted = 886
Counted = 1330
Counted = 177
Counted = 2221
Counted = 2667
Counted = 3112
Counted = 3557
Counted = 4002
Counted = 4448
Counted = 4893
Counted = 5338
Counted = 5784
Counted = 6229
Counted = 6674
Counted = 7120
Counted = 7565
Counted = 8010
Counted = 8456
Counted = 8901
Counted = 9347
Counted = 9792
Counted = 10237
Counted = 10683
Counted = 11130
Counted = 11576
Counted = 12022
Counted = 12469
Counted = 12915
Counted = 13361
Counted = 13808
Counted = 14254
Counted = 14700
Counted = 15147
Counted = 15593
Counted = 16040
Counted = 16486
Counted = 16932
Counted = 17378
Counted = 17825
Counted = 18271
Counted = 18717
Counted = 19164
Counted = 19610
Counted = 20056
Counted = 20503
Counted = 20949
Counted = 21395
Counted = 21842
Counted = 22288
Counted = 22735
Counted = 23169
Counted = 23616
Counted = 24062
Counted = 24508
Counted = 24955
Counted = 25401
Counted = 25730
Counted = 25756
Counted = 26200
Counted = 26646
Counted = 27093
Counted = 27539
Counted = 27985
Counted = 28432
Counted = 28878
Counted = 29324
Counted = 29770
Counted = 30217
Counted = 30663
Counted = 31110
Counted = 31556
Counted = 32002
Counted = 32449
Counted = -32641
Counted = -32195
Counted = -31748
Counted = -31302
Counted = -30855
Counted = -30408
Counted = -29962
Counted = -29515
Counted = -29069
Counted = -28622

, 👍10

Обсуждение

«Теперь, если я переведу тот же код в цикл void, он будет последовательно считаться, давая мне непостоянные результаты». значит что именно?, @Ignacio Vazquez-Abrams

Я отредактировал свой вопрос, чтобы попытаться лучше объяснить себя, @Brandon Whosville


1 ответ


Лучший ответ:

9

Вам необходимо сбросить IRQCount обратно в 0 перед повторным присоединением прерывания. В противном случае он просто продолжит отсчет с того места, где остановился в прошлый раз.

На самом деле я бы оставил прерывание подключенным и просто сбросил переменную непосредственно перед задержкой. Таким образом, накладные расходы на прерывание присоединения/отсоединения не добавляются к задержке в 25 мс.

volatile int IRQcount;
int pin = 2;
int pin_irq = 0; //IRQ, соответствующий контакту 2

void setup() {
  // поместите сюда код установки для однократного запуска:
  Serial.begin (9600);
  attachInterrupt(pin_irq, IRQcounter, RISING);
}

void IRQcounter() {
  IRQcount++;
}

void loop() {
  // поместите сюда ваш основной код для многократного запуска:
  IRQcount = 0;
  delay(25);
  int result = IRQcount;
  Serial.print(F("Counted = "));
  Serial.println(result);
}

Поскольку int имеет 2 байта, прерывание может произойти в середине установки/чтения этих двух байтов. Иногда это может привести к неправильному значению. Чтобы предотвратить это, вы должны отключить прерывание при установке/чтении значения

volatile int IRQcount;
int pin = 2;
int pin_irq = 0; //IRQ, соответствующий контакту 2

void setup() {
  // поместите сюда код установки для однократного запуска:
  Serial.begin (9600);
  attachInterrupt(pin_irq, IRQcounter, RISING);
}

void IRQcounter() {
  IRQcount++;
}

void loop() {
  // поместите сюда ваш основной код для многократного запуска:

  cli();//отключаем прерывания
  IRQcount = 0;
  sei();//включаем прерывания

  delay(25);

  cli();//отключаем прерывания
  int result = IRQcount;
  sei();//включаем прерывания

  Serial.print(F("Counted = "));
  Serial.println(result);
}
,

Спасибо Гербен! Используя этот код, я получаю случайный возврат нежелательной почты. Как проще всего это осудить? Сделайте вывод, скажем, 3 чтения, прежде чем принимать решение о том, что делать. Или усреднение импульсов по промежутку вместо необработанного счета? Вот пример возврата, я получаю аномалию каждые несколько секунд. Подсчитано = 439, Подсчитано = 438, Подсчитано = 430, Подсчитано = 48, Подсчитано = 318, Подсчитано = 438,, @Brandon Whosville

Я увеличил задержку, чтобы получить больший размер выборки. Это дает мне реальную отдачу от моего шумного источника ввода. Кажется, это работает идеально! Спасибо!, @Brandon Whosville

Я предполагаю, что вы использовали код с кли и сэй в нем. Довольно странно иметь два последовательных неправильных значения., @Gerben

Gerben, Да, я использовал код с cli и sei. Вы имеете в виду, что странно получать два неправильных результата подряд? Кажется, что возврат правильный, это входящий сигнал, который не является стабильным, дает нежелательные результаты. Если я сэмплирую более, скажем, 100 мс, это дает много импульсов на сэмпл, чтобы безопасно активировать или отключить схему. Я действительно ценю твою помощь!, @Brandon Whosville

Но 48 и 318, которые вы получили, оба ниже, чем в среднем около 435. Я не знаю подключенной схемы, так что это может быть просто схема, а не код Arduino. В любом случае, если вы довольны конечным результатом... Рад, что помог., @Gerben

Я считаю, что проблема связана с программным обеспечением, связанным с самим хост-компьютером. Я пробовал несколько схем подкачки заряда и остановился на Arduino из-за неустойчивого сигнала. Я провел много экспериментов, используя различные формы кода на Arduino, а также другие типы аппаратных подходов к этому. Проблема в нестабильности входящего сигнала, а не в его интерпретации ардуино. Каждая часть оборудования, которое я использовал для мониторинга сигнала, показала большие различия в нем. Arduino {с вашей помощью} позволил мне избавиться от дребезга схемы подкачки заряда, которая доводила меня до нервного срыва!, @Brandon Whosville