Arduino: Slave cihazların SPI veriyoluna paralel ve seri bağlantısı. "delay()" ifadesi olmadan İşleme Paralel işlemleriyle ilişkilendirme

Arduino: Slave cihazların SPI veriyoluna paralel ve seri bağlantısı.  Operatör olmadan İşleme Paralel süreçlerle iletişim kurma
Arduino: Slave cihazların SPI veriyoluna paralel ve seri bağlantısı. "delay()" ifadesi olmadan İşleme Paralel işlemleriyle ilişkilendirme

Bu programı yükledikten sonra, Arduino IDE'ye ne kadar benzediğine şaşıracaksınız. Şaşırmayın, her iki program da aynı motorda yapılır.

Uygulama, bir kitaplık da dahil olmak üzere birçok özelliğe sahiptir. Seri, böylece pano ile arasındaki veri transferini bağlayabiliriz.

Arduino IDE'yi başlatın ve seçin en basit örnek veri çıkışı Seri port:

void setup() ( Serial.begin(9600); ) void loop() ( Serial.println("Hello Kitty!"); // tekrar göndermeden önce 500 milisaniye bekleyin delay(500); )

Örneği çalıştıralım ve kodun çalıştığından emin olalım.

Veri alma

Şimdi aynı metni . Yeni bir projeye başlıyoruz ve kodu yazıyoruz.

İlk adım, kitaplığı içe aktarmaktır. Hadi gidelim eskiz | Kitaplığı İçe Aktar | Seri. Çizgi çizimde görünecektir:

process.serial.* dosyasını içe aktarın; Seri seri; // bir seri port nesnesi yarat String alındı; // seri porttan alınan veriler void setup() ( String port = Serial.list(); serial = new Serial(this, port, 9600); ) void draw() ( if (serial.available() > 0) ( // eğer veri varsa, Received = serial.readStringUntil("\n"); // data oku ) println(required); //verileri konsolda göster )

Verilerin seri bağlantı noktasından alındığından emin olmak için, sınıfın bir nesnesine ihtiyacımız var. Seri. Arduino'dan String verileri gönderdiğimiz için, String'i Processing'de de almamız gerekiyor.

yöntemde kurmak() müsait olmak lazım seri port. Genellikle bu, listedeki ilk kullanılabilir bağlantı noktasıdır. Bundan sonra nesneyi ayarlayabiliriz Seri, bağlantı noktasını ve veri aktarım hızını belirtir (oranların eşleşmesi arzu edilir).

Geriye kartı tekrar bağlamak, İşleme'den taslağı çalıştırmak ve gelen verileri uygulama konsolunda gözlemlemek kalır.

İşleme, yalnızca konsolla çalışmanıza değil, aynı zamanda standart pencereler oluşturmanıza da olanak tanır. Kodu yeniden yazalım.

process.serial.* dosyasını içe aktarın; Seri seri; // bir seri port nesnesi yarat String alındı; // seri porttan alınan veriler void setup() ( size(320, 120); String port = Serial.list(); serial = new Serial(this, port, 9600); ) void draw() ( if (serial.available() > 0) ( // eğer veri varsa, // okuyun ve alınan değişkene yazın accept = serial.readStringUntil("\n"); ) // Metin için ayarlar textSize(24); clear(); if (alındı ​​! = boş) ( metin(alındı, 10, 30); ) )

Örneği tekrar çalıştıralım ve tek bir yerde yeniden çizilmiş yazıtlı bir pencere görelim.

Böylece Arduino'dan veri almayı öğrenmiş olduk. Bu, güzel grafikler çizmemize veya sensör okumalarını izlemek için programlar oluşturmamıza izin verecektir.

veri gönderme

Panodan sadece veri alamıyoruz, aynı zamanda panoya veri göndererek bizi bilgisayardan komutları yürütmeye zorluyoruz.

Processing'den "1" karakterini gönderdiğimizi varsayalım. Kart gönderilen karakteri algıladığında, port 13'teki (yerleşik) LED'i açın.

Eskiz öncekine benzer olacaktır. Örneğin küçük bir pencere oluşturalım. Pencere alanına tıkladığımızda "1" göndereceğiz ve bunu doğrulama için konsolda çoğaltacağız. Tıklama yoksa "0" komutu gönderilir.

process.serial.* dosyasını içe aktarın; Seri seri; // bir seri port nesnesi yarat String alındı; // seri porttan alınan veriler void setup() ( size(320, 120); String port = Serial.list(); serial = new Serial(this, port, 9600); ) void draw() ( if (mousePressed == true) ( ​​//eğer pencere içinde tıklarsak serial.write("1"); //1 gönder println("1"); ) else ( //tıklama yoksa serial.write("0"); //gönder) 0 ) )

Şimdi Arduino için bir eskiz yazalım.

Karakter komutuDeğeri; // seri porttan gelen data int ledPin = 13; // yerleşik LED geçersiz kurulum() ( pinMode(ledPin, OUTPUT); // veri çıkış modu Serial.begin(9600); ) geçersiz döngü() ( if (Serial.available()) ( commandValue = Serial.read(); ) if (commandValue == "1") ( digitalWrite(ledPin, HIGH); // LED'i aç ) else ( digitalWrite(ledPin, LOW); // aksi halde kapat) delay(10); // bir sonraki veri okumadan önceki gecikme)

Her iki taslağı da çalıştıralım. Pencerenin içine tıklıyoruz ve LED'in yandığını görüyoruz. Tıklayamazsınız, ancak fare düğmesini basılı tutabilirsiniz - LED sürekli yanacaktır.

Veri değişimi

Şimdi her iki yaklaşımı birleştirmeyi deneyelim ve pano ile uygulama arasında iki yönde mesaj alışverişi yapalım.

İçin maksimum verimlilik bir boole değişkeni ekleyin. Sonuç olarak artık Processing'den sürekli olarak 1 veya 0 göndermemize gerek kalmıyor ve seri port boşalmış oluyor ve gereksiz bilgi iletmiyor.

Kart gönderilen birimi algıladığında, boole değerini mevcut duruma göre tersine değiştiririz ( DÜŞÜK Açık YÜKSEK ve tersi). İÇİNDE başka sadece "1" bulamazsak göndereceğimiz "Hello Kity" dizesini kullanırız.

İşlev iletişim kurmak()İşleme'de almayı beklediğimiz diziyi gönderir. Cevap gelirse, İşleme verileri alabilir.

Karakter komutuDeğeri; // seri porttan gelen data int ledPin = 13; boolean ledState = DÜŞÜK; //LED'in durumunu kontrol edin void setup() ( pinMode(ledPin, OUTPUT); Serial.begin(9600); kurmakContact(); // alıcı yanıt verirken kontağa bir bayt gönderin) void loop() ( // eğer veriler okunabiliyorsa (Serial.available() > 0) ( // verileri oku commandValue = Serial.read(); if (commandValue == "1") ( ledState = !ledState; digital Write(ledPin, ledState); ) delay(100); ) else ( // Geri gönder Serial.println("Hello Kitty"); ) delay(50); ) geçersiz tesisContact() ( iken (Serial.available()<= 0) { Serial.println("A"); // отсылает заглавную A delay(300); } }

İşleme taslağına geçelim. yöntemini kullanacağız seriOlay(), arabellekte belirli bir karakter bulunduğunda çağrılacak.

Yeni bir boole değişkeni ekleyin ilk temas, Arduino ile bir bağlantı olup olmadığını belirlemenizi sağlar.

yöntemde kurmak() satır ekle serial.bufferUntil("\n");. Bu, belirli bir karakter bulana kadar gelen verileri bir arabellekte saklamamızı sağlar. Bu durumda gönderdiğimiz için (\n) döndürürüz. Serial.println() Arduino'dan. "\N" sonunda, yeni bir satırı etkinleştireceğimiz anlamına gelir, yani bu, göreceğimiz son veriler olacaktır.

Sürekli veri gönderdiğimiz için, yöntem seriOlay() döngü görevlerini gerçekleştirir çizmek(), boş bırakabilirsiniz.

Şimdi ana yöntemi düşünün seriOlay(). Her yeni satıra (\n) girdiğimizde bu metod çağrılır. Ve her seferinde aşağıdaki eylem dizisi gerçekleştirilir:

  • Gelen veriler okunur;
  • Herhangi bir değer içerip içermedikleri kontrol edilir (yani bize boş bir veri dizisi veya "null" geçirilip geçirilmediği);
  • Boşlukları kaldırmak;
  • İlk defa gerekli verileri aldıysak boolean değişkeninin değerini değiştiriyoruz. ilk temas ve Arduino'ya yeni veriler almaya hazır olduğumuzu söyleyin;
  • Bu, gerekli veri türünün ilk alımı değilse, bunları konsolda görüntüler ve yapılan tıklama ile ilgili verileri mikrodenetleyiciye göndeririz;
  • Arduino'ya yeni bir veri paketi almaya hazır olduğumuzu söylüyoruz.
içe aktarma işleme.serial.*; Seri seri; // bir seri port nesnesi yarat String alındı; // seri porttan alınan veriler // Arduino'dan gelen verileri kontrol edin boolean firstContact = false; void setup() ( size(320, 120); String port = Serial.list(); serial = new Serial(this, port, 9600); serial.bufferUntil("\n"); ) void draw() ( ) void serialEvent(Serial myPort) ( // gelen verilerden bir dizi oluşturma // "\n" - ayırıcı - alınan veri paketinin sonu = myPort.readStringUntil("\n"); //emin olun) if (required != null) ( //remove boşluk alınan = trim(required); println(required); //el sıkışmayı başlatmak için "A" dizimizi arayın //bulunursa, arabelleği temizleyin ve veri isteği gönderin if (firstContact == false) ( if (required.equals("A")) ( serial.clear(); firstContact = true; myPort.write("A"); print ln("contact"); ) ) else ( //iletişim kurulduysa verileri al ve ayrıştır println(required); if (mousePressed == true) ( ​​//pencereye tıkladıysak serial.write("1"); //1 gönder println("1"); ) //tüm verilere sahip olduğunda yeni bir paket için istekte bulun serial.write("A"); ) ) )

Bağlanıp başlatıldığında, konsolda "Hello Kitty" ifadesi görünmelidir. Processing penceresinde tıklandığında pin 13 üzerindeki led yanacak ve sönecektir.

Processing'in yanı sıra PuTTy programlarını kullanabilir veya portlarla çalışmak için hazır sınıfları kullanarak kendi C# programınızı yazabilirsiniz.

04.İletişim: Dimmer

Örnek, bir LED'in parlaklığını kontrol etmek için bir bilgisayardan bir karta nasıl veri gönderebileceğinizi gösterir. Veriler, 0'dan 255'e kadar tek bayt biçiminde gelir. Veriler, İşleme dahil olmak üzere bilgisayardaki seri bağlantı noktasına erişimi olan herhangi bir programdan gelebilir.

Örneğin, 9 numaralı pimde bir direnç ve bir LED bulunan standart bir devreye ihtiyacınız var.

Arduino için eskiz.

Sabit int ledPin = 9; // Pin 9'daki LED geçersiz kurulum() ( Serial.begin(9600); // modu pinMode(ledPin, OUTPUT); ) geçersiz döngü() ( bayt parlaklığı; // (Serial.available()) ise bilgisayardan veri olup olmadığını kontrol edin ( // 0'dan 255'e kadar alınan son baytları oku parlaklık = Serial.read(); // LED'in parlaklığını ayarla analogWrite(ledPin, parlaklık); ) )

İşleme Kodu

process.serial.* dosyasını içe aktarın; seri port; void setup() ( size(256, 150); println("Mevcut seri portlar:"); println(Serial.list()); // Bu listedeki ilk portu kullanır (sayı 0). Arduino kartınıza karşılık gelen portu // seçmek için bunu değiştirin. Son parametre (örn. , Serial.list (), 9600); // Arduino kartı tarafından kullanılan portun adını biliyorsanız, o zaman açıkça // port = new Serial(this, "COM1", 9600); ) geçersiz çizim() ( // (int i = 0; i) için siyahtan beyaza bir gradyan çizin

Başlatın ve fareyi oluşturulan pencerenin üzerinde herhangi bir yönde hareket ettirin. LED'in parlaklığı sola hareket ettirildiğinde azalır, sağa hareket ettirildiğinde artar.

04.İletişim: Fiziksel Piksel (Fare ile LED'i yakın)

Problemi biraz değiştirelim. Fareyi karenin üzerine getirip kart üzerindeki LED'i yakmak için "H" (Yüksek) karakterini göndereceğiz. Fare karenin alanından ayrıldığında LED'i kapatmak için "L" (Düşük) karakterini göndereceğiz.

Arduino için kod.

Sabit int ledPin = 13; // LED incomingByte için pin 13; // veri almak için değişken void setup() ( Serial.begin(9600); pinMode(ledPin, OUTPUT); ) void loop() ( // eğer veri varsa if (Serial.available() > 0) ( // tampondaki byte'ı oku incomingByte = Serial.read(); // eğer H (ASCII 72) ise, LED'i aç if (incomingByte == "H") ( digitalWrite(ledPin, HIGH); ) // eğer bir L karakteriyse (ASCII 76), sonra LED'i kapatın if (incomingByte == "L") ( digitalWrite(ledPin, LOW); ) ) )

İşleme Kodu.

process.serial.* dosyasını içe aktarın; floatboxX; floatboxY; intboxBoyutu=20; booleanmouseOverBox = yanlış; seri port; void setup() ( size(200, 200); boxX = width / 2.0; boxY = height / 2.0; rectMode(RADIUS); println(Serial.list()); // Arduino kartının bağlı olduğu portu açın (bu durumda #0) // Portu Arduino'nun kullandığı hızda açtığınızdan emin olun (9600bps) port = new Serial(this, Serial.list(), 9600); ) void draw() ( background(0 ); // İmleç karenin üzerindeyse if (mouseX > boxX - boxSize && mouseX boxY - boxSize && mouseY

04.İletişim: Grafik (Grafik çiz)

Önceki örnekte bilgisayardan panoya veri gönderdiysek, şimdi ters görevi gerçekleştireceğiz - potansiyometreden veri alacağız ve bunları bir grafik şeklinde göstereceğiz.


Donanım kesintileri

Bu ders için komik bir resim bulamadım, sadece programlama üzerine bir ders buldum ve bu dersin en başında bize neyin ne olduğunu mükemmel bir şekilde açıklıyor. yarıda kesmek. Arduino'daki bir kesinti tam olarak aynı şekilde tanımlanabilir: mikrodenetleyici "her şeyi bırakır", kesme işleyicisinde bir işlev bloğu yürütmeye geçer, bunları yürütür ve ardından tam olarak ana kodda durduğu yere geri döner.

Kesintiler farklıdır, yani kesintilerin kendileri değil, nedenleri: bir kesinti analogdan dijitale dönüştürücüye, zamanlayıcı sayacına veya kelimenin tam anlamıyla bir mikrodenetleyici pinine neden olabilir. Bu tür kesintilere harici denir. donanım ve bugün bundan bahsediyoruz.

Harici donanım kesintisi- Bu, mikrodenetleyicinin pimindeki voltaj değişikliğinden kaynaklanan bir kesintidir. Ana nokta, mikrodenetleyicinin (bilgi işlem çekirdeği) pimi yoklamaz Ve bununla zaman kaybetme, başka bir "demir parçası" pimleme ile meşgul. Pimdeki voltaj değişir değişmez (yani dijital sinyal, +5 uygulandı / +5 kaldırıldı) - mikrodenetleyici bir sinyal alır, her şeyden çıkar, kesmeyi işler ve çalışmaya geri döner. Bu neden gerekli? Çoğu zaman, kesintiler, ana kodu yüklemeden kısa olayları - darbeleri ve hatta sayılarını saymak için algılamak için kullanılır. Bir donanım kesintisi, karmaşık uzun hesaplamalar veya koddaki gecikmeler sırasında bir düğmeye kısa bir süre basmayı veya bir sensör tetiklemesini yakalayabilir, örn. kabaca konuşursak - pim yoklanır ana koda paralel. Ayrıca, kesintiler, neredeyse tüm çevre birimleri kapatıldığında mikrodenetleyiciyi güç tasarrufu modlarından uyandırabilir. Arduino IDE'de donanım kesintileriyle nasıl çalışılacağını görelim.

Arduino'da Kesintiler

Tüm pimlerin "kesemeyeceği" gerçeğiyle başlayalım. evet var böyle bir şey pinChangeInterrupts, ancak ileri düzey derslerde bunun hakkında konuşacağız. Şimdi, donanım kesintilerinin yalnızca belirli pinler oluşturabileceğini anlamamız gerekiyor:

MK / kesme numarası INT 0 İÇ 1 İÇ 2 INT 3 İÇ 4 İÇ 5
ATmega 328/168 (Nano, UNO, Mini) D2 D3
ATmega 32U4 (Leonardo, Mikro) D3 D2 D0 D1 D7
ATmega 2560 (Mega) D2 D3 D21 D20 D19 D18

Tablodan da anlayacağınız gibi kesmelerin pin numarasından farklı olarak kendi numaraları vardır. Kullanışlı bir özellik var digitalPinToInterrupt(pin), bir pin numarası alır ve kesme numarasını döndürür. Bu fonksiyonu Arduino nano üzerinde 3 rakamı ile besleyerek 1 elde ederiz. Yukarıdaki tabloya göre her şey tembeller için bir fonksiyondur.

İşlev kullanılarak bir kesme bağlanır insertInterrupt(pin, işleyici, mod):

  • toplu iğne- kesme numarası
  • işleyici- kesme işleyici işlevinin adı (bunu kendiniz oluşturmanız gerekir)
  • mod– çalışma "modunu" kesme:
    • DÜŞÜK(düşük) - bir sinyal tarafından tetiklenir DÜŞÜK pim üzerinde
    • YÜKSELEN(büyüme) - pimdeki sinyal değiştiğinde tetiklenir DÜŞÜK Açık YÜKSEK
    • DÜŞME(düşme) - pimdeki sinyal değiştiğinde tetiklenir YÜKSEK Açık DÜŞÜK
    • DEĞİŞTİRMEK(değiştir) - sinyal değiştiğinde tetiklenir (ile DÜŞÜK Açık YÜKSEK ve tersi)

Kesme işlevi kullanılarak da devre dışı bırakılabilir. detachInterrupt(sabitleme), pimin tekrar olduğu yer kesme numarası.

Ayrıca, işlevle kesmeleri genel olarak devre dışı bırakabilirsiniz. kesinti yok() ve bunları tekrar çöz kesintiler (). Onlara karşı dikkatli olun! kesinti yok() aynı zamanda zamanlayıcı kesintilerini durduracak ve tüm zaman fonksiyonları ve PWM üretimi sizin için “kesilecektir”.

Kesmede düğme basmalarının sayıldığı ve ana döngüde 1 saniyelik bir gecikmeyle çıktı verildiği bir örneğe bakalım. Düğmeyle normal modda çalışırken, böyle kaba bir çıktıyı bir gecikmeyle birleştirmek imkansızdır:

Uçucu int sayacı = 0; // sayaç değişkeni void setup() ( Serial.begin(9600); // iletişim için bir port açtı // D2 ve GND'ye bir düğme bağladı pinMode(2, INPUT_PULLUP); \ // D2 kesinti 0 // işleyici - buttonTick işlevi // FALLING - düğmeye basıldığında, bir sinyal 0 olacak ve onu yakalarız pluginInterrupt(0, buttonTick, FALLING); ) void buttonTick() ( counter++; // + basarak) geçersiz döngü() ( Serial.println(counter); // print delay(1000); // wait )

Bu nedenle, kodumuz gecikme sırasında bile tıklamaları sayar! Harika. Ama ne uçucu? Global bir değişken ilan ettik. tezgah, düğmedeki tıklama sayısını saklayacak. Değişkenin değeri kesmede değişecekse, belirticiyi kullanarak mikrodenetleyiciyi bu konuda bilgilendirmeniz gerekir. uçucu değişkenin veri tipini belirtmeden önce yazılan , aksi halde çalışma hatalı olacaktır. Sadece şunu hatırlamanız gerekiyor: bir kesmede bir değişken değişirse, yapın uçucu.

Birkaç önemli nokta daha:

  • Bir kesmede değiştirilen değişkenler şu şekilde bildirilmelidir: uçucu
  • Kesintilerde aşağıdaki gibi gecikmeler olmaz gecikme()
  • Bir kesmede değerini değiştirmez milis() Ve mikro ()
  • Kesintide, bağlantı noktasına giden çıktı düzgün çalışmıyor ( Serial.print()), ayrıca orada kullanmayın - çekirdeği yükler
  • Kesinti halinde, mümkün olduğunca az hesaplama yapmaya çalışmanız gerekir ve genel olarak "uzun" eylemler - bu, sık kesintilerle MC'nin çalışmasını yavaşlatır! Ne yapalım? Alttarafı oku.

Kesme, hemen işlenmesi gerekmeyen bir olayı yakalarsa, aşağıdaki kesme işleme algoritmasını kullanmak daha iyidir:

  • Kesme işleyicisinde, sadece bayrağı kaldırın
  • Programın ana döngüsünde bayrağı kontrol ediyoruz, yükselirse sıfırlıyor ve gerekli işlemleri yapıyoruz.
geçici boolean intFlag = false; // flag void setup() ( Serial.begin(9600); // iletişim için bir port açıldı // D2 ve GND'ye bir buton bağlandı pinMode(2, INPUT_PULLUP); // D2 interrupt 0 // handler - buttonTick function // FALLING - butona basıldığında 0 sinyali olacak, onu yakalarız pluginInterrupt(0, buttonTick, FALLING); ) void buttonTick() ( intFlag = true; / / kesme bayrağını yükseltti) geçersiz döngü () ( if (intFlag) ( intFlag = false; // reset // birşeyler yap Serial.println("Interrupt!"); ) )

Temel olarak kesintiler hakkında bilmeniz gereken her şey bu, ileri düzey derslerde daha spesifik durumları analiz edeceğiz.

Video

Talimat

Genel olarak konuşursak, Arduino gerçek görev paralelleştirmesini veya çoklu okumayı desteklemez.
Ancak, bazı ek arka plan görevlerini gerçekleştirme zamanının gelip gelmediğini kontrol etmek için "döngü ()" döngüsünün her tekrarında belirtmek mümkündür. Bu durumda, kullanıcıya birkaç görevin aynı anda gerçekleştirildiği anlaşılıyor.
Örneğin, belirli bir frekansta yanıp sönelim ve aynı zamanda bir piezo yayıcıdan siren gibi yükselen ve alçalan sesler çıkaralım.
Ve LED ve biz zaten Arduino'ya birden fazla kez bağlandık. Devreyi şekildeki gibi kuralım. Bir LED bağlarsanız dijital çıkış"13" dışında, 220 ohm'luk bir akım sınırlama direncini unutmayın.

Bu taslağı yazalım ve Arduino'ya yükleyelim.
Panodan sonra, taslağın tam olarak ihtiyacımız olan şekilde yürütülmediği görülebilir: siren tamamen çalışana kadar, LED yanıp sönmeyecektir ve LED'in sirenin sesi SIRASINDA yanmasını istiyoruz. Buradaki sorun nedir?
Gerçek şu ki, bu sorun olağan şekilde çözülemez. Görevler, mikrodenetleyici tarafından kesinlikle sırayla gerçekleştirilir. "delay()" ifadesi programın çalışmasını belirli bir süre geciktirir ve bu süre dolana kadar programın aşağıdaki komutları çalıştırılmaz. Bu nedenle, programın "loop()" döngüsündeki her görev için farklı bir süre belirleyemeyiz.
Bu nedenle, bir şekilde çoklu görevi simüle etmeniz gerekir.

Arduino'nun görevleri sözde paralel olarak gerçekleştireceği varyant, Arduino geliştiricileri tarafından https://www.arduino.cc/en/Tutorial/BlinkWithoutDelay makalesinde önerilmiştir.
Yöntemin özü, "döngü ()" döngüsünün her tekrarında, LED'in yanıp sönme (bir arka plan görevi gerçekleştirme) zamanının gelip gelmediğini kontrol etmemizdir. Ve öyleyse, o zaman LED'in durumunu tersine çeviriyoruz. Bu, "delay()" operatörünün bir tür atlamasıdır.
Önemli bir dezavantaj Bu method LED kontrol bloğundan önceki kod bölümünün LED'in yanıp sönme zaman aralığından "ledInterval" daha hızlı yürütülmesi gerektiğidir. Aksi takdirde, yanıp sönme gereğinden daha az sıklıkta gerçekleşecek ve görevlerin paralel yürütülmesinin etkisini alamayacağız. Özellikle çizimimizde sirenin sesindeki değişim süresi 200+200+200+200 = 800 ms olup LED'in yanıp sönme aralığını 200 ms olarak ayarladık. Ancak LED, ayarladığımızdan 4 kat farklı olan 800 ms'lik bir süre ile yanıp sönecektir. Genel olarak, kodda "delay()" operatörü kullanılıyorsa, sözde paralelliği simüle etmek zordur, bu nedenle bundan kaçınmak istenir.
Bu durumda siren sesi kontrol bloğunun da saatin gelip gelmediğini kontrol etmesi ve "delay()" kullanmaması gerekir. Ancak bu, kod miktarını artıracak ve programın okunabilirliğini kötüleştirecektir.

Bu sorunu çözmek için, kolayca sözde paralel süreçler oluşturmanıza olanak tanıyan harika ArduinoThread kitaplığını kullanacağız. Benzer şekilde çalışır, ancak zamanı kontrol etmek için kod yazmanıza izin vermez - görevi bu döngüde tamamlayıp tamamlamamanız gerekir. Bu, kod miktarını azaltır ve taslağın okunabilirliğini artırır. Kütüphaneyi çalışırken kontrol edelim.
Her şeyden önce, kütüphane arşivini https://github.com/ivanseidel/ArduinoThread/archive/master.zip resmi web sitesinden indirin ve Arduino IDE geliştirme ortamının "libraries" dizinine açın. Ardından "ArduinoThread-master" klasörünü "ArduinoThread" olarak yeniden adlandırın.

Bağlantı şeması aynı kalacaktır. Sadece program kodu değişecektir. Şimdi kenar çubuğundakiyle aynı olacak.
Programda, her biri kendi işlemini gerçekleştiren iki iş parçacığı oluşturuyoruz: biri LED'i yanıp söner, ikincisi siren sesini kontrol eder. Her iş parçacığı için döngünün her yinelemesinde, yürütme zamanının gelip gelmediğini kontrol ederiz. Ulaşırsa, "run()" yöntemi kullanılarak yürütülmek üzere başlatılır. Önemli olan "delay()" operatörünü kullanmamaktır.
Daha ayrıntılı açıklamalar kodda verilmiştir.
Kodu Arduino hafızasına yükleyin, çalıştırın. Şimdi her şey tam olması gerektiği gibi çalışıyor!

Genel olarak konuşursak, Arduino gerçek görev paralelleştirmesini veya çoklu okumayı desteklemez. Ancak döngünün her tekrarında mümkündür. döngü() mikrodenetleyiciye bazı ek arka plan görevlerini yürütme zamanının gelip gelmediğini kontrol etmesini söyleyin. Bu durumda, kullanıcıya birkaç görevin aynı anda gerçekleştirildiği anlaşılıyor.

Örneğin, bir LED'i belirli bir frekansta yanıp sönelim ve aynı anda bir piezo yayıcıdan siren gibi yükselen ve alçalan sesler çıkaralım. Hem LED'i hem de piezo yayıcıyı Arduino'ya birden fazla kez bağladık. Devreyi şekildeki gibi kuralım.

Bir LED'i "13" dışında bir dijital pine bağlıyorsanız, 220 ohm'luk bir akım sınırlama direncini unutmayın.

2 LED ve Piezo Buzzer Kontrolü delay() operatörünü kullanarak

Bu taslağı yazalım ve Arduino'ya yükleyelim.

Sabit int sesPin = 3; /* piezoelektrik elemanın bağlı olduğu pin numarası ile bir değişken tanımlayın */ const int ledPin = 13; // LED pin numarası ile bir değişken tanımlayın geçersiz kurulum()( pinMode(sesPin, ÇIKIŞ); // pin 3'ü çıkış olarak bildirin. pinMode(ledPin, ÇIKIŞ); // pin 13'ü çıkış olarak bildirin. } geçersiz döngü() (// Ses kontrolü: tone(soundPin, 700); // 700 Hz gecikme frekansında ses çıkar(200); ton(soundPin, 500); // 500 Hz'de gecikme(200); ton(soundPin, 300); // 300 Hz'de gecikme(200); ton(soundPin, 200); // 200 Hz'de gecikme(200); // LED kontrolü: digitalWrite(ledPin, HIGH); // yangın geciktirme(200); digitalWrite(ledPin, DÜŞÜK); // gecikmeyi söndür(200); }

Açtıktan sonra, taslağın tam olarak ihtiyacımız olan şekilde yürütülmediği görülebilir: siren tamamen çalışana kadar LED yanıp sönmeyecek ve LED'in yanıp sönmesini istiyoruz sırasında bir siren sesi. Buradaki sorun nedir?

Gerçek şu ki, bu sorun olağan şekilde çözülemez. Görevler, mikrodenetleyici tarafından kesinlikle sırayla gerçekleştirilir. Şebeke gecikme() programın çalışmasını belirli bir süre geciktirir ve bu süre dolana kadar programın aşağıdaki komutları yürütülmez. Bu nedenle, döngüdeki her görev için farklı bir yürütme süresi belirleyemeyiz. döngü() programlar. Bu nedenle, bir şekilde çoklu görevi simüle etmeniz gerekir.

3 Paralel Süreçler"delay()" operatörü olmadan

Arduino'nun görevleri sözde paralel olarak gerçekleştireceği seçenek, Arduino geliştiricileri tarafından önerilmiştir. Yöntemin özü, döngünün her tekrarında döngü() LED'i yanıp sönme (bir arka plan görevi gerçekleştirme) zamanının gelip gelmediğini kontrol ederiz. Ve öyleyse, o zaman LED'in durumunu tersine çeviriyoruz. Bu bir tür baypas operatörüdür. gecikme().

Sabit int sesPin = 3; // piezoelektrik elemanın pin numarası ile değişken const int ledPin = 13; // LED pin numaralı değişken const long ledInterval = 200; // LED yanıp sönme aralığı, msn. int ledState = DÜŞÜK; // işaretsiz LED'in ilk durumu uzun öncekiMillis = 0; // önceki LED ateşlemesinin zamanını sakla geçersiz kurulum()( pinMode(sesPin, ÇIKIŞ); // pin 3'ü çıkış olarak ayarlayın. pinMode(ledPin, ÇIKIŞ); // pin 13'ü çıkış olarak ayarlayın. } geçersiz döngü() (// Ses kontrolü: tone(soundPin, 700); gecikme(200); ton(soundPin, 500); gecikme(200); ton(soundPin, 300); gecikme(200); ton(soundPin, 200); gecikme(200); // Yanıp Sönen LED: // Arduino açıldığından beri geçen süre, ms: unsigned long currentMillis = millis(); // Eğer yanıp sönme zamanı geldiyse, if (currentMillis - priorMillis >= ledInterval) ( öncekiMillis = currentMillis; // o zaman hatırla şimdiki zaman if (ledState == LOW) ( // ve LED durumunu ters çevirin ledState = HIGH; ) else ( ledState = LOW; ) digitalWrite(ledPin, ledState); // LED'in durumunu değiştirin) }

Bu yöntemin önemli bir dezavantajı, LED kontrol bloğundan önceki kod bölümünün "ledInterval" LED'inin yanıp sönme zaman aralığından daha hızlı yürütülmesi gerekmesidir. Aksi takdirde, yanıp sönme gereğinden daha az sıklıkta gerçekleşecek ve görevlerin paralel yürütülmesinin etkisini alamayacağız. Özellikle çizimimizde sirenin sesindeki değişim süresi 200+200+200+200 = 800 ms olup LED'in yanıp sönme aralığını 200 ms olarak ayarladık. Ancak LED, ayarladığımızın 4 katı olan 800 ms'lik bir sürede yanıp sönecektir.

Genel olarak, kod operatörü kullanıyorsa gecikme(), bu durumda sözde paralelliği simüle etmek zordur, bu nedenle bundan kaçınmak istenir.

Bu durumda siren ses kontrol ünitesinin de saatin gelip gelmediğini kontrol etmesi ve kullanmaması gerekir. gecikme(). Ancak bu, kod miktarını artıracak ve programın okunabilirliğini kötüleştirecektir.

4 ArduinoThread Kitaplığını Kullanma paralel iş parçacıkları oluşturmak için

Sorunu çözmek için harika bir kütüphane kullanacağız Arduino İpliği, kolayca sözde paralel süreçler oluşturmanıza olanak tanır. Benzer şekilde çalışır, ancak zamanı kontrol etmek için kod yazmanıza izin vermez - görevi bu döngüde tamamlayıp tamamlamamanız gerekir. Bu, kod miktarını azaltır ve taslağın okunabilirliğini artırır. Kütüphaneyi çalışırken kontrol edelim.


Her şeyden önce, kütüphane arşivini resmi web sitesinden indirin ve dizine açın. kütüphaneler/ Arduino IDE geliştirme ortamı. Ardından klasörü yeniden adlandırın Arduino Konu ustası V Arduino İpliği.

Bağlantı şeması aynı kalacaktır. Sadece program kodu değişecektir.

#katmak // ArduinoThread kitaplığının bağlanması const int soundPin = 3; // piezoelektrik elemanın pin numarası ile değişken const int ledPin = 13; // LED pin numaralı değişken Thread ledThread = Thread(); // LED'i kontrol etmek için bir dizi oluştur soundThread = Thread(); // siren için bir kontrol akışı oluştur geçersiz kurulum()( pinMode(sesPin, ÇIKIŞ); // pin 3'ü çıkış olarak bildirin. pinMode(ledPin, ÇIKIŞ); // pin 13'ü çıkış olarak bildirin. ledThread.onRun(ledBlink); // iş parçacığına bir görev atayın ledThread.setInterval(1000); // yanıt aralığını ayarlayın, ms soundThread.onRun(sound); // diziye bir görev atayın soundThread.setInterval(20); // yanıt aralığını ayarla, ms } geçersiz döngü() (// LED'i değiştirme zamanının gelip gelmediğini kontrol edin: if (ledThread.shouldRun()) ledThread.run(); // diziyi başlat // Sirenin tonunu değiştirme zamanının gelip gelmediğini kontrol edin: if (soundThread.shouldRun()) soundThread.run(); // iş parçacığını başlat } // LED akısı: geçersiz ledBlink() ( statik bool ledStatus = false; // LED durumu Açık/Kapalı ledStatus = !ledStatus; // durumu tersine çevir digitalWrite(ledPin, ledStatus); // led'i aç/kapat } // Siren akışı: geçersiz ses() ( statik int tonu = 100; // ses tonu, Hz tonu(soundPin, ton); // sireni "ton" Hz'de aç if (ton )

Programda iki iş parçacığı oluşturuyoruz - ledİplik Ve sesİpliği, her biri kendi işlemini gerçekleştirir: biri LED'i yanıp söner, ikincisi siren sesini kontrol eder. Her iş parçacığı için döngünün her yinelemesinde, yürütme zamanının gelip gelmediğini kontrol ederiz. Ulaşırsa, yöntem kullanılarak yürütülmek üzere başlatılır. koşmak(). Ana şey operatörü kullanmamak gecikme(). Daha ayrıntılı açıklamalar kodda verilmiştir.


Kodu Arduino hafızasına yükleyin, çalıştırın. Şimdi her şey tam olması gerektiği gibi çalışıyor!

Ve işte kullanımına bir örnek arduino fonksiyonları iliştirmeKesme().

Kesinti, işlemciye acil dikkat gerektiren bazı olayların meydana geldiği hakkında bilgi veren bir sinyaldir. İşlemci, mevcut talimatların yürütülmesini keserek ve kontrolü kesme işleyicisine (ISR, Interrupt Service Routine) devrederek bu sinyale yanıt vermelidir. Bir işleyici, kendimize yazdığımız ve olaya yanıt vermesi gereken kodu oraya koyduğumuz normal bir işlevdir.

ISR kesintisine hizmet verdikten sonra, işlev işini sonlandırır ve işlemci mutlu bir şekilde kesintiye uğrayan etkinliklere geri döner - kodu durduğu yerden yürütmeye devam eder. Tüm bunlar otomatik olarak gerçekleşir, bu nedenle görevimiz yalnızca hiçbir şeyi bozmadan ve işlemciyi çok sık dikkatimizi dağıtmaya zorlamadan bir kesme işleyicisi yazmaktır. Devreyi, bağlı cihazların çalışma ilkelerini ve bir kesintinin ne sıklıkla çağrılabileceği, oluşumunun özellikleri nelerdir hakkında bir anlayışa ihtiyacınız olacak. Bütün bunlar, kesintilerle çalışmanın ana zorluğudur.

Donanım ve yazılım kesintileri

Arduino'daki kesintiler birkaç türe ayrılabilir:

  • Donanım kesintileri. Mikroişlemci mimarisi düzeyinde kesinti. Olayın kendisi, verimli bir anda harici bir cihazdan gerçekleşebilir - örneğin, klavyede bir düğmeye basmak, hareket ettirmek Bilgisayar faresi ve benzeri.
  • Yazılım kesintileri. Özel bir talimat kullanılarak programın içinde başlatılırlar. Bir kesme işleyicisini çağırmak için kullanılır.
  • Dahili (senkronize) kesmeler. Programın yürütülmesindeki bir değişiklik veya ihlalin bir sonucu olarak (örneğin, geçersiz bir adrese, geçersiz işlem koduna vb. erişirken) dahili bir kesinti meydana gelir.

Neden donanım kesintilerine ihtiyacımız var?

Donanım kesintileri, harici bir olaya yanıt olarak meydana gelir ve harici bir donanım aygıtından gelir. Arduino'da 4 tip donanım kesintisi vardır. Hepsi kesme pimindeki sinyalde farklılık gösterir:

  • Kontak yere çekilir. Kesme işleyicisi, kesme pimi DÜŞÜK olduğu sürece yürütülür.
  • Bir kontaktaki sinyali değiştirme. Bu durumda Arduino, kesme pininde bir sinyal değişikliği meydana geldiğinde bir kesme işleyicisi yürütür.
  • Bir pimde sinyali DÜŞÜK'ten YÜKSEK'e değiştirmek - düşükten yükseğe geçerken, bir kesme işleyicisi yürütülür.
  • Bir pimdeki sinyali YÜKSEK'ten DÜŞÜK'e değiştirme - sinyal yüksekten alçağa değiştiğinde, bir kesme işleyicisi yürütülür.

Kesintiler, zamanlama problemlerini çözmeye yardımcı oldukları için Arduino programlarında kullanışlıdır. Örneğin, UART ile çalışırken kesintiler, her karakterin gelişini takip etmemenizi sağlar. Harici donanım aygıtı bir kesme sinyali verir, işlemci hemen karakteri zamanında yakalayan kesme işleyicisini çağırır. Bu, kesinti olmadan UART'ın durumunu kontrol etmek için harcanacak olan CPU zamanından tasarruf sağlar, bunun yerine gerekli tüm eylemler kesme işleyicisi tarafından etkilemeden gerçekleştirilir. ana program. Donanım aygıtından herhangi bir özel yetenek gerekmez.

Kesinti çağırmanın ana nedenleri şunlardır:

  • Çıkışın durum değişikliğinin belirlenmesi;
  • Zamanlayıcı kesintisi;
  • SPI, I2C, USART aracılığıyla veri kesintileri;
  • Analogdan dijitale dönüştürme;
  • EEPROM, flash bellek kullanma isteği.

Arduino'da kesintiler nasıl uygulanır?

Bir kesme sinyali alındığında, işlem askıya alınır. Kesinti anında yürütüleceği bildirilen işlevin yürütülmesi başlar. Bildirilen bir işlev, giriş değerlerini kabul edemez ve tamamlandığında değerleri döndüremez. Kesme, ana program döngüsündeki kodun kendisini etkilemez. Arduino'da kesintilerle çalışmak için standart bir işlev kullanılır. iliştirmeKesme().

Farklı Arduino kartlarında kesintilerin uygulanması arasındaki fark

Donanım uygulamasına bağlı olarak belirli model Mikrodenetleyicinin birkaç kesmesi vardır. Ödemek arduino uno 2. ve 3. pinde 2 kesinti vardır, ancak ikiden fazla çıkış gerekiyorsa kart destekler özel mod pin değiştirme Bu mod, tüm pinler için girişi değiştirerek çalışır. Giriş değiştirme kesme modundaki fark, kesmelerin sekiz pimden herhangi biri üzerinde üretilebilmesidir. Bu durumda işleme daha karmaşık ve daha uzun olacaktır, çünkü her bir kişinin son durumunu takip etmeniz gerekecektir.

Diğer kartlarda kesinti sayısı daha fazladır. Örneğin, kartın harici kesintileri kaldırabilen 6 pini vardır. Tüm Arduino kartları için, insertInterrupt (interrupt, function, mode) fonksiyonu ile çalışırken, Inerrupt 0 argümanı dijital pin 2 ile ilişkilendirilir.

Arduino Dilinde Kesintiler

Şimdi uygulamaya geçelim ve kesmeleri projelerinizde nasıl kullanacağınız hakkında konuşalım.

InsertInterrupt() Sözdizimi

InsertInterrupt işlevi, kesintilerle çalışmak için kullanılır. Bir işleyiciye harici bir kesinti bağlamaya yarar.

Çağrı sözdizimi: insertInterrupt(interrupt, function, mode)

İşlev bağımsız değişkenleri:

  • kesme - çağrılan kesme sayısı (standart 0 - 2. pin için, Arduino Uno kartı için 1 - 3. pin için),
  • işlev - kesintiye uğradığında çağrılan işlevin adı (önemli - işlev herhangi bir değeri kabul etmemeli veya döndürmemelidir),
  • mod, kesmeyi tetiklemenin koşuludur.

Aşağıdaki tetikleme koşulları ayarlanabilir:

  • DÜŞÜK - kontak sıfır değerine sahip olduğunda, düşük bir sinyal seviyesinde gerçekleştirilir. Kesme döngüsel olarak tekrarlanabilir - örneğin, bir düğmeye basıldığında.
  • DEĞİŞİM - ön tarafta, sinyal yüksekten alçağa değiştiğinde veya tam tersi olduğunda kesme gerçekleşir. Herhangi bir sinyal değişiminde bir kez yürütülür.
  • YÜKSELEN - Sinyal DÜŞÜK'ten YÜKSEK'e değiştiğinde bir kesme gerçekleştirin.
  • FALLING - Sinyal YÜKSEK'ten DÜŞÜK'e değiştiğinde bir kez kesme gerçekleştirin.4

Önemli notlar

Kesintilerle çalışırken, aşağıdaki önemli sınırlamalar dikkate alınmalıdır:

  • İşleyici işlevinin yürütülmesi çok uzun sürmemelidir. Mesele şu ki, Arduino aynı anda birden fazla kesintiyi kaldıramaz. İşleyici işleviniz yürütülürken, diğer tüm kesmeler yok sayılır ve önemli olayları kaçırabilirsiniz. Büyük bir şey yapmanız gerekiyorsa, olay işlemeyi ana döngü() döngüsünde iletmeniz yeterlidir. İşleyicide yalnızca olay bayrağını ayarlayabilirsiniz ve döngüde bayrağı kontrol edip işleyebilirsiniz.
  • Değişkenler konusunda çok dikkatli olmalısınız. Akıllı bir C++ derleyicisi, ihtiyaç duymadığı değişkenleri kaldırarak programınızı "yeniden optimize edebilir". Derleyici, bazı değişkenleri bir bölümde ayarlayıp diğerinde kullandığınızı görmeyecektir. Temel veri türleri söz konusu olduğunda bu olasılığı ortadan kaldırmak için şunları kullanabilirsiniz: anahtar kelime uçucu, şu şekilde: uçucu boole durumu = 0. Ancak bu yöntem karmaşık veri yapılarıyla çalışmaz. Bu yüzden her zaman tetikte olmalısınız.
  • Çok sayıda kesme kullanılması önerilmez (6-8'den fazla kesmemeye çalışın). Çok sayıdaçeşitli olaylar, kodun ciddi şekilde karmaşıklaşmasını gerektirir ve bu nedenle hatalara yol açar. Ek olarak, sistemlerde yürütmenin zamansal doğruluğunun olmadığı da anlaşılmalıdır. büyük miktar konuşma kesintisi olamaz - sizin için önemli olan komut çağrıları arasındaki boşluğun ne olduğunu asla tam olarak anlayamayacaksınız.
  • İşleyicilerde Delay() kullanılmamalıdır. Gecikme aralığını belirleme mekanizması zamanlayıcıları kullanır ve ayrıca işleyicinizin engelleyeceği kesintiler üzerinde de çalışırlar. Sonuç olarak herkes herkesi bekleyecek ve program askıda kalacaktır. Aynı nedenle kesme tabanlı iletişim protokolleri (i2c gibi) kullanılamaz.

InsertInterrupt örnekleri

Pratik yapmaya başlayalım ve kesintileri kullanmanın en basit örneğini ele alalım. Örnekte, Arduino Uno'nun 2. pimindeki sinyal değiştiğinde, geleneksel olarak LED'i bağlayacağımız 13. pimin durumunu değiştirecek bir işleyici işlevi tanımlıyoruz.

#define PIN_LED 13 uçucu boolean actionState = LOW; void setup() ( pinMode(PIN_LED, OUTPUT); // Kesmeyi ayarlayın // myEventListener işlevi, pin 2'de sinyal değiştiğinde çağrılır (kesme 0, pin 2'ye bağlanır) // sinyal değiştiğinde (hangi yönde olursa olsun) pluginInterrupt(0, myEventListener, CHANGE); ) void loop() ( // Döngü işlevinde hiçbir şey yapmayız, çünkü tüm olay işleme kodu myEventListener'da olacaktır işlevi) void myE ventListener() ( actionState != actionState; // // LED'i açmak veya kapatmak gibi diğer eylemleri gerçekleştirin digitalWrite(PIN_LED, actionState); )

Zamanlayıcı ve düğmeler için daha karmaşık kesintilere ve işleyicilerine ilişkin bazı örneklere bakalım.

Sıçrama önleyici düğme kesintileri

Kesinti meydana geldiğinde - kontaklar düğmeye basıldığında sağlam temas kurmadan önce, salınarak birkaç işlem oluştururlar. Gevezelikle başa çıkmanın iki yolu vardır - donanım, yani düğmeye bir kondansatör lehimleyerek ve yazılım.

İşlevi kullanarak gevezelikten kurtulabilirsiniz - düğmenin ilk çalıştırılmasından itibaren geçen süreyi tespit etmenizi sağlar.

If(digitalRead(2)==HIGH) ( //düğmeye basıldığında //Bir önceki basıştan bu yana 100 milisaniyeden fazla zaman geçtiyse if (millis() - öncekiMillis >= 100) ( //İlk işlemin zamanı hatırlanır priorMillis = millis(); if (led==oldled) ( //düğmenin durumunun değişmediği kontrol edilir led=!led; )

Bu kod, gevezeliği kaldırmanıza izin verir ve kesintilerde izin verilmeyen gecikme işlevinde olduğu gibi programın yürütülmesini engellemez.

Zamanlayıcı kesintileri

Bir zamanlayıcı, 16 MHz işlemciden elde edilen belirli bir frekansta sayan bir sayaçtır. İstenen sayma modunu elde etmek için frekans bölücüyü yapılandırabilirsiniz. Sayacı, belirli bir değere ulaşıldığında kesintiler oluşturacak şekilde de yapılandırabilirsiniz.

Ve zamanlayıcı kesintisi, kesintiyi milisaniyede bir kez yürütmenize izin verir. Arduino'nun 3 zamanlayıcısı vardır - Timer0, Timer1 ve Timer2. Timer0, millis() işlevine iletilen sayacı güncelleyen milisaniyede bir kesinti oluşturmak için kullanılır. Bu zamanlayıcı sekiz bittir ve 0'dan 255'e kadar sayar. Değer 255 olduğunda bir kesme üretilir. Varsayılan olarak, 1kHz'e yakın bir frekans elde etmek için 65'e bir saat bölücü kullanılır.

Karşılaştırma kayıtları, zamanlayıcıdaki durumu ve saklanan verileri karşılaştırmak için kullanılır. İÇİNDE bu örnek sayaç 0xAF'ye ulaştığında kod bir kesme oluşturacaktır.

TIMSK0 |= _BV(OCIE0A);

Zamanlayıcı kesme vektörü için bir kesme işleyicisi tanımlamak gerekir. Kesme vektörü, kesme çağrıldığında yürütülecek talimatın konumuna işaretçidir. Birkaç kesinti vektörü, bir kesinti vektör tablosunda birleştirilir. Bu durumda zamanlayıcının adı TIMER0_COMPA_vect olacaktır. Bu işleyicide, döngü () ile aynı eylemler gerçekleştirilecektir.

SIGNAL(TIMER0_COMPA_vect) ( unsigned long currentMillis = millis(); wiper1.Update(currentMillis); if(digitalRead(2) == HIGH) ( wiper2.Update(currentMillis); led1.Update(currentMillis); ) led2.Update(currentMillis); led3.Update(currentMillis); ) // Döngü() işlevi boş kalacaktır. boşluk döngüsü() ( )

Özetleme

Arduino'da kesinti oldukça karmaşık bir konudur çünkü bir kerede projenin tüm mimarisini düşünmeniz, kodun nasıl yürütüldüğünü, hangi olayların mümkün olduğunu, ana kod kesintiye uğradığında ne olacağını hayal etmeniz gerekir. Bu dil yapısıyla çalışmanın tüm özelliklerini ortaya çıkarmayı amaçlamadık, asıl amaç ana kullanım durumlarını tanıtmaktı. İlerleyen yazılarda kesintilerden daha detaylı bahsetmeye devam edeceğiz.