Apakah ada cara saya dapat membuat beberapa bagian dari program berjalan bersama tanpa melakukan banyak hal dalam blok kode yang sama?
Satu utas menunggu perangkat eksternal sambil juga berkedip LED di utas lainnya.
arduino-uno
threads
Bja
sumber
sumber
Jawaban:
Tidak ada multi-proses, atau multi-threading, dukungan di Arduino. Anda dapat melakukan sesuatu yang dekat dengan banyak utas dengan beberapa perangkat lunak.
Anda ingin melihat Protothreads :
Tentu saja, ada contoh Arduino di sini dengan kode contoh . Pertanyaan SO ini mungkin berguna juga.
ArduinoThread juga bagus.
sumber
Arduino berbasis AVR tidak mendukung threading (perangkat keras), saya tidak terbiasa dengan Arduino berbasis ARM. Salah satu cara mengatasi keterbatasan ini adalah penggunaan interupsi, terutama interupsi waktunya. Anda dapat memprogram penghitung waktu untuk menghentikan rutinitas utama setiap begitu banyak mikrodetik, untuk menjalankan rutinitas tertentu lainnya.
http://arduino.cc/en/Reference/Interrupts
sumber
Dimungkinkan untuk melakukan sisi perangkat lunak multi-threading pada Uno. Threading tingkat perangkat keras tidak didukung.
Untuk mencapai multithreading, itu akan membutuhkan implementasi penjadwal dasar dan memelihara proses atau daftar tugas untuk melacak berbagai tugas yang perlu dijalankan.
Struktur penjadwal non-preemptive yang sangat sederhana adalah seperti:
Di sini,
tasklist
bisa menjadi array fungsi pointer.Dengan masing-masing fungsi formulir:
Setiap fungsi dapat melakukan tugas terpisah seperti
function1
melakukan manipulasi LED, danfunction2
melakukan perhitungan float. Ini akan menjadi tanggung jawab setiap tugas (fungsi) untuk mematuhi waktu yang dialokasikan untuk itu.Semoga ini cukup untuk Anda mulai.
sumber
Sesuai deskripsi kebutuhan Anda:
Tampaknya Anda bisa menggunakan satu interupsi Arduino untuk "utas" pertama (saya lebih suka menyebutnya "tugas" sebenarnya).
Interupsi Arduino dapat memanggil satu fungsi (kode Anda) berdasarkan peristiwa eksternal (level tegangan atau perubahan level pada pin input digital), yang akan memicu fungsi Anda segera.
Namun, satu poin penting yang perlu diingat dengan interupsi adalah bahwa fungsi yang dipanggil harus secepat mungkin (biasanya, seharusnya tidak ada
delay()
panggilan atau API lain yang akan bergantung padadelay()
).Jika Anda memiliki tugas yang panjang untuk diaktifkan pada pemicu peristiwa eksternal, maka Anda berpotensi menggunakan penjadwal kooperatif dan menambahkan tugas baru ke sana dari fungsi interupsi Anda.
Poin penting kedua tentang interupsi adalah bahwa jumlahnya terbatas (misalnya hanya 2 pada UNO). Jadi, jika Anda mulai memiliki lebih banyak peristiwa eksternal, Anda perlu menerapkan beberapa jenis multiplexing semua input menjadi satu, dan memiliki fungsi interupsi Anda menentukan inut multiplexing apa yang merupakan pemicu yang sebenarnya.
sumber
Solusi sederhana adalah dengan menggunakan Penjadwal . Ada beberapa implementasi. Ini menjelaskan yang tersedia untuk papan berbasis AVR dan SAM. Pada dasarnya satu panggilan akan memulai tugas; + msgstr "sketsa di dalam sketsa".
Scheduler.start () akan menambahkan tugas baru yang akan menjalankan taskSetup sekali dan kemudian berulang kali memanggil taskLoop seperti sketsa Arduino bekerja. Tugas ini memiliki tumpukan sendiri. Ukuran tumpukan adalah parameter opsional. Ukuran tumpukan standar adalah 128 byte.
Untuk memungkinkan pengalihan konteks tugas perlu memanggil yield () atau delay () . Ada juga makro dukungan untuk menunggu suatu kondisi.
Makro adalah gula sintaksis untuk yang berikut:
Menunggu juga dapat digunakan untuk menyinkronkan tugas. Di bawah ini adalah contoh cuplikan:
Untuk perincian lebih lanjut, lihat contoh - contohnya . Ada beberapa contoh dari beberapa LED berkedip ke tombol debounce dan shell sederhana dengan baris perintah non-blocking terbaca. Templat dan ruang nama dapat digunakan untuk membantu menyusun dan mengurangi kode sumber. Sketsa di bawah ini menunjukkan cara menggunakan fungsi templat untuk multi-kedip. Cukup dengan 64 byte untuk stack.
Ada juga tolok ukur untuk memberikan beberapa gagasan tentang kinerja, yaitu waktu untuk memulai tugas, pengalihan konteks, dll.
Terakhir, ada beberapa kelas pendukung untuk sinkronisasi dan komunikasi tingkat tugas; Antrian dan Semaphore .
sumber
Dari mantra sebelumnya dari forum ini, pertanyaan / jawaban berikut dipindahkan ke Teknik Elektro. Ini memiliki kode arduino sampel untuk berkedip LED menggunakan penghenti waktu saat menggunakan loop utama untuk melakukan serial IO.
https://electronics.stackexchange.com/questions/67089/how-can-i-control-things-without-using-delay/67091#67091
Repost:
Interupsi adalah cara umum untuk menyelesaikan sesuatu saat sesuatu yang lain sedang terjadi. Pada contoh di bawah ini, LED berkedip tanpa menggunakan
delay()
. Setiap kaliTimer1
kebakaran, interrupt service routine (ISR)isrBlinker()
dipanggil. Mengaktifkan / menonaktifkan LED.Untuk menunjukkan bahwa hal-hal lain dapat terjadi secara bersamaan,
loop()
berulang kali tulis foo / bar ke port serial yang tidak tergantung pada LED yang berkedip.Ini adalah demo yang sangat sederhana. ISR dapat menjadi jauh lebih kompleks dan dapat dipicu oleh timer dan peristiwa eksternal (pin). Banyak perpustakaan umum diimplementasikan menggunakan ISR.
sumber
Saya juga membahas topik ini sambil menerapkan tampilan LED matriks.
Dalam satu kata, Anda dapat membuat penjadwal pemungutan suara dengan menggunakan fungsi millis () dan penghenti waktu di Arduino.
Saya menyarankan artikel-artikel berikut dari Bill Earl:
https://learn.adafruit.com/multi-tasking-the-arduino-part-1/overview
https://learn.adafruit.com/multi-tasking-the-arduino-part-2/overview
https://learn.adafruit.com/multi-tasking-the-arduino-part-3/overview
sumber
Anda juga bisa mencoba pustaka ThreadHandler saya
https://bitbucket.org/adamb3_14/threadhandler/src/master/
Ini menggunakan penjadwal mengganggu untuk memungkinkan pengalihan konteks tanpa menyampaikan hasil () atau menunda ().
Saya membuat perpustakaan karena saya membutuhkan tiga utas dan saya membutuhkan dua utas untuk berjalan pada waktu yang tepat tidak peduli apa yang sedang dilakukan. Utas pertama menangani komunikasi serial. Yang kedua adalah menjalankan filter Kalman menggunakan perkalian matriks float dengan perpustakaan Eigen. Dan yang ketiga adalah thread loop kontrol arus cepat yang harus dapat mengganggu perhitungan matriks.
Bagaimana itu bekerja
Setiap utas siklik memiliki prioritas dan titik. Jika utas, dengan prioritas lebih tinggi dari utas yang saat ini dijalankan, mencapai waktu eksekusi berikutnya, penjadwal akan menjeda utas saat ini dan beralih ke utas yang lebih tinggi. Setelah utas prioritas tinggi menyelesaikan eksekusi, penjadwal beralih kembali ke utas sebelumnya.
Aturan penjadwalan
Skema penjadwalan perpustakaan ThreadHandler adalah sebagai berikut:
Cara Penggunaan
Utas dapat dibuat melalui c ++ inheritance
Atau via createThread dan fungsi lambda
Objek utas secara otomatis terhubung ke ThreadHandler saat dibuat.
Untuk memulai eksekusi dari objek objek panggilan:
sumber
Dan inilah perpustakaan multitasking koperasi mikroprosesor lain - PQRST: Antrian Prioritas untuk Menjalankan Tugas Sederhana.
Dalam model ini, utas diimplementasikan sebagai subkelas dari a
Task
, yang dijadwalkan untuk beberapa waktu mendatang (dan mungkin dijadwal ulang secara berkala, jika, seperti biasa, ia mensubklasifikasikanLoopTask
sebagai gantinya). Therun()
metode objek disebut ketika tugas menjadi jatuh tempo. Therun()
Metode melakukan beberapa pekerjaan karena, dan kemudian kembali (ini adalah sedikit koperasi); itu biasanya akan memelihara semacam mesin negara untuk mengelola aksinya pada pemanggilan yang berurutan (contoh yang sepele adalahlight_on_p_
variabel dalam contoh di bawah). Ini membutuhkan sedikit pemikiran ulang tentang bagaimana Anda mengatur kode Anda, tetapi telah terbukti sangat fleksibel dan kuat dalam penggunaan yang cukup intensif.Agnostik tentang unit waktu, jadi sama senangnya berjalan di unit
millis()
sepertimicros()
, atau centang lainnya yang nyaman.Berikut adalah program 'blink' yang diimplementasikan menggunakan perpustakaan ini. Ini hanya menampilkan satu tugas berjalan: tugas lain biasanya akan dibuat, dan mulai di dalam
setup()
.sumber
run()
metode dipanggil, tidak terputus, sehingga memiliki tanggung jawab untuk menyelesaikannya dengan cepat. Namun, biasanya, ia akan melakukan tugasnya kemudian menjadwal ulang sendiri (mungkin secara otomatis, dalam kasus subkelasLoopTask
) untuk beberapa waktu mendatang. Pola umum adalah untuk tugas untuk mempertahankan beberapa mesin keadaan internal (contoh sepele adalahlight_on_p_
keadaan di atas) sehingga berperilaku yang sesuai ketika jatuh tempo berikutnya.run()
. Ini berbeda dengan utas kooperatif, yang dapat menghasilkan CPU dengan, misalnya, meneleponyield()
ataudelay()
. Atau utas preemptive, yang dapat dijadwalkan keluar kapan saja. Saya merasa perbedaan itu penting, karena saya telah melihat bahwa banyak orang yang datang ke sini mencari utas melakukannya karena mereka lebih suka menulis kode pemblokiran daripada mesin negara. Memblokir utas nyata yang menghasilkan CPU baik-baik saja. Memblokir tugas RtC tidak.