Milislerin harcadığı zamanı bulmak mümkün mü?


13

İşlev millis100+ mikrosaniye veya daha kısa bir sürede çalışacaktır. Tek bir milis çağrısı ile geçen süreyi ölçmenin güvenilir bir yolu var mı?

microsBununla birlikte, akla gelen bir yaklaşım , bir çağrı çağrısını micros, fonksiyon çağrısının microskendisi tarafından harcanan zamanı da içerecektir , bu yüzden mikronların ne kadar sürdüğüne bağlı olarak, ölçüm milliskapalı olabilir.

Üzerinde çalıştığım bir uygulama olarak kod dahil her adım için doğru zaman ölçümleri gerektirir bulmak gerekir millis.


Burada ne istediğini açıklayabilir misin? Milis () 'den doğru zamanlar almaya mı çalışıyorsunuz yoksa milis () işlevini çağırmanın ne kadar sürdüğünü bulmaya çalışıyorsunuz?
Cybergibbons

@Cybergibbons Bir aramanın ne kadar miilissürdüğü.
asheeshr

Yanıtlar:


21

Bir şeyin ne kadar süreceğini tam olarak bilmek istiyorsanız , tek bir çözüm var: Sökmeye bakın!

Minimum kodla başlayarak:

void setup(){};

volatile uint16_t x;
void loop()
{
  x = millis();

}

Bu kod derlendi ve daha sonra beslendi avr-objdump -Sbelgelenmiş bir demontaj üretir. İşte ilginç alıntılar:

void loop() üretir:

000000a8 <loop>:
  a8:   0e 94 a7 00     call    0x14e   ; 0x14e <millis>
  ac:   60 93 00 01     sts 0x0100, r22
  b0:   70 93 01 01     sts 0x0101, r23
  b4:   80 93 02 01     sts 0x0102, r24
  b8:   90 93 03 01     sts 0x0103, r25
  bc:   08 95           ret

Bu bir işlev çağrısı ( call), dört kopya (her baytın uint32_tdönüş değerinde her kopyasını kopyalar ( millis()arduino belgelerinin bunu a olarak adlandırdığını unutmayın long, ancak değişken boyutları açıkça belirtmemek yanlıştır) ve son olarak işlev dönüşü.

call4 saat döngüsü stsgerektirir ve her biri 2 saat döngüsü gerektirir, bu nedenle sadece işlev çağrısı yükü için minimum 12 saat döngüsüne sahibiz.

Şimdi, <millis>şu konumda bulunan işlevin sökülmesine bakalım 0x14e:

unsigned long millis()
{
    unsigned long m;
    uint8_t oldSREG = SREG;
 14e:   8f b7           in  r24, 0x3f   ; 63

    // disable interrupts while we read timer0_millis or we might get an
    // inconsistent value (e.g. in the middle of a write to timer0_millis)
    cli();
 150:   f8 94           cli
    m = timer0_millis;
 152:   20 91 08 01     lds r18, 0x0108
 156:   30 91 09 01     lds r19, 0x0109
 15a:   40 91 0a 01     lds r20, 0x010A
 15e:   50 91 0b 01     lds r21, 0x010B
    SREG = oldSREG;
 162:   8f bf           out 0x3f, r24   ; 63

    return m;
}
 164:   b9 01           movw    r22, r18
 166:   ca 01           movw    r24, r20
 168:   08 95           ret

Gördüğünüz gibi, millis()fonksiyon oldukça basit:

  1. in kesme kayıt ayarlarını kaydeder (1 döngü)
  2. cli kesintileri kapatır (1 döngü)
  3. lds milli sayacın geçerli değerinin 4 baytından birini geçici bir kayıt defterine kopyalayın (2 saat döngüsü)
  4. lds Bayt 2 (2 saat çevrimi)
  5. lds Bayt 3 (2 saat çevrimi)
  6. lds Bayt 4 (2 saat çevrimi)
  7. out kesme ayarlarını geri yükle (1 saat çevrimi)
  8. movw karışık kayıtlar (1 saat döngü)
  9. movw ve tekrar (1 saat döngü)
  10. ret altyordamdan dönüş (4 döngü)

Yani, hepsini toplarsak, millis()fonksiyonun kendisinde toplam 17 saat döngüsünün yanı sıra toplam 29 saat döngüsü için 12 çağrı yükü var.

16 Mhz saat hızı (çoğu arduino) varsayarsak, her saat döngüsü 1 / 16e6saniye veya 0.0000000625 saniyedir, bu da 62.5 nanosaniye'dir. 62,5 ns * 29 = 1,812 mikrosaniye.

Bu nedenle, çoğu Arduino'da tek bir millis()çağrı için toplam yürütme süresi 1.812 mikrosaniye olacaktır .


AVR Montaj referansı

Bir yan not olarak, burada optimizasyon için yer var! unsigned long millis(){}İşlev tanımını güncellerseniz, inline unsigned long millis(){}çağrı ek yükünü kaldırabilirsiniz ( biraz daha büyük kod boyutu pahasına ). Ayrıca, derleyici iki gereksiz hareket yapıyor gibi görünüyor (iki movwçağrı, ama ben o kadar yakından bakmadım).

Gerçekten, işlev çağrısı yükü dikkate 5 talimatları olduğunu ve gerçek içerikleri arasında millis()fonksiyonu sadece 6 talimatları, sanırım millis()işlevi gerçekten olmalıdır inlinevarsayılan olarak, ancak Arduino kod temeli oldukça zayıf duruma getirilmiştir.


İşte ilgilenen herkes için tam bir sökme:

sketch_feb13a.cpp.elf:     file format elf32-avr


Disassembly of section .text:

00000000 <__vectors>:
    SREG = oldSREG;

    return m;
}

