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

10

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

Моя единственная проблема - он возвращает этот номер только один раз после сброса платы. Теперь, если я перенесу тот же самый код в код 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 that matches to pin 2

void setup() {
  // Put your setup code here, to run once:
  Serial.begin (9600);
}

void IRQcounter() {
   IRQcount++;
}

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

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

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

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
Брэндон Уосвилл
источник
«Теперь, если я перенесу тот же самый код в цикл void, он будет рассчитывать последовательно, давая мне непостоянные результаты». значит что именно?
Игнасио Васкес-Абрамс
Я отредактировал свой вопрос, чтобы попытаться лучше объяснить себя
Брэндон Whosville

Ответы:

9

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

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

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);
}

void IRQcounter() {
  IRQcount++;
}

void loop() {
  // put your main code here, to run repeatedly:
  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 that matches to pin 2

void setup() {
  // put your setup code here, to run once:
  Serial.begin (9600);
  attachInterrupt(pin_irq, IRQcounter, RISING);
}

void IRQcounter() {
  IRQcount++;
}

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

  cli();//disable interrupts
  IRQcount = 0;
  sei();//enable interrupts

  delay(25);

  cli();//disable interrupts
  int result = IRQcount;
  sei();//enable interrupts

  Serial.print(F("Counted = "));
  Serial.println(result);
}
Gerben
источник
Спасибо Гербен! Используя этот код, я получаю случайный возврат мусора. Что было бы самым простым способом осудить это? Давайте сделаем, скажем, 3 чтения, прежде чем принимать решение о том, что делать. Или усреднение импульсов по промежутку вместо необработанного счета? Вот пример возвращения, я получаю аномалию каждые несколько секунд. Считается = 439, Считается = 438, Считается = 430, Считается = 48, Считается = 318, Считается = 438,
Брэндон Эвсвилл
1
Я увеличил задержку, чтобы увеличить размер выборки. Это дает мне реальную отдачу от моего шумного источника ввода. Кажется, это работает идеально! Спасибо!
Брэндон Эвсвилл,
Я предполагаю, что вы использовали код с clis и seis в нем. Довольно странно иметь два последовательных неправильных значения.
Гербен
1
Gerben, да, я использовал код с cli и sei в нем. Вы имеете в виду, что странно получать два неправильных возврата подряд? Кажется, что возвраты верны, это входящий сигнал, который нестабилен, давая нежелательные возвраты. Если я сэмплирую, скажем, 100 мс, это дает много импульсов на сэмпл, чтобы безопасно активировать или убить цепь. Я очень ценю вашу помощь!
Брэндон Эвсвилл
Но 48 и 318, которые вы получили, оба ниже, чем в среднем около 435. Я не знаю подключенную схему, так что это может быть схема, а не код arduino. В любом случае, пока вы довольны конечным результатом ... Рад, что помог.
Гербен