Jawaban lainnya sangat bagus, tetapi saya ingin menguraikan cara micros()
kerjanya. Ini selalu membaca timer hardware saat ini (mungkin TCNT0
) yang terus-menerus diperbarui oleh perangkat keras (pada kenyataannya, setiap 4 mikrodetik karena prescaler dari 64). Ini kemudian menambahkan penghitung limpahan Timer 0, yang diperbarui oleh penghentian overflow timer (dikalikan dengan 256).
Dengan demikian, bahkan di dalam ISR, Anda dapat mengandalkan micros()
pembaruan. Namun jika Anda menunggu terlalu lama maka Anda melewatkan pembaruan melimpah, dan kemudian hasilnya dikembalikan akan turun (yaitu Anda akan mendapatkan 253, 254, 255, 0, 1, 2, 3 dll.)
Ini micros()
- sedikit disederhanakan untuk menghapus definisi untuk prosesor lain:
unsigned long micros() {
unsigned long m;
uint8_t oldSREG = SREG, t;
cli();
m = timer0_overflow_count;
t = TCNT0;
if ((TIFR0 & _BV(TOV0)) && (t < 255))
m++;
SREG = oldSREG;
return ((m << 8) + t) * (64 / clockCyclesPerMicrosecond());
}
Kode di atas memungkinkan untuk overflow (memeriksa bit TOV0) sehingga dapat mengatasi overflow sementara interupsi mati tetapi hanya sekali - tidak ada ketentuan untuk menangani dua overflow.
TLDR;
- Jangan lakukan penundaan di dalam ISR
- Jika Anda harus melakukannya, Anda dapat menggunakan waktu
micros()
tetapi tidak millis()
. Juga delayMicroseconds()
kemungkinan.
- Jangan tunda lebih dari 500 µs atau lebih, atau Anda akan melewatkan waktu yang berlebihan.
- Bahkan penundaan singkat dapat menyebabkan Anda kehilangan data serial yang masuk (pada 115200 baud Anda akan mendapatkan karakter baru setiap 87 μs).
micros()
bukan ISR. Ini adalah fungsi normal. Bendera TOV0 memungkinkan Anda menguji perangkat keras untuk melihat apakah pelimpah waktu telah terjadi (tetapi belum diproses).Tidak salah menggunakan
millis()
ataumicros()
dalam rutinitas interupsi.Ini adalah salah untuk menggunakannya secara tidak benar.
Hal utama di sini adalah saat Anda berada dalam rutinitas interupsi "jam tidak berdetak".
millis()
danmicros()
tidak akan berubah (well,micros()
awalnya akan, tetapi begitu melewati titik milidetik ajaib di mana centang milidetik diperlukan, semuanya akan berantakan.)Jadi Anda tentu dapat menelepon
millis()
ataumicros()
mencari tahu waktu saat ini dalam ISR Anda, tetapi jangan berharap waktu itu berubah.Adalah kurangnya perubahan waktu yang diperingatkan dalam kutipan yang Anda berikan.
delay()
mengandalkanmillis()
perubahan untuk mengetahui berapa banyak waktu yang telah berlalu. Karena itu tidak berubahdelay()
tidak pernah bisa selesai.Jadi intinya
millis()
danmicros()
akan memberi tahu Anda saat ISR Anda dipanggil, tidak masalah ketika di ISR Anda menggunakannya.sumber
micros()
pembaruan. Selalu membaca register pengatur waktu perangkat keras.Ungkapan yang dikutip bukanlah peringatan, itu hanya pernyataan tentang bagaimana segala sesuatu bekerja.
Secara intrinsik tidak ada yang salah dengan menggunakan
millis()
ataumicros()
dalam rutinitas interupsi yang ditulis dengan benar.Di sisi lain, melakukan apa saja dalam rutinitas interupsi yang ditulis dengan tidak benar secara definisi salah.
Rutin interupsi yang membutuhkan lebih dari beberapa mikrodetik untuk melakukan tugasnya, kemungkinan besar, ditulis secara tidak benar.
Singkatnya: Rutin interupsi yang ditulis dengan benar tidak akan menyebabkan atau menghadapi masalah dengan
millis()
ataumicros()
.Sunting: Mengenai "mengapa micros ()" mulai berperilaku tidak menentu "", seperti yang dijelaskan dalam laman " pemeriksaan fungsi mikro Arduino ",
micros()
kode pada Uno biasa secara fungsional setara denganIni mengembalikan empat byte unsigned long yang terdiri dari tiga byte terendah dari
timer0_overflow_count
dan satu byte dari register penghitung timer-0.Ini
timer0_overflow_count
bertambah sekitar satu kali per milidetik olehTIMER0_OVF_vect
interrupt handler, seperti yang dijelaskan dalam pemeriksaan halaman web fungsi arduino millis .Sebelum pengendali interupsi dimulai, perangkat keras AVR menonaktifkan interupsi. Jika (misalnya) interrupt handler dijalankan selama lima milidetik dengan interupsi masih dinonaktifkan, setidaknya empat timer 0 overflow akan terlewatkan. [Interupsi yang ditulis dalam kode C dalam sistem Arduino bukan reentrant (mampu menangani dengan benar beberapa eksekusi yang tumpang tindih dalam handler yang sama) tetapi orang dapat menulis handler bahasa assembly reentrant yang mengaktifkan kembali interupsi sebelum memulai proses yang memakan waktu.]
Dengan kata lain, kelebihan waktu tidak "menumpuk"; setiap kali overflow terjadi sebelum interupsi dari overflow sebelumnya telah ditangani,
millis()
penghitung kehilangan milidetik, dan perbedaantimer0_overflow_count
pada gilirannya membuatmicros()
kesalahan dengan milidetik juga.Mengenai "lebih pendek dari 500 μs" sebagai batas waktu atas untuk pemrosesan interupsi, "untuk mencegah pemblokiran timer terlalu lama", Anda bisa naik hingga di bawah 1024 μs (misalnya 1020 μs) dan
millis()
masih akan berfungsi, sebagian besar waktu. Namun, saya menganggap interrupt handler yang mengambil lebih dari 5 μs sebagai sluggard, lebih dari 10 μs sebagai slothful, lebih dari 20 μs sebagai seperti siput.sumber
micros()
"mulai berperilaku tidak menentu"? Dan apa yang Anda maksud dengan "rutin interupsi yang ditulis dengan benar"? Saya berasumsi itu berarti "lebih pendek dari 500us" (untuk mencegah pemblokiran penghitung waktu terlalu lama), "menggunakan variabel volatil untuk komunikasi" dan "tidak memanggil kode perpustakaan" sebanyak mungkin, apakah ada hal lain?