Как считать RPS для быстрого вращения с помощью метода изменения статуса в Arduino?

Я пытаюсь рассчитать количество оборотов в секунду (RPS) от вращающегося энкодера. Я пытаюсь получить его, проверяя состояние с помощью digitalRead. Однако не могу получить больше 6 RPS. Есть ли решение? Буду благодарен за помощь. Ниже приведен код.

float rps;

void setup() {
  Serial.begin(9600);
  DDRC &= ~_BV (1); // pinMode (A1, INPUT);
}

void loop() {
  static int lastReedState;
  static unsigned long lastTransition;
  int reedState = (PINC & _BV (1)) == 0; // digitalRead (A1);
  // При восходящем переходе геркона:
  if (reedState == LOW && lastReedState == HIGH) {
    // HIGH LOW измеряет период минимума
    // Вычислить время с момента последнего действительного перехода.
    unsigned long now = micros();
    unsigned long revolutionTime = now - lastTransition;
    // измерение периода High
    // Вычислить RPS
    rps = 1.00 / (12.00*revolutionTime) *1000000.00;
    // 12 — разрешение вращающихся энкодеров
    // Запомните этот переход.
    lastTransition = now;
  }
  // Запомнить последнее состояние.
  lastReedState = reedState;
  Serial.println(rps);
}

, 👍3

Обсуждение

Просто спрашиваю, какую Arduino вы используете? Почему не используете прерывания?, @dhimaspw

Я использую Arduino Uno. Фактически, мне приходится считывать 8 входных сигналов. В этом случае прерывания становятся очень сложными., @zalt

Вы пробовали использовать несколько PulseIn()?, @dhimaspw

Использование PulseIn() через некоторое время повлияет на другие процессы. Поэтому я избегаю использования этой функции., @zalt

Ваш код такой медленный из-за Serial.println(rps);. Вам следует как минимум встроить этот оператор в конструкцию типа if (millis() - lastTimePrinted >= PRINT_PERIOD) { ... } и не пытаться печатать быстрее вашей скорости передачи данных (960 байт/с)., @Edgar Bonet

Используйте прерывания и команды sei() и cli() для включения и выключения прерываний. Пока вы занимаетесь важными делами, отключайте прерывания, а когда количество запросов достигнет нужного значения, включайте их снова., @Martynas


2 ответа


0

Для одного канала я бы использовал функцию захвата ввода на Таймере/Счётчике 1. Без дребезга это будет довольно просто.

Если вы хотите одновременно считывать данные с 8 входов, можно использовать прерывания по изменению состояния контактов и Таймер/Счётчик 1 в качестве временной развёртки. Если вы не используете последовательный порт, можно использовать весь PORTD, в противном случае можно использовать, например, 4 канала на PORTC и 4 канала на PORTD. Но, опять же, устранение дребезга будет немного затруднительным.

,

Мне интересно, можно ли использовать более одного прерывания на PORTC или PORTD. Потому что я так и делал, но не смог получить корректный результат при использовании более одного прерывания на каждый порт., @zalt

@zalt Для прерываний по изменению состояния пинов нет, для каждого порта есть свой источник прерывания. Вам нужно выяснить, какие линии были изменены. Однако существует библиотека Arduino [PinChangeInt] (http://playground.arduino.cc/Main/PinChangeInt), в которой можно зарегистрировать функцию обратного вызова для каждого входа., @KIIV

Реализованное с помощью конечного автомата, квадратурное кодирование не требует устранения дребезга. Дребезг может привести к появлению недопустимых или дополнительных состояний, но они взаимно компенсируются., @James Waldby - jwpat7

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

Хорошо. Пока всё сделано. У меня есть ещё один вопрос. Задаю новый., @zalt


1

Рассмотрите возможность использования кода, аналогичного показанному в ответах на следующие вопросы: Чтение с поворотного энкодера KY-040 с помощью Digispark; и Чтение каналов RC-приёмника с использованием прерывания вместо импульсного входа; и Можно ли объединять внешние прерывания по схеме ИЛИ на '328 (Uno)?.

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

Во втором ответе на вопрос описывается обработка нескольких энкодеров с помощью одной процедуры прерывания, использующей пару из двух контактов PCI (pin-change-interrupt) на каждый энкодер. Этот метод предполагает, что контакты пары находятся в одном порту. Большинство контактов ввода-вывода Arduino совместимы с PCI, но некоторые — нет; на некоторых моделях Arduino некоторые контакты PCI не выведены на разъёмы или не распознаются IDE как PCI, как указано в вопросе Почему PJ0 и PJ1 не отображаются как контакты PCINT.

Третий ответ включает код из первых двух, а также скетч, отображающий таблицу векторов и масок PCI. Эта таблица помогает спланировать расположение выводов для снижения накладных расходов на обработку прерывания (ISR). Например, если у вас есть полдюжины энкодеров, вы можете подключить три из них к шести выводам одного порта (и одному вектору), а остальные три — к шести выводам другого порта (и ещё одному вектору). Или вы можете подключить по два энкодера к каждому из трёх портов. Последний метод может работать в среднем немного быстрее (например, около микросекунды на вызов ISR).

,