Soru:
Arduino Uno'da iki döngüyü aynı anda nasıl çalıştırabilirim?
Daniel T.
2014-09-29 02:54:06 UTC
view on stackexchange narkive permalink

Arduino'da yeniyim ve kontrol etmeye çalıştığım iki cihazım var:

  1. Renkleri değiştirebilen bir RGB LED ışık şeridi
  2. Işık ortam ışığı seviyesini algılayabilen sensör

Yapmak istediğim şey, LED şeridin bir gökkuşağı renkleri arasında sürekli olarak dönmesini sağlamaktır ve ışık sensörü LED'in parlaklığını ayarlar ortam ışık seviyesine göre şerit. İşte kendi başlarına test ettiğim ve düzgün çalıştıklarını doğruladığım iki kod parçası:

LED şerit:

  j = (j + 1 )% 256; // ışık döngüsünün geçerli yinelemesi // şerit rengini ayarlayın (int i = 0; i< strip.numPixels (); i ++) {strip.setPixelColor (i, Wheel (((i * 256 / strip.numPixels ()) + j) & 255));} // yeni renkleri göster ve sonraki cyclestrip.show (); delay (20);  

Işık sensörü:

  sensörler_event_t olayı; tsl.getEvent (&event); // bir ışık ölçüm şeridi alın.setBrightness (event.light); // LED şeridin parlaklığını ayarlayın  

Sorun, ışık sensörünün 100 ms ile 600 ms arasında bir okuma alması ve tsl.getEvent (&event) kod> bloke edici bir çağrıdır, bu nedenle sonuç, LED şeridinin çok yavaş güncellenmesidir. Işık sensörünün LED şerit güncellemesini engellememesi için ikisini yan yana çalıştırmam gerekir. Bunu nasıl başaracağım hakkında bir fikriniz var mı?

"tsl" hangi kütüphaneden geliyor?
100 ila 600 ms aşırıdır. Analog girişe bağlı bir LDR için mi?
@BrettM Sanırım TSL2561 I2C ışık sensörünü kullanıyor.
Altı yanıtlar:
Gerben
2014-09-29 18:02:07 UTC
view on stackexchange narkive permalink

Doğruluğunu düşürerek sensörün verileri daha hızlı döndürmesini sağlayabilirsiniz.

  tsl.setIntegrationTime (TSL2561_INTEGRATIONTIME_13MS); / * hızlı ancak düşük çözünürlüklü * /  

Kitaplığı, her okumadan sonra sensörün gücünü kapatmayacak şekilde de değiştirebilirsiniz. TSL2561.cpp 'yi açın, getFullLuminosity işlevini bulun ve disable (); okuyan satırı ve okuyan 12 satırı yorumlayın switch (_integration) {...}

Başka bir çözüm de piksellerin zamanlayıcı kullanarak her 20 ms'de bir güncellenmesini sağlamaktır. Zamanlayıcıya sahip olabilir, ana döngüyü her 20 ms'de bir kesebilir ve piksel değerlerini güncelleyebilirsiniz.

