Вопрос по Arduino ISR timing
Я пытаюсь понять, как Arduino ISR отслеживает синхронизацию между импульсами, хранящимися в переменной, если эта переменная используется последней.
Скажем, например, у вас есть магнит, установленный на круглом предмете, который проходит через геркон. Используя это для запуска ISR, который вызывает функцию, содержащую что-то вроде counts++, а затем сохраняет это значение в переменной.
Если эта переменная используется последним для включения двигателя, например, в соответствии с захватом счета, то как микроконтроллер arduino узнает частоту или время вывода счета или импульсов магнита, проходящего через герконовый переключатель, на той же частоте, на которой были получены счета? Например, магнит, установленный на валу диаметром 2 дюйма, будет вращаться медленнее мимо герконового выключателя, чем магнит, установленный на валу диаметром 5 дюймов, или можно будет изменять скорость магнита мимо герконового выключателя по своему усмотрению. Так как же counter++ отслеживает эту частоту? считывает ли он вывод attachinterupt (или вызываемая функция отслеживает), или ISR помечает каждый полученный импульс и сохраняет этот интервал в объявленной переменной? значит, когда переменная используется снова, в ней хранится этот интервал?
Чтобы быть более ясным, если магнит совершает один оборот за одну секунду, то как микроконтроллер узнает, что ему потребовалась одна секунда, и запоминает ее вместе с отсчетом оборотов?
Спасибо за любую помощь
@Jim, 👍0
Обсуждение1 ответ
Все, что делает прерывание, - это считается. У него нет понятия времени. Например:
volatile uint32_t revolutions = 0;
void count() {
revolutions++;
}
....
attachInterrupt(0, count, FALLING);
будет просто считать до 1 каждый раз, когда срабатывает прерывание.
Чтобы преобразовать это количество во что - то значимое, вам нужно вручную ввести понятие времени, то есть количество "оборотов" (например) между двумя точками времени. И это зависит от вашего скетча, чтобы реализовать это.
Самым простым способом может быть:
// Для чего-либо большего, чем 8-битное значение на 8-битной машине
// сделайте критический раздел для сохранения и сброса cli подсчета
cli();
uint32_t savedResolutions = revolutions;
revolutions = 0;
sei();
Serial.print(savedRevolutions);
Serial.println(F(" revolutions per second"));
// Введем понятие времени - это позволит
// заставить его считать один раз в секунду.
delay(1000);
Конечно, вместо функции delay()
вы можете использовать функцию millis()
почти так же, как в
примере BlinkWithoutDelay в среде IDE.
Можно (если вы не считаете слишком быстро) включить элемент времени в процедуру прерывания, отслеживая время в переменной:
volatile uint32_t rps = 0;
void count() {
static uint32_t revolutions = 0;
static uint32_t timestamp = millis();
revolutions++;
if (millis() - timestamp >= 1000) {
timestamp = millis();
rps = revolutions;
revolutions = 0;
}
}
....
attachInterrupt(0, count, FALLING);
Тогда вы можете просто ссылаться на переменную rps в любое время, чтобы получить обороты в секунду. Опять же, его действительно следует запросить в критическом разделе, чтобы предотвратить изменение значения во время активного чтения...
cli();
uint32_t myRPS = rps;
sei();
Serial.print(myRPS);
Serial.println(F(" revolutions per second"));
Я видел, как люди использовали переменную++ или +1 в функции, вызываемой ISR, без каких-либо миллисекунд или привязки ко времени, затем использовали эту переменную против другой переменной, чтобы зафиксировать пиковое значение, используйте это, чтобы включить что-то на этот период, например., @Jim
Конечно, если это то, что они делают, требует, чтобы они это делали..., @Majenko
"например, они вводят понятие времени на более позднем этапе" не могли бы вы объяснить, что вы подразумеваете под этим, возможно, на примере? Я не совсем понимаю это, @Jim
Вы имеете в виду помимо того, что я уже показываю в своем ответе?, @Majenko
да, это помогло бы, @Jim
Я не уверен, что мог бы что-то добавить, сделав то, что я уже сделал. Я показал вам самый простой и простой из возможных примеров. Чего еще ты хочешь?, @Majenko
например, если бы он использовал прерывание, чтобы фиксировать прерывание Рида один раз в секунду в переменной rev++, и использовать его позже, как вы предложили, @Jim
Объедините первый блок кода со вторым блоком кода (который вы заключаете в комбинацию setup() и loop() с правильными контактами, последовательной конфигурацией и т. Д.), И у вас будет свой пример., @Majenko
что ж, это все проясняет, чувак, спасибо. Я представляю себе эти блоки кода со всем, что я должен в них вставить прямо сейчас. похоже, вы предлагали, чтобы люди использовали счетчик, не привязанный к какой-либо миле или задержке, поэтому я попросил пример, @Jim
Я знаю, как использовать блоки кода и объявить initialize в настройке и поместить attachinterupt туда, вне цикла , чтобы он работал независимо от цикла. Я хотел знать, как переменная счетчика ++ может быть сопоставлена или соотноситься с любой продолжительностью при использовании с прерыванием, но вы говорите, что это невозможно без дополнительного внутреннего прерывания или задержки, но я видел, как это делается без всего этого, поэтому я не получаю, @Jim
Если вы видели, как это делалось без этого, то вы смотрите на что-то совершенно другое. Вы не можете получить X в секунду, не введя понятие "секунды". Прерывание не имеет к этому никакого отношения, если вы явно не закодируете его там, как в моем втором примере., @Majenko
так что же такое счетчик, такой как ++ или +1? это всего лишь байт в памяти регистраторов?, @Jim
Любой. Они оба означают одно и то же. rev++
означает "увеличить обороты", "rev = rev + 1"означает" добавить 1 к обороту и сохранить его в обороте". rev+=1
означает "добавьте 1 к обороту и сохраните его в обороте"., @Majenko
нет, я спрашиваю, например, требуется ли 1 сек для увеличения оборотов счетчика ++ или +1, что одна секунда не имеет никакого отношения к счетчику? значение приращения-это всего лишь дополнительный байт в памяти?, @Jim
Значение приращения-это просто изменение переменной в памяти. Количество байтов, которое требуется, зависит от того, что это за переменная. Это просто переменная величина. Нет ничего (кроме флага "volatile"), что отличало бы его от любой другой переменной., @Majenko
да, я понимаю это, как поплавок, int, длинный и т. Д., Переменный размер. Я говорю, что время не имеет никакого отношения, оно не хранится вместе с приращением. например, магнит проходит через язычок, 1 отсчет, 1 секунда, еще один проход, 2 отсчета, 2 секунды и т. Д.?, @Jim
Если вы не создадите переменную для хранения подобных вещей, где она будет храниться? Он всегда делает *точно* только то, что вы ему говорите. В фоновом режиме *никогда* нет никакой "магии" для хранения дополнительных данных., @Majenko
ладно, круто. Я подумал, что, может быть, функция в interupt смотрела на контакт interupt и отмечала его время, подсчитывала время, которое потребовалось. На самом деле я вижу выделение кода только с переменной++, затем они хранят это в переменной и хранят общее количество в другой переменной, используют это в течение некоторого времени и т. Д. Я не видел никаких милис и т. Д., Как вы видите в задержке мигания, ничего из этого, поэтому был озадачен тем, как это работало, @Jim
Ладно, кажется, я понимаю, что они делали. Они использовали rev++ в вызываемой функции interupt, сохранили это количество в переменной rev, присвоили значение 0, а затем использовали другую переменную для хранения общего количества в revA. когда ревА больше, чем рев, делай что-нибудь, иначе ничего не делай. все еще кажется, что это будет зависеть от времени, но...сбивает с толку., @Jim
они сравнивали 2 переменные и сохраняли большее количество, затем использовали это условие для включения двигателя, так что оно ни к чему не было приурочено, просто когда одна стала больше другой, сохраните это, и это условие стало истинным, включите двигатель... Что касается вложенных операторов "если", если у вас есть if, то вложенное if равносильно И, правильно? но "если", тогда "если" равносильно "НЕТ", верно?, @Jim
- Почему необходимо использовать ключевое слово volatile для глобальных переменных при обработке прерываний в ардуино?
- Серийное прерывание
- Прерывание ардуино при смене контакта
- Влияет ли `millis()` на длинные ISR?
- Как прервать функцию цикла и перезапустить ее?
- Задержка Arduino внутри прерывания
- Аппаратное прерывание срабатывает случайным образом
- Какой правильный способ запроса устройства I2C из процедуры обслуживания прерывания?
Он этого не знает. Вам придется кодировать это самостоятельно. Вы действительно могли бы иметь ISR, хранящий значение `millis ()'. Еще лучше было бы, чтобы ISR (локально) хранил значение millis() последнего вызова ISR. Затем, когда ISR вызывается в следующий раз, он может вычислить время, прошедшее с момента последнего вызова ISR. Если двигатель работает быстрее, этот метод может стать немного менее точным. В этом случае вы могли бы иметь основной "цикл" измерения времени, необходимого для увеличения счетчика, например, на 20 (то есть на 20 оборотов). Он может рассчитать среднюю скорость вращения., @Gerben
поэтому, когда люди используют для ex. interupt, чтобы вызвать функцию, например void Revolutions(){ rev++; }; а затем есть оператор if с переменными типа if { revA = rev; rev=0; для хранения оборотов и использования этого снова в другом операторе if, например, если revA>rev, analogWrite(motor) длительность значения, хранящегося в revA, не сохраняется? если нет, то что хранится?, @Jim
@Jim Когда люди просто считают такие революции, они вводят понятие времени на более позднем этапе. Например, они будут смотреть (и сбрасывать) этот счет один раз в секунду, давая количество оборотов в этом секундном окне и, следовательно, количество оборотов в секунду., @Majenko
"они будут смотреть (и сбрасывать) этот счет один раз в секунду, давая количество оборотов в этом односекундном окне и, следовательно, количество оборотов в секунду". Я просто пытаюсь понять, что, например, counter++ или rev+1 и т. Д. Тоже привязано? interupt вызывает функцию, затем 1,2,3,4.... подсчитывает проход, его сохранение, а затем выводит в соответствии с каким временем?, @Jim
возможно, главное, чего мне не хватает, - это "сброс", используется прерывание, вызывается его функция, а затем сбрасывается так, чтобы временные рамки всех наборов/сбросов соответствовали общему количеству времени, затраченному на захват времени, которое вы хотите включить двигатель, например. это означает, что если бы захват 500 наборов/сбросов занял 1 минуту, то вы могли бы приблизительно зафиксировать это в переменной?, @Jim
Главное, что вы упускаете, - это то, что "время" не имеет абсолютно никакого отношения к прерыванию. Он находится в другом месте программы, так как *написан программистом скетча*. Это может быть так же просто, как "задержка(1000)" в основном цикле, или это может быть сделано с помощью millis() неблокирующим способом., @Majenko
да, я видел, как это делается на скетче, без задержки или миллиса в вызываемой функции interupt, @Jim