unsigned long micros() {
   0:   0c 94 34 00     jmp 0x68    ; 0x68 <__ctors_end>
   4:   0c 94 51 00     jmp 0xa2    ; 0xa2 <__bad_interrupt>
   8:   0c 94 51 00     jmp 0xa2    ; 0xa2 <__bad_interrupt>
   c:   0c 94 51 00     jmp 0xa2    ; 0xa2 <__bad_interrupt>
  10:   0c 94 51 00     jmp 0xa2    ; 0xa2 <__bad_interrupt>
  14:   0c 94 51 00     jmp 0xa2    ; 0xa2 <__bad_interrupt>
  18:   0c 94 51 00     jmp 0xa2    ; 0xa2 <__bad_interrupt>
  1c:   0c 94 51 00     jmp 0xa2    ; 0xa2 <__bad_interrupt>
  20:   0c 94 51 00     jmp 0xa2    ; 0xa2 <__bad_interrupt>
  24:   0c 94 51 00     jmp 0xa2    ; 0xa2 <__bad_interrupt>
  28:   0c 94 51 00     jmp 0xa2    ; 0xa2 <__bad_interrupt>
  2c:   0c 94 51 00     jmp 0xa2    ; 0xa2 <__bad_interrupt>
  30:   0c 94 51 00     jmp 0xa2    ; 0xa2 <__bad_interrupt>
  34:   0c 94 51 00     jmp 0xa2    ; 0xa2 <__bad_interrupt>
  38:   0c 94 51 00     jmp 0xa2    ; 0xa2 <__bad_interrupt>
  3c:   0c 94 51 00     jmp 0xa2    ; 0xa2 <__bad_interrupt>
  40:   0c 94 5f 00     jmp 0xbe    ; 0xbe <__vector_16>
  44:   0c 94 51 00     jmp 0xa2    ; 0xa2 <__bad_interrupt>
  48:   0c 94 51 00     jmp 0xa2    ; 0xa2 <__bad_interrupt>
  4c:   0c 94 51 00     jmp 0xa2    ; 0xa2 <__bad_interrupt>
  50:   0c 94 51 00     jmp 0xa2    ; 0xa2 <__bad_interrupt>
  54:   0c 94 51 00     jmp 0xa2    ; 0xa2 <__bad_interrupt>
  58:   0c 94 51 00     jmp 0xa2    ; 0xa2 <__bad_interrupt>
  5c:   0c 94 51 00     jmp 0xa2    ; 0xa2 <__bad_interrupt>
  60:   0c 94 51 00     jmp 0xa2    ; 0xa2 <__bad_interrupt>
  64:   0c 94 51 00     jmp 0xa2    ; 0xa2 <__bad_interrupt>

00000068 <__ctors_end>:
  68:   11 24           eor r1, r1
  6a:   1f be           out 0x3f, r1    ; 63
  6c:   cf ef           ldi r28, 0xFF   ; 255
  6e:   d8 e0           ldi r29, 0x08   ; 8
  70:   de bf           out 0x3e, r29   ; 62
  72:   cd bf           out 0x3d, r28   ; 61

00000074 <__do_copy_data>:
  74:   11 e0           ldi r17, 0x01   ; 1
  76:   a0 e0           ldi r26, 0x00   ; 0
  78:   b1 e0           ldi r27, 0x01   ; 1
  7a:   e2 e0           ldi r30, 0x02   ; 2
  7c:   f2 e0           ldi r31, 0x02   ; 2
  7e:   02 c0           rjmp    .+4         ; 0x84 <.do_copy_data_start>

00000080 <.do_copy_data_loop>:
  80:   05 90           lpm r0, Z+
  82:   0d 92           st  X+, r0

00000084 <.do_copy_data_start>:
  84:   a0 30           cpi r26, 0x00   ; 0
  86:   b1 07           cpc r27, r17
  88:   d9 f7           brne    .-10        ; 0x80 <.do_copy_data_loop>

0000008a <__do_clear_bss>:
  8a:   11 e0           ldi r17, 0x01   ; 1
  8c:   a0 e0           ldi r26, 0x00   ; 0
  8e:   b1 e0           ldi r27, 0x01   ; 1
  90:   01 c0           rjmp    .+2         ; 0x94 <.do_clear_bss_start>

00000092 <.do_clear_bss_loop>:
  92:   1d 92           st  X+, r1

00000094 <.do_clear_bss_start>:
  94:   ad 30           cpi r26, 0x0D   ; 13
  96:   b1 07           cpc r27, r17
  98:   e1 f7           brne    .-8         ; 0x92 <.do_clear_bss_loop>
  9a:   0e 94 f0 00     call    0x1e0   ; 0x1e0 <main>
  9e:   0c 94 ff 00     jmp 0x1fe   ; 0x1fe <_exit>

000000a2 <__bad_interrupt>:
  a2:   0c 94 00 00     jmp 0   ; 0x0 <__vectors>

000000a6 <setup>:
  a6:   08 95           ret

000000a8 <loop>:
  a8:   0e 94 a7 00     call    0x14e   ; 0x14e <millis>
  ac:   60 93 00 01     sts 0x0100, r22
  b0:   70 93 01 01     sts 0x0101, r23
  b4:   80 93 02 01     sts 0x0102, r24
  b8:   90 93 03 01     sts 0x0103, r25
  bc:   08 95           ret

000000be <__vector_16>:
#if defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
ISR(TIM0_OVF_vect)
#else
ISR(TIMER0_OVF_vect)
#endif
{
  be:   1f 92           push    r1
  c0:   0f 92           push    r0
  c2:   0f b6           in  r0, 0x3f    ; 63
  c4:   0f 92           push    r0
  c6:   11 24           eor r1, r1
  c8:   2f 93           push    r18
  ca:   3f 93           push    r19
  cc:   8f 93           push    r24
  ce:   9f 93           push    r25
  d0:   af 93           push    r26
  d2:   bf 93           push    r27
    // copy these to local variables so they can be stored in registers
    // (volatile variables must be read from memory on every access)
    unsigned long m = timer0_millis;
  d4:   80 91 08 01     lds r24, 0x0108
  d8:   90 91 09 01     lds r25, 0x0109
  dc:   a0 91 0a 01     lds r26, 0x010A
  e0:   b0 91 0b 01     lds r27, 0x010B
    unsigned char f = timer0_fract;
  e4:   30 91 0c 01     lds r19, 0x010C

    m += MILLIS_INC;
  e8:   01 96           adiw    r24, 0x01   ; 1
  ea:   a1 1d           adc r26, r1
  ec:   b1 1d           adc r27, r1
    f += FRACT_INC;
  ee:   23 2f           mov r18, r19
  f0:   2d 5f           subi    r18, 0xFD   ; 253
    if (f >= FRACT_MAX) {
  f2:   2d 37           cpi r18, 0x7D   ; 125
  f4:   20 f0           brcs    .+8         ; 0xfe <__vector_16+0x40>
        f -= FRACT_MAX;
  f6:   2d 57           subi    r18, 0x7D   ; 125
        m += 1;
  f8:   01 96           adiw    r24, 0x01   ; 1
  fa:   a1 1d           adc r26, r1
  fc:   b1 1d           adc r27, r1
    }

    timer0_fract = f;
  fe:   20 93 0c 01     sts 0x010C, r18
    timer0_millis = m;
 102:   80 93 08 01     sts 0x0108, r24
 106:   90 93 09 01     sts 0x0109, r25
 10a:   a0 93 0a 01     sts 0x010A, r26
 10e:   b0 93 0b 01     sts 0x010B, r27
    timer0_overflow_count++;
 112:   80 91 04 01     lds r24, 0x0104
 116:   90 91 05 01     lds r25, 0x0105
 11a:   a0 91 06 01     lds r26, 0x0106
 11e:   b0 91 07 01     lds r27, 0x0107
 122:   01 96           adiw    r24, 0x01   ; 1
 124:   a1 1d           adc r26, r1
 126:   b1 1d           adc r27, r1
 128:   80 93 04 01     sts 0x0104, r24
 12c:   90 93 05 01     sts 0x0105, r25
 130:   a0 93 06 01     sts 0x0106, r26
 134:   b0 93 07 01     sts 0x0107, r27
}
 138:   bf 91           pop r27
 13a:   af 91           pop r26
 13c:   9f 91           pop r25
 13e:   8f 91           pop r24
 140:   3f 91           pop r19
 142:   2f 91           pop r18
 144:   0f 90           pop r0
 146:   0f be           out 0x3f, r0    ; 63
 148:   0f 90           pop r0
 14a:   1f 90           pop r1
 14c:   18 95           reti

0000014e <millis>:

unsigned long millis()
{
    unsigned long m;
    uint8_t oldSREG = SREG;
 14e:   8f b7           in  r24, 0x3f   ; 63

    // disable interrupts while we read timer0_millis or we might get an
    // inconsistent value (e.g. in the middle of a write to timer0_millis)
    cli();
 150:   f8 94           cli
    m = timer0_millis;
 152:   20 91 08 01     lds r18, 0x0108
 156:   30 91 09 01     lds r19, 0x0109
 15a:   40 91 0a 01     lds r20, 0x010A
 15e:   50 91 0b 01     lds r21, 0x010B
    SREG = oldSREG;
 162:   8f bf           out 0x3f, r24   ; 63

    return m;
}
 164:   b9 01           movw    r22, r18
 166:   ca 01           movw    r24, r20
 168:   08 95           ret

0000016a <init>:

void init()
{
    // this needs to be called before setup() or some functions won't
    // work there
    sei();
 16a:   78 94           sei

    // on the ATmega168, timer 0 is also used for fast hardware pwm
    // (using phase-correct PWM would mean that timer 0 overflowed half as often
    // resulting in different millis() behavior on the ATmega8 and ATmega168)
#if defined(TCCR0A) && defined(WGM01)
    sbi(TCCR0A, WGM01);
 16c:   84 b5           in  r24, 0x24   ; 36
 16e:   82 60           ori r24, 0x02   ; 2
 170:   84 bd           out 0x24, r24   ; 36
    sbi(TCCR0A, WGM00);
 172:   84 b5           in  r24, 0x24   ; 36
 174:   81 60           ori r24, 0x01   ; 1
 176:   84 bd           out 0x24, r24   ; 36
    // this combination is for the standard atmega8
    sbi(TCCR0, CS01);
    sbi(TCCR0, CS00);
#elif defined(TCCR0B) && defined(CS01) && defined(CS00)
    // this combination is for the standard 168/328/1280/2560
    sbi(TCCR0B, CS01);
 178:   85 b5           in  r24, 0x25   ; 37
 17a:   82 60           ori r24, 0x02   ; 2
 17c:   85 bd           out 0x25, r24   ; 37
    sbi(TCCR0B, CS00);
 17e:   85 b5           in  r24, 0x25   ; 37
 180:   81 60           ori r24, 0x01   ; 1
 182:   85 bd           out 0x25, r24   ; 37

    // enable timer 0 overflow interrupt
#if defined(TIMSK) && defined(TOIE0)
    sbi(TIMSK, TOIE0);
#elif defined(TIMSK0) && defined(TOIE0)
    sbi(TIMSK0, TOIE0);
 184:   ee e6           ldi r30, 0x6E   ; 110
 186:   f0 e0           ldi r31, 0x00   ; 0
 188:   80 81           ld  r24, Z
 18a:   81 60           ori r24, 0x01   ; 1
 18c:   80 83           st  Z, r24
    // this is better for motors as it ensures an even waveform
    // note, however, that fast pwm mode can achieve a frequency of up
    // 8 MHz (with a 16 MHz clock) at 50% duty cycle

#if defined(TCCR1B) && defined(CS11) && defined(CS10)
    TCCR1B = 0;
 18e:   e1 e8           ldi r30, 0x81   ; 129
 190:   f0 e0           ldi r31, 0x00   ; 0
 192:   10 82           st  Z, r1

    // set timer 1 prescale factor to 64
    sbi(TCCR1B, CS11);
 194:   80 81           ld  r24, Z
 196:   82 60           ori r24, 0x02   ; 2
 198:   80 83           st  Z, r24
#if F_CPU >= 8000000L
    sbi(TCCR1B, CS10);
 19a:   80 81           ld  r24, Z
 19c:   81 60           ori r24, 0x01   ; 1
 19e:   80 83           st  Z, r24
    sbi(TCCR1, CS10);
#endif
#endif
    // put timer 1 in 8-bit phase correct pwm mode
#if defined(TCCR1A) && defined(WGM10)
    sbi(TCCR1A, WGM10);
 1a0:   e0 e8           ldi r30, 0x80   ; 128
 1a2:   f0 e0           ldi r31, 0x00   ; 0
 1a4:   80 81           ld  r24, Z
 1a6:   81 60           ori r24, 0x01   ; 1
 1a8:   80 83           st  Z, r24

    // set timer 2 prescale factor to 64
#if defined(TCCR2) && defined(CS22)
    sbi(TCCR2, CS22);
#elif defined(TCCR2B) && defined(CS22)
    sbi(TCCR2B, CS22);
 1aa:   e1 eb           ldi r30, 0xB1   ; 177
 1ac:   f0 e0           ldi r31, 0x00   ; 0
 1ae:   80 81           ld  r24, Z
 1b0:   84 60           ori r24, 0x04   ; 4
 1b2:   80 83           st  Z, r24

    // configure timer 2 for phase correct pwm (8-bit)
#if defined(TCCR2) && defined(WGM20)
    sbi(TCCR2, WGM20);
#elif defined(TCCR2A) && defined(WGM20)
    sbi(TCCR2A, WGM20);
 1b4:   e0 eb           ldi r30, 0xB0   ; 176
 1b6:   f0 e0           ldi r31, 0x00   ; 0
 1b8:   80 81           ld  r24, Z
 1ba:   81 60           ori r24, 0x01   ; 1
 1bc:   80 83           st  Z, r24
#if defined(ADCSRA)
    // set a2d prescale factor to 128
    // 16 MHz / 128 = 125 KHz, inside the desired 50-200 KHz range.
    // XXX: this will not work properly for other clock speeds, and
    // this code should use F_CPU to determine the prescale factor.
    sbi(ADCSRA, ADPS2);
 1be:   ea e7           ldi r30, 0x7A   ; 122
 1c0:   f0 e0           ldi r31, 0x00   ; 0
 1c2:   80 81           ld  r24, Z
 1c4:   84 60           ori r24, 0x04   ; 4
 1c6:   80 83           st  Z, r24
    sbi(ADCSRA, ADPS1);
 1c8:   80 81           ld  r24, Z
 1ca:   82 60           ori r24, 0x02   ; 2
 1cc:   80 83           st  Z, r24
    sbi(ADCSRA, ADPS0);
 1ce:   80 81           ld  r24, Z
 1d0:   81 60           ori r24, 0x01   ; 1
 1d2:   80 83           st  Z, r24

    // enable a2d conversions
    sbi(ADCSRA, ADEN);
 1d4:   80 81           ld  r24, Z
 1d6:   80 68           ori r24, 0x80   ; 128
 1d8:   80 83           st  Z, r24
    // here so they can be used as normal digital i/o; they will be
    // reconnected in Serial.begin()
#if defined(UCSRB)
    UCSRB = 0;
#elif defined(UCSR0B)
    UCSR0B = 0;
 1da:   10 92 c1 00     sts 0x00C1, r1
#endif
}
 1de:   08 95           ret

000001e0 <main>:
#include <Arduino.h>

int main(void)
 1e0:   cf 93           push    r28
 1e2:   df 93           push    r29
{
    init();
 1e4:   0e 94 b5 00     call    0x16a   ; 0x16a <init>

#if defined(USBCON)
    USBDevice.attach();
#endif

    setup();
 1e8:   0e 94 53 00     call    0xa6    ; 0xa6 <setup>

    for (;;) {
        loop();
        if (serialEventRun) serialEventRun();
 1ec:   c0 e0           ldi r28, 0x00   ; 0
 1ee:   d0 e0           ldi r29, 0x00   ; 0
#endif

    setup();

    for (;;) {
        loop();
 1f0:   0e 94 54 00     call    0xa8    ; 0xa8 <loop>
        if (serialEventRun) serialEventRun();
 1f4:   20 97           sbiw    r28, 0x00   ; 0
 1f6:   e1 f3           breq    .-8         ; 0x1f0 <main+0x10>
 1f8:   0e 94 00 00     call    0   ; 0x0 <__vectors>
 1fc:   f9 cf           rjmp    .-14        ; 0x1f0 <main+0x10>

000001fe <_exit>:
 1fe:   f8 94           cli

00000200 <__stop_program>:
 200:   ff cf           rjmp    .-2         ; 0x200 <__stop_program>

Vay be, harika cevap! +1
Şapkalı Adam

1) Bu dördü sts, çağrı yükü olarak sayılmamalıdır: Bu, sonucu normalde yapmayacağınız bir değişken değişken içinde saklamanın maliyetidir. 2) Sistemimde (Arduino 1.0.5, gcc 4.8.2), bende yok movw. Daha sonra arama maliyeti millis(): 4 çağrı yükü + millis()kendi başına 15 döngü = toplam 19 döngü (MHz 16 MHz'de ≈ 1.188 µs).
Edgar Bonet

1
@EdgarBonet - Bu bir anlam ifade etmiyor, xbir uint16_t. Sebebi en fazla 2 kopya olmalıdır. Neyse, soru ne kadar uzun olduğunu millis()almak kullanıldığında sonuç görmezden denilen değilken. Herhangi bir pratik kullanım sonucu ile bir şey yapmayı içereceğinden, sonucu saklanmaya zorladım volatile. Normalde, aynı etki, çağrının dönüş değerine ayarlanan değişkenin daha sonra kullanılmasıyla elde edilebilir, ancak bu ekstra çağrının yanıtta yer kaplamasını istemedim.
Connor Wolf

Bu uint16_tkaynak (4 bayt RAM'e saklanır) montaj uymuyor. Muhtemelen iki farklı sürümün kaynağını ve sökülmesini gönderdiniz.
Edgar Bonet

@ConnorWolf Şaşırtıcı cevap ve açıklama. Teşekkür ederim!
Lefteris

8

Bir döngü yaparak değil, kopyalayıp yapıştırarak milis 1000 kez çizen bir çizim yazın. Bunu ölçün ve beklenen gerçek zamanla karşılaştırın. Sonuçların IDE'nin (ve özellikle derleyicisinin) farklı sürümlerine göre değişebileceğini unutmayın.

Başka bir seçenek, bir IO pinini milis çağrısından önce ve sonra değiştirmek, ardından çok küçük bir değer ve biraz daha büyük bir değer için zamanı ölçmektir. Ölçülen zamanlamaları karşılaştırın ve ek yükü hesaplayın.

En doğru yol, üretilen kod olan sökme listesine bir göz atmaktır. Ama bu kalbin zayıflığı için değil. Her talimat döngüsünün ne kadar sürdüğünü veri sayfasını dikkatlice incelemeniz gerekir.


1000 millis()çağrı ile geçen süreyi nasıl ölçersiniz ?
apnorton

Millis () zamanlayıcısında her bir dahili değişkeni artıran bir kesme ile sağlandığını biliyor musunuz?
TheDoctor

@Doktor ile karıştırdım delay, haklısın. Ancak fikir aynı kalır, çok sayıda çağrıyı zamanlayabilir ve ortalayabilirsiniz. Kesintileri küresel olarak kapatmak çok iyi bir fikir olmayabilir; o)
jippie

Seriye karakterler yazdırmak birkaç milisaniyeyi alırken, veri kümenizin yeterince büyük olduğundan emin olun. Tam zamanı hatırlamıyorum, ancak Seri'ye gönderilen karakter başına ~ 0.6ms gibi bir şey olduğunu düşünüyorum.
Steven10172

@ Steven10172, boş bir dizeyi 1000 kez dizeye (veya daha fazlasına) karşı zamanlayabilirsiniz, o zaman deltayı bilirsiniz ve ölçüm daha doğrudur.
jippie

3

Tekrar tekrar milis çağırıyorum ve sonra gerçek ve beklenen karşılaştırılması.

Biraz asgari yük olacak, ancak milis () adını verdiğinizde önemi azalacaktır.

Eğer bakarsan

C:\Program Files (x86)\Arduino\Arduino ERW 1.0.5\hardware\arduino\cores\arduino\wiring.c

Millis () 'in sadece 4 talimat (cli is simply # define cli() \__asm__ \__volatile__ ("cli" ::))ve dönüşte çok küçük olduğunu görebilirsiniz .

Şartlı olarak uçucu olan bir FOR döngüsü kullanarak yaklaşık 10 milyon kez derdim. Uçucu anahtar kelime, derleyicinin döngü üzerinde herhangi bir optimizasyon girişiminde bulunmasını engeller.

Aşağıdakilerin sözdizimsel olarak mükemmel olmasını garanti etmiyorum.

int temp1,temp2;
temp1=millis();
for (volatile unsigned int j=0;j<1000000;++j){
temp2=millis();}
Serial.print("Execution time = ");
Serial.print((temp2-temp1,DEC);
Serial.print("ms");

benim tahminim milis çağrısı başına ~ 900ms veya yaklaşık 56us alır. (Aruduino kullanışlı bir ATM'im yok.


1
Sen değişmelidir int temp1,temp2;için volatile int temp1,temp2;potansiyel onları uzak optimize gelen derleyici önlemek için.
Connor Wolf

Uçucuya iyi bir çağrı. Kesinlikle içine koymak ve sonra yapmadım. Daha uygun bir kıyaslama yapmanın yolunun boş bir döngü çalıştırmak, bu yürütme süresini kaydetmek, daha sonra iş yaparken döngüyü tekrar çalıştırmak olduğunu da belirtmeliydim. Farkı çıkarın, yineleme sayısına bölün ve son derece hassas yürütme süreniz vardır.
80HD

Bu tür bir kıyaslama yalnızca kod yürütmenizi hiç önermeyen bir sistemde çalışır . Arduino ortamı varsayılan olarak periyodik olarak yürütülecek periyodik kesintilere sahiptir. Daha iyi bir çözüm, her yürütmede bir pimi değiştirmek ve söz konusu kodu çalıştırıp çalıştırmama sırasında geçiş oranını ölçmek için bir tür yüksek çözünürlüklü bir zamanlayıcı kullanmak , her biri için birkaç örnek üzerinde minimum yürütme süresini almak olacaktır. , taban çizgisini çıkartın ve bunu yürütme süreniz olarak kabul edin. Yürütme sürenizin, kesintiler arasındaki minimum süreden daha kısa olduğunu varsayarsak.
Connor Wolf
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.