(Zamanlayıcılarım için kayıtları ve doğrudan ISR'leri kendim belirlediğim için zamanlayıcılar konusunda size gerçekten yardımcı olamam, ki bu yeni başlayanlar için değil. Ancak muhtemelen bunun için kitaplıklar var. daha kullanıcı dostu.)

http://playground.arduino.cc/code/timer1 bu kitaplık, zamanlayıcıları kolaylaştırmaya yardımcı olmalıdır
Tsl2561'i her zaman açık bırakarak herhangi bir gecikme ihtiyacını reddetmek için yukarıdaki düzenlememe bakın.
Duncan C
2014-09-29 04:42:33 UTC
view on stackexchange narkive permalink

Arduino, çok iş parçacıklı veya çok görevli bir cihaz değildir. Birbirinizle "iyi oynamak" için farklı işlevlerinizi yazmalısınız. Kodun engellenmesi, bu tür çoklu görevler için ölümdür. Engelleyici olmaması için ışık sensörünü okuyan kodunuzu yeniden yazmanız gerekebilir.

Bu kodun engellenmemesini sağlayabilirseniz, Visual Micro'nun gönderisi en iyi yoldur.

Visual Micro
2014-09-29 04:30:45 UTC
view on stackexchange narkive permalink

Döngünüzde () bir 'durum sunucusu' kurun. Basitçe ifade etmek gerekirse bu, her görev için bir sonraki komutu takip etmek, ardından döngü başına her görevde bir şey yapmak anlamına gelir ().

Bir görevin diğerinden daha hızlı çalışması gerekiyorsa, Daha sonra ne yapılacağına karar vermek için döngünüzde zamanlayıcı.

Bir görevin duraklaması gerekiyorsa, "Son Çalıştırma" milis () değerini global bir değişkene kaydedin ve doğru süre geçene kadar görevi göz ardı edin . Bir delay () kullanmayın, her zaman loop () çalışmasına izin verin.

Buradaki fikir, loop () 'un olabildiğince sık çalışması, ancak her çalıştığında bir şey yapmanızdır.

Bu şekilde çalışmak biraz zaman alır, ancak Arduino işlemcisini tüm işleri eşit şekilde işlemesi için serbest bırakır.

  int task1Status = 0; int task2Status = 0; void döngü () {doOneThingOfTask1 (); doOneThingOfTask2 ();} // Ledleri yakmak için 10 şey var, ancak sadece tek bir boşuna doOneThingOfTask1 () {if (task1Status == 10) task1Status = 0; switch (task1Status) {case 0: // yeni bir işlem yapmaya başla case 1: // bir şeyler yap case 9: // son şeyi yap}}  
Benzer bir şey yayınlayacaktım, sonra OP'nin ışık ölçümleri almak için kodun kodu bloke ettiğini söylediğini fark ettim.
@Duncan C Oh! İyi bir nokta. Cevabı bırakacağım çünkü kodun başka bir yerinde aynı sorunu ortadan kaldıran bir çalışma yolunu tanımladığını düşünüyorum. Ayrıca getEvent () için kütüphane çağrısını inceleyerek, gecikmeyi azaltmak için aynı çözüm uygulanabilir. Açıkçası bu, kitaplık kodunu değiştirmek anlamına gelir, ancak kitaplığı eskiz klasörüne kopyalayabilir ve yerel kaynak olarak hackleyebilir. bir Lib değişikliği kesinlikle yardımcı olacaktır, ancak yerel kaynak ve küçük bir bilgisayar korsanlığı bir çözüm üretebilir. Teşekkürler :)
JRobert
2014-09-29 22:10:02 UTC
view on stackexchange narkive permalink

İlk, en büyük sorununuz

ışık sensörünün okuma yapması 100 ms'den 600 ms'ye kadar her yerde ve tsl.getEvent (&event) ise engelleyen bir çağrı,

Işık sensörüne engelsiz erişime ihtiyacınız var. Bloklandığında ne yaptığını görmek için kütüphane koduna bakın. Muhtemelen sensörün 'tamamlandı' biti ayarlamasını bekler. Öyleyse, kitaplığı

  1. biti test eden bir boolean .isDone () işlevi ekleyerek değiştirmeniz gerekir ve izin vermeyin ana programınız isDone () == TRUE olana kadar bir okuma çağrısı yapar; veya
  2. .getEvent () 'i, sensör henüz hazır değilse engelleme yerine hemen bariz bir şekilde geçersiz bir okuma (-1 gibi) döndürecek şekilde bir engelleme dışı yapmak.
  3. ol>

    Bu, ana programınızın yapması gereken her şeyi hizmete sunmasını sağlar ve yavaş sensör için her şeyi bekletmeden yapmaya hazır hale gelir.

ForestPhoenix
2014-10-24 18:46:08 UTC
view on stackexchange narkive permalink

Çoklu göreve izin veren kitaplıklar var, örneğin kitaplığım arduOS.

Bu işe yaramalı:

  #include <arduos16.h> # dahil <arduos_core.h> # include <roundscheduler.h>SYS_enable_preemptive; // bunu UNUTMAYIN !!! void setup () {auto sched = new SYS :: RoundScheduler (2); sched->add (&loop1); // bu 2 işlevdir. sched->add (&loop2); SYS :: start ();}  

Ancak, gerçek çoklu görev yapmanın çok belirsiz hatalarla oldukça zor olabileceğini unutmayın. (ama onları bulabilirsiniz).

Bu işletim sistemi, ortalama arduino işletim sisteminizden daha kolay görünüyor
lxx
2015-01-01 13:34:27 UTC
view on stackexchange narkive permalink

1. İki arduino kullanın ve birbirleriyle seri veya i2c yoluyla konuşmalarını sağlayın. Muhtemelen en basit seçenek (ama en ucuzu değil - yine de klon arduino'ları 4 dolardan alabilirsiniz).

2. Daha hızlı güncellenen bir ışık sensörü bulun. Bir ldr (ışığa bağlı direnç) / fotosel denediniz mi? O zaman analog okuma kullanabilir.

Arduino'dan c'ye de geçebilirsiniz, ancak bu çok daha fazla iş ve yine de benzer problemlerle karşılaşacaksınız.

C'ye geçmek bu sorun için gerçekten hiçbir şey yapmaz.


Bu Soru-Cevap, otomatik olarak İngilizce dilinden çevrilmiştir.Orijinal içerik, dağıtıldığı cc by-sa 3.0 lisansı için teşekkür ettiğimiz stackexchange'ta mevcuttur.
Loading...