Arduino'da loop () ne kadar hızlı çalışır?

Merhaba, Unity3D konusundaki deneyimimi oyunlaştırmak için Arduino Nano kullanıyorum. Unity3D'deki Güncelle() 'nin saniyede bir kare çalıştığını biliyorum, ancak elektronik bir adam olmadığım için Arduino'da loop() işlevinin nasıl çalıştığını bilmiyorum .

CPU döngüsünün sayısına (veya Arduino durumunda mikro işlemci çipine) mi bağlı, yoksa ne? Lütfen açıkla. Oyunumda bazı gecikmelerle karşılaşıyorum. Onları ancak Arduino'da loop() işlevinin nasıl çalıştığını biliyorsanız düzeltebilirim.

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

4
Kısa cevap "olabildiğince hızlı" gibi görünüyor.
katma yazar Jirka Hanika, kaynak
"Saniyedeki her kareyi çalıştırır" kareleri tamamen anladığınızdan emin değilsiniz, ya da belki sadece bir yazım hatası. ancak Unity3D'de her kare mümkün olduğunca hızlı çalışır, kasıtlı olarak değil, çerçevede bir gecikme olur
katma yazar Udo G, kaynak
çerçeveye bir gecikme koyun (düzenleyemez mi? yapabileceğimi düşündüm)
katma yazar Udo G, kaynak

5 cevap

Döngü çalışması gerektiği sürece döngü çalışır.

Bir CPU'daki talimatlar sırayla çalışır. Ne kadar fazla talimat varsa o kadar uzun sürer.

Döngü içine girdiğiniz kod ne kadar uzun olursa o kadar uzun çalışacaktır.

Her döngü yinelemesinin ne kadar süreceğini bilmek için iki yol vardır:

  1. Profilleme: Döngünün her yinelemesini aktif olarak zamanlayın, uyarılsa da, zamanlama eylemi geçen süreyi etkiler.
  2. Döngü sayımı. Kaynağı derlemede derleyin ve tüm talimatlar için gerekli fonksiyonların toplam sayısını (fonksiyon çağrıları dahil) toplayın. Küçük döngüler için zorlu, başka bir şey için devasa bir görev.

Ayrıca, birçok dış faktörün, döngünün() ne kadar süreceğini etkileyebileceğini unutmayın - örneğin seri iletişim hızı vb.

8
katma
@FilipFranik: 1. millis() değerini güncelleyen kesme, her 1024 µs'de veya 16 MHz'de 16384 CPU döngüsünde çalışır. 2. Kesintiler, yazılım PWM çıktısının kalitesini etkiler (örneğin, Servo kütüphanesi). Donanım tarafından oluşturulan PWM üzerinde etkisi yoktur (örneğin, analogWrite() ile).
katma yazar Sprogz, kaynak
Kesintileri unutmayın; örneğin, her 16000 saat döngüsünde (16Mhz osilatör için) milis değerini güncelleme. Düzenli aralıklarla programın çalışmasını durdururlar ve arduino'nun iyi bir PWM kaynağı olmasını önlerler. (evet onları kapatabilirsiniz)
katma yazar Robert Sibek, kaynak

Döngünün sonu() ile bir sonraki çalıştırması arasındaki talimatlar bir ret, jmp ve bir çağrıdır.

Ana işlevi etkin olarak düşünebilirsiniz:

void main(){

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

}

Gerçekte gerçekte millis() ve benzeri işleri yapmak için init() 'dan önce yapılan bazı kurulumlar vardır.

3
katma
@Majenko bu kesinti ile bitmedi mi?
katma yazar CTKeane, kaynak
Arduino'nun standart çalışma süresine baktıkça, daha fazla kirilmis oluyorum ...
katma yazar CTKeane, kaynak
@ next-hack: Arduino IDE'nin daha yeni sürümleri, -flto seçeneğiyle gcc çağrısı yapar, bu da bağlantı zamanı optimizasyonunu sağlar ve loop() satır içi olmasına neden olabilir. Eski sürümler bu seçeneği kullanmaz, bu nedenle loop() art arda main() tarafından çağrılan gerçek bir işleve derlenir.
katma yazar Sprogz, kaynak
Ayrıca döngüden sonra seri olay kodunuz vardır.
katma yazar Majenko, kaynak
Hayır değil. Sadece döngünün sonunda denir. Çok kaba ve birçok insan ne kadar anlamsız olduğunu anlamıyor.
katma yazar Majenko, kaynak
Ben döngü() derleyici tarafından optimize edilmiş olduğunu düşünüyorum, bu nedenle gerçek jmp veya ret oluşmaz. Kod şu şekildedir: while (1) yourLoopCode; işlev çağrısı olmadan. Ama GCC ile korkunç aptal şeyler gördüm ...
katma yazar next-hack, kaynak

Bu döngüde ne olduğuna bağlı. Birkaç saat döngüsünden sonsuz asmaya kadar.

1
katma

Main.cpp dosyasına (kurulumumdaki avr kodu için) dosyaya bir bakış:

C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino\main.cpp

Arduino'nun döngüsel() dönüşümlü olarak sonsuz döngüdeki serialEventRun() ile çalıştığını gösterir:

int main(void)
{
    init();
    initVariant();
 #if defined(USBCON)
    USBDevice.attach();
#endif

    setup();

    for (;;) {
        loop();
        if (serialEventRun) serialEventRun();
    }

    return 0;
}

HardwareSerial.cpp'in denetlenmesi, serialEventRun() öğesinin çiziminizde tanımladıysanız, basitçe serialEvent() öğesini çağırdığını gösterir.

Bu, serialEvent() kodunu yazmamış ve düzenli çalışmasını beklemiyorsanız, kendi sonsuz döngünüzü döngü() içine güvenle yazabileceğiniz anlamına gelir.

Bu şu soruyu soruyor: eğer serialEvent (), döngü() ile sıralı olarak çağırılırsa, loop() hiç dönmezse, serialEvent() çağrılacak mı? Başka bir deyişle, serialEvent (), döngü() döndüğünde çağrılmasının yanı sıra, kesme odaklı mıdır? Aşağıda görülen hızlı bir test, sürenin sürülmediğini değil olduğunu gösterir, bu nedenle önceki paragraf doğrudur.

/*
  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 = "";
    }
  }
}

Bu, serialEvent() kodunun a: içindeki ana döngünüze() girebileceği anlamına gelir:

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

blok.

1
katma

arduino işlevlerini ararken deneyin mikrosaniye () ve delayMicroseconds () Döngünüze 16000 mikrosaniyeden daha uzun süre beklemeniz gerekiyorsa, milisaniye yapan diğer delay() işlevine de bakın.

Bu arada, dahili saat çok az kapalıdır ve oda sıcaklığına göre değişir, bu nedenle bir el sıkışma olmadan diğer cihazınızla senkronize kalmaya güvenmeyin.

0
katma
micros() ve delayMicroseconds() 32 bit tam sayılar kullanır ( uzun süre işaretsiz ) ve 2³² µs veya yaklaşık 1,19 saate kadar olan süreleri yönetebilir .
katma yazar Sprogz, kaynak