Прерывание является спорадическим, возможно, после 220 Гц или около того

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

Я считаю, что он работает нормально, пока сигнал не достигнет примерно 420 Гц (что ничего не значит ..). pulseIn также возвращает много длительностей "0" с хорошей длительностью "900ns". Таким образом, похоже, что триггер high / low срабатывает слишком часто, что не было исправлено с помощью debounce. С помощью осциллографа я вижу, что сигнал хороший на частоте 550 Гц

21:34:12.750 -> Htz: 0
21:34:14.575 -> L: 44
21:34:14.575 -> Htz: 88
21:34:15.265 -> L: 70
21:34:15.265 -> Htz: 140
21:34:15.479 -> L: 89
21:34:15.479 -> Htz: 178
21:34:15.913 -> L: 109
21:34:15.913 -> Htz: 218
21:34:16.452 -> L: 117
21:34:16.577 -> Htz: 234
21:34:16.986 -> L: 134
21:34:16.986 -> Htz: 268
21:34:17.511 -> L: 186
21:34:17.511 -> Htz: 372
21:34:18.036 -> L: 213
21:34:18.036 -> Htz: 426
21:34:18.567 -> L: 702
21:34:18.567 -> Htz: 1404
21:34:19.195 -> L: 1913
21:34:19.196 -> Htz: 3826
21:34:19.838 -> L: 3508
21:34:19.838 -> Htz: 7016

код

unsigned long timestamp;
int lsensorpin = 2;
int PWMpin = 3;
String printout;
unsigned int reading;
unsigned long L;
unsigned int lRPM;
unsigned int Htz;

void setup() {
  pinMode(lsensorpin, INPUT);//_PULLUP); //2
  pinMode(PWMpin, OUTPUT);
  analogWrite(PWMpin, 100);
  Serial.begin(9600);
  Serial.println("FInish Setup");
}

void loop() {

  //printout=" High:";
  //reading= pulseIn(lsensorpin, HIGH);
  //printout=printout + reading + " Low:";
  //reading= pulseIn(lsensorpin, LOW);
  //printout= printout + reading;
  //Serial.println(printout + reading);
  
  L=0;
  attachl();
  delay(500);
  detachl();
  Htz=L*2;
  lRPM= L*60;
  Serial.print("L: ");
  Serial.println(L);
  //Serial.print("Htz: ");
  //Serial.println(Htz);
  
  //Serial.print("RPM: ");
  //Serial.println(lRPM);
}

void tickL() {
L=L+1;
}

void attachl(){
    attachInterrupt(digitalPinToInterrupt(lsensorpin), tickL, RISING);
}

void detachl(){
    detachInterrupt(digitalPinToInterrupt(lsensorpin));
}

Debounced Signal

, 👍-1

Обсуждение

Считаете ли вы, что на delay () влияют прерывания? Каждая служба прерывания занимает некоторое время выполнения, и задержка увеличивается на это время выполнения. Функция реализует задержку через определенное количество циклов команд. Возможно, вы захотите использовать таймер для определения интервала измерения., @the busybee

Почему вы подключаете и отключаете прерывание в своем основном цикле? Попробуйте использовать более высокую скорость передачи данных, например, 115200 бод. (9600 - это очень медленно)., @Nick Gammon


1 ответ


1

Из моего поста о прерываниях:


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

Пример (не рекомендуется):

volatile unsigned long events;
const unsigned long INTERVAL = 1000;  // 1 секунда

void eventISR ()     
  { 
  events++;  
  }   // конец eventISR

void setup () 
  { 
  Serial.begin(115200); 
  attachInterrupt (digitalPinToInterrupt (2), eventISR, FALLING); 
  }   // завершение настройки

void loop ()    
  {
  events = 0;       // сброс счетчика
  interrupts ();    // разрешить
  delay (INTERVAL); // ожидание требуемого времени
  noInterrupts();   // останавливать прерывания

  Serial.print ("I counted ");
  Serial.println (events);
  }  // конец цикла

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

Лучше использовать результат millis() и просто определить, когда истечет отведенное время.

Улучшенный скетч:

volatile bool counting;
volatile unsigned long events;

unsigned long startTime;
const unsigned long INTERVAL = 1000;  // 1 секунда

void eventISR ()
  {
  if (counting)
    events++;    
  }  // конец eventISR
  
void setup ()
  {
  Serial.begin (115200);
  Serial.println ();
  attachInterrupt (digitalPinToInterrupt (2), eventISR, FALLING);
  }  // завершение настройки

void showResults ()
  {
  Serial.print ("I counted ");
  Serial.println (events);
  }  // окончание показа результатов
  
void loop ()
  {
  if (counting)
    {
    // время вышло?
    if (millis () - startTime < INTERVAL)
      return;  
    counting = false;
    showResults ();
    }  // конец if
    
  noInterrupts ();
  events = 0;
  startTime = millis ();
  EIFR = bit (INTF0);  // снять флаг для прерывания 0
  counting = true;
  interrupts ();
  }  // конец цикла

В loop() здесь мы ждем истечения интервала (в данном случае 1 секунды), в противном случае мы возвращаемся, фактически ничего не делая. Конечно, вы могли бы заняться другими делами вместо того, чтобы просто возвращаться.

Если время истекло, мы показываем счетчик.

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

Этот код, казалось, нормально работал до 100 кГц, хотя подсчеты становились немного неточными. Вы можете установить более точные тайминги, используя аппаратные счетчики / таймеры. Подробности здесь:

http://www.gammon.com.au/timers


Также вы должны объявить переменную L изменчивой.

,

Интересное форматирование, выглядит как-то в стиле python.. Я тоже не могу нормально видеть блоки: D (субъективное ощущение), @KIIV

@KIIV Почему? Весь блок имеет отступ. Я считаю, что это легче всего читать. Кажется, это называется [стиль кузнецов] (https://en.wikipedia.org/wiki/Indentation_style#стиль кузнецов). «Этот стиль также был популярен на заре Windows…» — я уже давно здесь, поэтому, вероятно, я усвоил этот стиль несколько лет назад., @Nick Gammon

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