як швидко працює loop () у Arduino

Привіт, я використовую Arduino Nano , щоб охарактеризувати мій досвід роботи з Unity3D. Я знаю, що Update() в Unity3D запускає кожен кадр на секунду, але я, тому що я не людина з електроніки, я не знаю, як функція loop() працює на Arduino .

Чи залежить це від кількості процесорних циклів (або мікропроцесорного чіпа у випадку Arduino) або що? Будь ласка, поясніть. Я зіткнувся з деякими відставаннями в своїй грі. Я можу їх виправити, лише якщо знаю, як функція loop() працює на Arduino

There ain't a lot of information about loop() in arduino documentation

4
Схоже, що коротка відповідь "якомога швидше".
додано Автор Jirka Hanika, джерело
"працює кожен кадр в секунду" не впевнений, що ви повністю розумієте кадри, або, можливо, просто помилку. але в Unity3D кожен кадр працює якомога швидше, вони не цілеспрямовано, а затримка в кадрі
додано Автор Udo G, джерело
покласти затримку у кадрі (неможливо відредагувати?
додано Автор Udo G, джерело

5 Відповіді

Цикл запускається до тих пір, поки потрібно запустити цикл.

Інструкції в процесорі виконуються послідовно. Чим більше інструкцій, тим більше часу потрібно для запуску.

Чим більше код ви введете в цикл, тим довше буде цикл.

Є два способи дізнатися, як довго буде виконуватися кожна ітерація циклу:

  1. Профілювання: активоване час кожної ітерації циклу, хоча і попередження, акт тимчасової синхронізації вплине на кількість часу.
  2. Підрахунок циклів. Скомпілюйте джерело в збірку і підсумуйте кількість тактових циклів, необхідних для всіх інструкцій (включаючи виклики функцій). Напружена для малих петель, гігантська задача для будь-якого іншого.

Також зауважте, що багато зовнішніх факторів можуть впливати на тривалість циклу() для запуску - наприклад, швидкість послідовного зв'язку тощо.

8
додано
@FilipFranik: 1. Переривання, яке оновлює значення millis() , виконується кожні 1024 мкс, або 16384 процесорів на 16 МГц. 2. Переривання впливають на якість вихідного програмного ШІМ (наприклад, бібліотеки сервосистеми). Вони не впливають на PWM, створені апаратно (наприклад, з analogWrite() ).
додано Автор Sprogz, джерело
Не забувайте про переривання, наприклад, оновлення millis значення кожні 16000 тактових циклів (для 16Mhz oscilator). Вони припиняють виконання програми через регулярні проміжки часу і запобігають тому, щоб arduino був гарним джерелом PWM. (так, ви можете вимкнути їх)
додано Автор Robert Sibek, джерело

інструкції між кінцем циклу() і наступним його запуском - ret, jmp і виклик.

Головну функцію можна вважати ефективною:

void main(){

    init();
    while(1) loop();

}

Хоча насправді є деякі налаштування, зроблені перед init() , щоб зробити millis() і таку роботу.

3
додано
@Majenko це не зроблено з перериваннями?
додано Автор CTKeane, джерело
Чим більше я дивлюся на стандартний час виконання arduino, тим більше я розчарований ...
додано Автор CTKeane, джерело
@ next-hack: Новіші версії IDE Arduino викликають gcc з опцією -flto , яка дозволяє оптимізувати час зв'язку і може призвести до вбудовування loop() . Старі версії не використовують цю опцію, тому loop() компілюється в реальну функцію, яку неодноразово викликає main() .
додано Автор Sprogz, джерело
Також ви маєте послідовний код події після циклу.
додано Автор Majenko, джерело
Ні це не так. Це просто викликається в кінці циклу. Це дуже грубо, і багато людей не розуміють, наскільки це безглуздо.
додано Автор Majenko, джерело
Я думаю, що цикл() оптимізований компілятором, тому фактичні jmp або ret не відбуваються. Код перекладається на: while (1) yourLoopCode; без виклику функції. Але я бачив жахливі німі з GCC ...
додано Автор next-hack, джерело

Це залежить від того, що в циклі. Від кількох тактових циклів до нескінченного зависають.

1
додано

Подивіться на 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() повертається? Швидкий тест - див. Нижче - показує, що він не керований перериваннями, тому попередній абзац є істинним.

/*
  Serial Event Checker

  A sketch to see if serialEvent() is interrupt-driven.
  Will serialEvent() be called if loop() never returns?

  This code is based on Tom Igoe's SerialEvent example.

  On (at least) Arduino Uno we find that serialEvent() simply runs
  sequentially with loop().  When loop() never returns serialEvent()
  is never called.

  NOTE: The serialEvent() feature is not available on the Leonardo, Micro, or
  other ATmega32U4 based boards.

  R Symonds-Tayler 2018-02-01

  This example code is in the public domain.

*/

String inputString = "";        //a String to hold incoming data

void setup() {
 //initialize serial:
  Serial.begin(115200);
 //reserve 200 bytes for the inputString:
  inputString.reserve(200);
}

// comment out this definition to allow loop() to return
#define INFINITE_LOOP

void loop() { 
#ifdef INFINITE_LOOP
    while(1);
#endif

}

/*
  SerialEvent occurs whenever a new data comes in the hardware serial RX. This
  routine is run between each time loop() runs, so using delay inside loop can
  delay response. Multiple bytes of data may be available.
*/
void serialEvent() {
  while (Serial.available()) {
   //get the new byte:
    char inChar = (char)Serial.read();
   //add it to the inputString:
    inputString += inChar;
   //if the incoming character is a newline, set a flag so the main loop can
   //do something about it:
    if (inChar == '\n') {
      Serial.print("Got: '");
      Serial.print(inputString);
      Serial.println("'");
     //clear the string:
      inputString = "";
    }
  }
}

Це означає, що код serialEvent() може також перейти до основного циклу() у межах:

if(serial.available()){
  //your code here...
}

блок.

1
додано

спробуйте шукати функції arduino micros () і затримкамікросекунд () Якщо вам може знадобитися ваш цикл, щоб чекати довше 16000 мікросекунд, тоді також шукайте іншу функцію delay (), яка робить мілісекунди.

До речі, внутрішній годинник дуже слабкий і змінюється в залежності від температури приміщення, тому не покладайтеся на його синхронізацію з іншим пристроєм без рукостискання.

0
додано
micros() і delayMicroseconds() використовують 32-розрядні цілі числа ( unsigned long ) і можуть керувати тривалістю до 2 × 2 мкс або близько 1,19 год. .
додано Автор Sprogz, джерело