arduino - millis ()

10

Disalin dari referensi Arduino - millis ()

Tip : Perhatikan bahwa parameter untuk millis adalah panjang yang tidak ditandai, kesalahan dapat dihasilkan jika seorang programmer mencoba melakukan matematika dengan tipe data lain seperti int.

Matematika macam apa? Jenis pemrosesan lain apa yang dikecualikan saat bekerja dengan millis?

Bisakah seseorang mengklarifikasi pernyataan ini dan / atau memberikan contoh?

pengguna3060854
sumber

Jawaban:

8

Setiap kali Anda menulis persamaan dalam C / C ++, tipe data yang dioperasikan memiliki efek yang sangat nyata pada output persamaan.

Setiap jenis suka int,, floatdan unsigned longmemiliki perilaku yang berbeda, dan mengambil sejumlah ruang dalam memori untuk disimpan.

int (on Arduino) adalah toko dalam 16 bit, dengan setengah dari nilainya diberikan ke angka negatif, setengah-1 diberikan ke nilai positif, dan satu nilai diberikan ke 0. Yang memberikan kisaran -2 ^ 15 (-32.768) ke + 2 ^ 15-1 (32.767).

unsigned long(on Arduino) adalah 32 bit, tetapi tidak ada yang ditunjuk sebagai negatif. kisarannya adalah 0 hingga 2 ^ 32-1 (4294967295).

Matematika macam apa? Jenis pemrosesan lain apa yang dikecualikan saat bekerja dengan millis?

Inti dari masalah ini adalah bahwa waktu milis kembali pernah melewati 32767 dan Anda mencoba menyimpannya dalam sebuah int, Arduino tidak dapat melakukannya, karena seorang inttidak dapat menyimpan angka sebesar itu. Jenis matematika yang terlarang adalah matematika yang terjadi pada tipe data yang lebih kecil, bukan operasi tertentu. Mungkin contoh-contoh ini akan membantu:

  int i = 32767;
  Serial.println(i);
  //No problems here; it fits just fine

32767

  i = 32767 + 1;
  Serial.println(i);
  //Oh no, the value didn't fit

-32768

  unsigned long fake_millis = 42000;
  i = fake_millis;
  Serial.println(i);
  //This is an example of millis going past an int

-23536

  i = -10;
  unsigned int j = i;
  Serial.println(j);
  //no way to put a negative number in an unsigned value

65526

  uint32_t k = fake_millis;
  Serial.println(k);
  //unsigned long is a uint32_t on arduino; this works great!

42000

Cara ini diterapkan sangat jenius; Jika Anda tertarik dari mana angka-angka ini berasal dan mengapa angka-angka itu tumpah dengan cara mereka, Anda harus melihat penjelasan yang sama dari representasi angka pelengkap dua.

BrettAM
sumber
Hanya pertanyaan sederhana: Mendeklarasikan "unsigned long fake_millis;" sama dengan "uint_32 fake_millis;" ?
user3060854
Ya, mereka sama di Arduino. Perbedaannya adalah unsigned longdapat berubah dengan platform yang berbeda (misalnya x86), uint32_takan selalu ada 32 bit yang tidak ditandai di mana-mana.
BrettAM
1
Perlu dicatat bahwa contoh kedua Anda ( 32767 + 1) menghasilkan perilaku yang tidak terdefinisi, yang hampir selalu merupakan hal yang buruk . Contoh Anda yang lain adalah perilaku terdokumentasi yang dapat Anda andalkan.
Edgar Bonet
6

millis()mengembalikan a unsigned long, yang merupakan bilangan bulat 32-bit unsigned di Arduino. Ketika Anda kemudian mencoba untuk melakukan sesuatu seperti unsigned int time = millis() - 1000, Anda mencoba untuk menyimpannya dalam integer 16-bit unsigned unsigned int. Bilangan bulat 16-bit tidak pernah dapat menyimpan nilai 32-bit.

Menurut spesifikasi C , paragraf 6.3.1.3, 16 bit bagian atas dibuang.

Jika memungkinkan, simpan millis()output dalam a unsigned longdan hanya gunakan tipe data dengan bit lebih sedikit ketika Anda benar-benar yakin Anda tidak akan kehilangan bit.

Ada informasi lebih lanjut tentang gips eksplisit di C di sini: https://stackoverflow.com/a/13652624/1544337

Komunitas
sumber
Terima kasih atas hasil editnya. Saya menghapus referensi ke uint32_t karena itu sesuatu yang berbeda. uint32_t menjamin bahwa Anda memiliki bilangan bulat 32-bit unsigned, unsigned long tidak (walaupun pada Arduino itu). Saya juga sudah menyebutkan bahwa ini adalah tipe 32-bit.
Maka tidakkah Anda mengatakan itu lebih benar untuk mengatakan itu mengembalikan uint32_tyang kebetulan unsigned longpada arduino?
BrettAM
@ BrettAM menurut dokumen fungsi ini mengembalikan sebuah unsigned long.
Komentar lama yang dihapus, karena seluruh diskusi tidak masuk akal dengan versi jawabannya saat ini. Hanya menyimpan ini sebagai catatan: jika konversi ke integer yang ditandatangani ( int time = millis() - 1000), hasilnya sama: 16 bit atas dibuang. Kali ini standar C mengatakan bahwa hasilnya adalah implementasi-didefinisikan, dan perilaku ditentukan dalam dokumentasi gcc pada perilaku integer yang ditentukan-implementasi (titik-keempat).
Edgar Bonet
2

Ketika Anda ingin melakukan hal-hal dengan millis () ingatlah untuk menginisialisasi variabel Anda dengan tipe "uint32_t"

Jadi lakukan sesuatu seperti "uint32_t last_millis" di mana Anda akan menyimpan output dari fungsi "millis ()".

Kalau tidak seperti kata yang lain, itu akan meluap ketika melewati 31.000 yang akan terjadi dengan cukup cepat.

nemik
sumber