Как считать 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);
}
@zalt, 👍3
Обсуждение2 ответа
Для одного канала я бы использовал функцию захвата ввода на Таймере/Счётчике 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
Рассмотрите возможность использования кода, аналогичного показанному в ответах на следующие вопросы: Чтение с поворотного энкодера KY-040 с помощью Digispark; и Чтение каналов RC-приёмника с использованием прерывания вместо импульсного входа; и Можно ли объединять внешние прерывания по схеме ИЛИ на '328 (Uno)?.
В первом ответе показан быстродействующий конечный автомат для обработки квадратурно-кодированных сигналов, т.е. входных сигналов вращающегося энкодера.
Во втором ответе на вопрос описывается обработка нескольких энкодеров с помощью одной процедуры прерывания, использующей пару из двух контактов PCI (pin-change-interrupt) на каждый энкодер. Этот метод предполагает, что контакты пары находятся в одном порту. Большинство контактов ввода-вывода Arduino совместимы с PCI, но некоторые — нет; на некоторых моделях Arduino некоторые контакты PCI не выведены на разъёмы или не распознаются IDE как PCI, как указано в вопросе Почему PJ0 и PJ1 не отображаются как контакты PCINT.
Третий ответ включает код из первых двух, а также скетч, отображающий таблицу векторов и масок PCI. Эта таблица помогает спланировать расположение выводов для снижения накладных расходов на обработку прерывания (ISR). Например, если у вас есть полдюжины энкодеров, вы можете подключить три из них к шести выводам одного порта (и одному вектору), а остальные три — к шести выводам другого порта (и ещё одному вектору). Или вы можете подключить по два энкодера к каждому из трёх портов. Последний метод может работать в среднем немного быстрее (например, около микросекунды на вызов ISR).
- Как использовать SPI на Arduino?
- Как решить проблему «avrdude: stk500_recv(): programmer is not responding»?
- Как создать несколько запущенных потоков?
- avrdude ser_open() can't set com-state
- Как подключиться к Arduino с помощью WiFi?
- Mac OSX Yosemite не отображает последовательные порты для Uno R3
- Как узнать частоту дискретизации?
- Что такое Serial.begin(9600)?
Просто спрашиваю, какую Arduino вы используете? Почему не используете прерывания?, @dhimaspw
Я использую Arduino Uno. Фактически, мне приходится считывать 8 входных сигналов. В этом случае прерывания становятся очень сложными., @zalt
Вы пробовали использовать несколько PulseIn()?, @dhimaspw
Использование PulseIn() через некоторое время повлияет на другие процессы. Поэтому я избегаю использования этой функции., @zalt
Ваш код такой медленный из-за
Serial.println(rps);. Вам следует как минимум встроить этот оператор в конструкцию типаif (millis() - lastTimePrinted >= PRINT_PERIOD) { ... }и не пытаться печатать быстрее вашей скорости передачи данных (960 байт/с)., @Edgar BonetИспользуйте прерывания и команды sei() и cli() для включения и выключения прерываний. Пока вы занимаетесь важными делами, отключайте прерывания, а когда количество запросов достигнет нужного значения, включайте их снова., @Martynas