как быстро loop() работает в Arduino
Привет, я использую Arduino Nano
для геймификации своего опыта работы на Unity3D. Я знаю, что Update()
в Unity3D работает каждый кадр в секунду, но я, поскольку я не специалист по электронике, не знаю, как функция loop()
работает на Arduino.
Зависит ли это от количества циклов процессора(или микросхемы микропроцессора в случае Arduino) или что? Пожалуйста, объясните. Я столкнулся с некоторыми задержками в своей игре. Я могу исправить их только в том случае, если знаю, как работает функция loop() на Arduino
В документации arduino не так много информации о loop()
loop
6 ответов
Лучший ответ:
Цикл выполняется до тех пор, пока цикл должен выполняться.
Инструкции в процессоре выполняются последовательно. Чем больше инструкций, тем больше времени требуется для выполнения.
Чем больше кода вы введете в цикл, тем дольше будет выполняться цикл.
Существует два способа узнать, сколько времени займет каждая итерация цикла:
- Профилирование: Активно размечайте каждую итерацию цикла, хотя имейте в виду, что акт синхронизации повлияет на количество затраченного времени.
- Подсчет циклов. Скомпилируйте исходный код в сборку и подсчитайте общее количество тактов, необходимых для всех инструкций (включая вызовы функций). Трудная для маленьких петель, гигантская задача для всего остального.
Также обратите внимание, что многие внешние факторы могут повлиять на продолжительность выполнения функции loop (), например, скорость последовательной связи и т.д.
Не забывайте о перерывах, например, обновляя значение миллисекунд каждые 16000 тактов (для генератора 16 МГц). Они регулярно останавливают выполнение программы и мешают arduino быть хорошим источником ШИМ. (да, вы можете отключить их), @Filip Franik
@FilipFranik: 1. Прерывание, которое обновляет значение millis ()
, выполняется каждые 1024 мкс, или 16384 цикла процессора с частотой 16 МГц. 2. Прерывания влияют на качество программного ШИМ-вывода (например, библиотека сервоприводов). Они не влияют на аппаратно сгенерированный PWM (например, с помощью " analogWrite ()")., @Edgar Bonet
Это зависит от того, что находится в цикле. От нескольких тактов до бесконечного зависания.
инструкции между завершением цикла() и его следующим запуском-это ret, jmp и вызов.
Вы можете считать, что основная функция эффективно:
void main(){
init();
while(1) loop();
}
Хотя на самом деле есть некоторая настройка, выполненная до init ()
, чтобы сделать millis()
и такую работу.
Также у вас есть последовательный код события после цикла., @Majenko
@Majenko разве это не сделано с прерываниями?, @ratchet freak
Нет, это не так. Он просто вызывается в конце цикла. Это очень грубо, и многие люди не понимают, насколько это бессмысленно на самом деле., @Majenko
Я думаю, что loop() оптимизирован компилятором, поэтому никаких реальных jmp или ret не происходит. Код переводится как: while (1) Ваш пароль; без вызова функции. Но я видел ужасные глупые вещи с GCC..., @next-hack
Чем больше я смотрю на стандартную среду выполнения arduino, тем больше я разочаровываюсь..., @ratchet freak
@следующий взлом: Более новые версии Arduino IDE вызывают gcc с опцией "- flto", которая позволяет оптимизировать время соединения и может привести к встроенному циклу (). Более старые версии не используют эту опцию, поэтому "loop ()" компилируется в реальную функцию, которая неоднократно вызывается " main ()"., @Edgar Bonet
попробуйте найти функции arduino micros() и delaymicrosecondes() Если вам может потребоваться, чтобы цикл ждал дольше 16000 микросекунд, также найдите другую функцию delay (), которая выполняет миллисекунды.
Кстати, внутренние часы очень немного выключены и меняются в зависимости от комнатной температуры, поэтому не полагайтесь на то, что они будут синхронизированы с другим вашим устройством без рукопожатия.
micros()
и delayMicroseconds()
используют 32-разрядные целые числа ("длина без знака") и могут управлять длительностью до 232 мкс, или около 1,19 часов., @Edgar Bonet
Взгляните на main.cpp (для кода avr в моей установке) в файле:
C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino\main.cpp
показывает, что Arduino запускает loop() попеременно с serialEventRun() в бесконечном цикле:
int main(void)
{
init();
initVariant();
#if defined(USBCON)
USBDevice.attach();
#endif
setup();
for (;;) {
loop();
if (serialEventRun) serialEventRun();
}
return 0;
}
Осмотр HardwareSerial.cpp показывает, что функция serialEventRun() просто вызывает функцию serialEvent (), если вы определили ее в своем скетче.
Это означает, что вы можете совершенно безопасно написать свой собственный бесконечный цикл внутри цикла (), если только вы не написали код serialEvent() и не ожидаете, что он будет выполняться регулярно.
Возникает вопрос: если serialEvent() вызывается последовательно с помощью loop(), будет ли вызываться serialEvent (), если loop() никогда не вернется? Другими словами, является ли serialEvent() управляемым прерыванием, а также вызывается при возврате loop ()? Быстрый тест-см. Ниже - показывает, что он не управляется прерываниями, поэтому предыдущий абзац верен.
/*
Проверка последовательных событий
Скетч, чтобы увидеть, вызвана ли функция serialEvent() прерываниями.
Будет ли вызвана функция serialEvent(), если функция loop() никогда не вернется?
Этот код основан на примере сериального события Тома Айго.
На (по крайней мере) Arduino Uno мы обнаруживаем, что serialEvent() просто запускается
последовательно с помощью функции loop(). Когда loop() никогда не возвращает serialEvent()
никогда не вызывается.
ПРИМЕЧАНИЕ. Функция serialEvent() недоступна на платах Leonardo, Micro или
других платах на базе ATmega32U4.
R Саймондс-Тейлер 2018-02-01
Этот пример кода находится в открытом доступе.
*/
String inputString = ""; // строка для хранения входящих данных
void setup() {
// инициализация последовательного:
Serial.begin(115200);
// зарезервируйте 200 байт для входной строки:
inputString.reserve(200);
}
// прокомментируйте это определение, чтобы разрешить циклу loop() возвращаться
#define INFINITE_LOOP
void loop() {
#ifdef INFINITE_LOOP
while(1);
#endif
}
/*
Событие serialEvent происходит всякий раз, когда в аппаратный последовательный приемник поступают новые данные. Эта
процедура выполняется между запусками каждого цикла (), поэтому использование задержки внутри цикла может
задержать реакцию. Может быть доступно несколько байтов данных.
*/
void serialEvent() {
while (Serial.available()) {
// получите новый байт:
char inChar = (char)Serial.read();
// добавьте его в строку ввода:
inputString += inChar;
// если входящий символ является новой строкой, установите флаг, чтобы основной цикл мог
// сделай что-нибудь с этим:
if (inChar == '\n') {
Serial.print("Got: '");
Serial.print(inputString);
Serial.println("'");
// clear the string:
inputString = "";
}
}
}
Это означает, что код serialEvent() с таким же успехом может войти в ваш основной loop() внутри:
if(serial.available()){
// ваш код здесь...
}
блок.
В этой статье bri_huang провел хороший эксперимент с использованием осциллографа и простых функций записи.
Он подсчитал, что скорость петли составляет 117 кГц, хотя микроконтроллер имеет тактовую частоту 16 МГц.
https://learn.sparkfun.com/blog/1687
Эта ссылка на самом деле мало что говорит о том, насколько “быстра” "петля ()" (что И. М. О. бессмысленно), а только о том, насколько быстра реализация Arduino "digitalWrite ()" (что не совсем самый быстрый способ переключения контакта на Arduino)., @StarCat
Так что, удовлетворительного ответа пока нет? Или мы можем предположить, что он работает со скоростью кварцевого генератора?, @Alejandro Camus
@Alejandro Camus У него есть миллиард факторов на всем пути от температуры вашей комнаты до того, какую нагрузку обрабатывает микропроцессор, мы даже не можем сказать, что он работает со скоростью генератора, так как для выполнения команд требуется время, @Coder9390
Это хороший тест того, насколько быстро работает digitalWrite()
; не очень хороший тест того, насколько быстры циклы loop()
. В этом тесте они сравнивали digitalWrite()
без разумных ожиданий, что это один такт или одна инструкция., @Edward Ned Harvey
Ага, баллы сняты, @Alejandro Camus
- Как я могу остановить цикл при использовании сервопривода с клавишным вводом?
- Невозможно получить показания счетчика (Modbus)
- Загрузка Arduino Nano дает ошибку: avrdude: stk500_recv(): programmer is not responding
- устаревшее преобразование из строковой константы в 'char*'
- Использовать Arduino Nano V3 для программирования другого Arduino (Pro Mini)?
- как отправить аргумент объектам ESP8266WebServer в функции
- Arduino синтаксический анализ строки с использованием sscanf
- Как прочитать значение PIN PWM-выхода?
"работает каждый кадр в секунду" не уверен, что вы полностью понимаете кадры, или, может быть, просто опечатка. но в Unity3D каждый кадр работает как можно быстрее, они делают это не целенаправленно, а с задержкой в кадре, @MCMastery
*поставьте* задержку в кадре (не можете ее отредактировать? я думал что смогу), @MCMastery
Похоже, короткий ответ - "как можно быстрее"., @user253751