Melalui proyek lama, saya memiliki kode pada dua Arduino Due yang terlihat seperti ini
void loop()
{
foo();
delay(time);
}
mengambil hati sebagian dari literatur menggunakan delay();
saya recoded ini sebagai
void loop()
{
static unsigned long PrevTime;
if(millis()-PrevTime>time)
{
foo();
PrevTime=millis();
}
}
Namun, ini tampaknya telah menciptakan situasi di mana kedua perangkat melayang selama periode waktu yang sebelumnya tidak
Pertanyaan saya ada dua:
- Mengapa
if(millis()-PrevTime>time)
menyebabkan lebih banyak penyimpangan daripadadelay(time)
? - Apakah ada cara untuk mencegah penyimpangan ini tanpa kembali ke
delay(time)
?
arduino-due
code-review
timing
ATE-ENGE
sumber
sumber
foo; delay;
) memiliki periode lebih lama dari 100ms (100ms + waktufoo
). Jadi Anda akan mengalami drift (tetapidelay
SW yang diimplementasikan adalah drifting). Dalam kasus apa pun, perlu diingat bahwa implementasi yang sama sempurna sekalipun "melayang", karena jam tidak sama; jika Anda membutuhkan sinkronisasi lengkap gunakan sinyal untuk, yah, sinkronkan kedua program.Jawaban:
Ada satu hal penting yang perlu Anda ingat ketika bekerja dengan waktu pada Arudino dalam bentuk apa pun:
Fungsi foo () Anda akan membutuhkan waktu. Apa waktu itu, kita tidak bisa mengatakan.
Cara yang paling dapat diandalkan untuk menangani waktu adalah dengan hanya mengandalkan waktu untuk memicu, bukan untuk berolahraga ketika pemicu berikutnya seharusnya.
Misalnya, ambil yang berikut ini:
Variabelnya
last
adalah waktu yang dipicu oleh rutin * ditambah waktu yangdoSomething
diperlukan untuk menjalankan. Jadi katakanlahinterval
100, dandoSomething
butuh 10ms untuk dijalankan, Anda akan mendapatkan pemicu pada 101ms, 212ms, 323ms, dll. Bukan 100ms yang Anda harapkan.Jadi satu hal yang dapat Anda lakukan adalah selalu menggunakan waktu yang sama tanpa menghiraukannya pada saat yang sama (seperti yang Juraj sarankan):
Sekarang waktu yang
doSomething()
diperlukan tidak akan berpengaruh apa pun. Jadi Anda akan mendapatkan pemicu pada 101ms, 202ms, 303ms, dll. Masih tidak cukup 100ms yang Anda inginkan - karena Anda mencari lebih dari 100ms yang telah berlalu - dan itu berarti 101ms atau lebih. Sebaliknya, Anda harus menggunakan>=
:Sekarang, dengan asumsi bahwa tidak ada hal lain yang terjadi di loop Anda, Anda mendapatkan pemicu pada 100ms, 200ms, 300ms, dll. Tetapi perhatikan bahwa bit: "selama tidak ada yang lain terjadi di loop Anda" ...
Apa yang terjadi jika operasi yang membutuhkan waktu 5 ms terjadi pada 99ms ...? Pemicuan Anda berikutnya akan ditunda hingga 104 ms. Itu sebuah penyimpangan. Tapi mudah untuk bertarung. Alih-alih mengatakan "Waktu yang direkam sekarang" Anda mengatakan "Waktu yang direkam 100ms lebih lambat dari itu". Itu berarti bahwa tidak peduli apa pun keterlambatan yang Anda dapatkan dalam kode Anda, pemicu Anda akan selalu berada pada interval 100 ms, atau melayang dalam centang 100 ms.
Sekarang Anda akan mendapatkan pemicu pada 100ms, 200ms, 300ms, dll. Atau jika ada keterlambatan dalam bit kode lain Anda mungkin mendapatkan 100ms, 204ms, 300ms, 408ms, 503ms, 600ms, dll. Selalu mencoba untuk menjalankannya sedekat mungkin dengan Interval mungkin terlepas dari penundaan. Dan jika Anda memiliki penundaan yang lebih besar dari interval itu, maka secara otomatis akan menjalankan rutinitas Anda cukup untuk mengejar waktu saat ini.
Sebelum Anda tertidur . Sekarang Anda memiliki jitter .
sumber
Karena Anda mengatur ulang timer setelah operasi.
sumber
Untuk apa yang Anda coba lakukan, delay () adalah cara yang tepat untuk mengimplementasikan kode. Alasan Anda ingin menggunakan if (millis ()) adalah jika Anda ingin mengizinkan loop utama untuk terus loop sehingga kode Anda atau kode lain di luar loop itu dapat melakukan pemrosesan lainnya.
Sebagai contoh:
Ini akan menjalankan foo () pada interval yang ditentukan sambil membiarkan loop terus berjalan di antaranya. Saya meletakkan perhitungan next_trigger_time sebelum panggilan ke foo () untuk membantu meminimalkan penyimpangan, tetapi itu tidak bisa dihindari. Jika penyimpangan merupakan masalah yang signifikan, gunakan penghenti waktu atau semacam sinkronisasi jam / penghitung waktu. Juga ingat bahwa millis () akan membungkus setelah beberapa periode waktu dan saya tidak memperhitungkan itu untuk menjaga contoh kode sederhana.
sumber
long m - millis()
tidak melakukan apa yang ingin Anda lakukan? Itu di rumah.kode Anda benar.
masalah yang Anda hadapi adalah dengan millis (): itu akan sedikit di bawah hitungan (under-count maksimum hanya sedikit 1ms, per doa).
solusinya adalah dengan kutu yang lebih baik, seperti micros () - tetapi itu juga akan sedikit di bawah hitungan.
sumber