Arduino multitasking - část třetí
Kresba Davida Earla
Digitální RGB LED diody , jako Neopixel , jsou skvělé pro vytváření ohromujících displejů a světelných efektů. Ale spojit je do jednoho projektu není tak snadné. Arduino je malý procesor, který upřednostňuje dělat jen jednu věc najednou. Jak se vám tedy podaří věnovat pozornost vnějším vstupům a generovat všechny ty úžasné obrazové vzory?
Mezi nejčastější dotazy týkající se Neopixelu na fórech Arduino patří:
- Jak mohu zajistit, aby můj projekt Neopixel spolehlivě reagoval na stisknutí tlačítek?
- Jak mohu spustit dva (nebo více) různých Neopixelových vzorů současně?
- Jak mohu přimět své Arduino dělat jiné věci, zatímco běží Neopixelový vzor?
V této příručce prozkoumáme způsoby, jak tvarovat váš Neopixelový kód tak, aby reagoval a reagoval na multitasking.
Problém? Smyčky a zpoždění
V praxi se všechny příklady kódu skládají ze smyček, které procházejí různými fázemi pixelové animace. Kód je tak zaneprázdněn aktualizací pixelů, že hlavní smyčka nikdy nedostane příležitost zkontrolovat přepínače.
Ale je opravdu zaneprázdněný? Ve skutečnosti kód tráví většinu času neděláním nic! Je to proto, že zpoždění funguje díky funkci delay (). Jak jsme viděli v první části, zpoždění je doslova ztrátou času. Proto se ho zbavíme.
Ale smyčky stále zůstávají. Pokud se pokusíte napsat jednu smyčku, která ukazuje dvě schémata animace najednou, kód se rychle zhroutí. Z tohoto důvodu se také musíme vyhnout vytváření smyček.
Dekonstrukce smyčky
Nevzdávej to
Jedním z často navrhovaných řešení problému s odezvou je kontrola přepínačů ve smyčce a jejich ukončení, pokud je stisknuto tlačítko. Kontrola spínače může pečlivě souviset se zpožděním. A smyčku lze přepsat, aby přestala fungovat brzy.
Díky tomu bude váš program lépe reagovat. S touto metodou však existuje několik problémů:
- Stále používáte funkci delay (), takže stále nespustíte dva (nebo více) vzory najednou.
- Co když opravdu nechcete smyčku přeskočit? Musíme najít způsob, jak dál reagovat - bez narušení schématu.
Pomohou přerušení?
Naučili jsme se, jak používat přerušení v části 2 . Nejsou však odpovědí na všechny tyto problémy.
Přerušení pomůže eliminovat povinnost kontrolovat spínače. Díky tomu je kód trochu čistší. To však neznamená, že to vyřeší zbývající problémy uvedené výše.
Myšlení mimo smyčku:
Všechny tyto potíže lze odstranit. Budeme se však muset zbavit zpoždění a vzdát se smyčky. Dobrou zprávou je, že konečný kód bude překvapivě jednoduchý.
Problém se smyčkou a zpoždění v Neopixelu jsou velmi podobné příkladu zametání serva v části 1 . V Neopixelových schématech můžeme použít stejnou metodu se stavovým automatem.
Základním řešením je souhrn vzorců ve třídě C ++. Zachyťte všechny stavové proměnné jako členské proměnné a přesuňte jádro logiky smyčky do funkce Update (), která k řešení zpoždění používá funkci millis ().
Funkci aktualizace lze volat z funkce loop () nebo z časového přerušení. Při každém průchodu můžete aktualizovat více schémat najednou a současně sledovat interakci mezi uživateli.
Společný kód
V tomto odstavci přepracujeme některá populární pixelová schémata, včetně:
- RainbowCycle
- ColorWipe
- TheaterChase
- Skener
- Fader
Tyto vzorce zúžíme na jednu třídu „NeoPattern“ získanou ze třídy Adafruit_NeoPixel. Můžete tedy dobrovolně změnit vzory na stejném pruhu .
A protože NeoPattern je odvozen od Adafruit_NeoPixel , můžete také použít všechny standardní funkce z knihovny NeoPixel!
Než implementujeme vzorový kód, podívejme se, co mají tato schémata společná a co o nich potřebujeme vědět, abychom je mohli spravovat. Pak můžeme začít vytvářet strukturu třídy, která se postará o všechny vzorce.
Členské proměnné:
Níže uvedená definice třídy uvádí členské proměnné, které mají použít vzor, směr, kterým jde, a aktuální stav stroje schématu.
Tip: Možnost Směr je užitečná při práci s neopixelovými disky, které mají pořadí pixelů ve směru hodinových ručiček a ne ve směru hodinových ručiček.
Tyto proměnné představují kompromis mezi rychlostí a velikostí. Režie na pixel je stejná jako základní třída Adafruit_Neopixel. Většina proměnných stavu vzoru je společná většině vzorů.
Pokud je na Arduinu k dispozici omezený počet SRAM, budou některé výpočty prováděny „za běhu“ ve funkcích Update () a ušetří místo navíc pro více pixelů!
Dokončení zpětných volání:
Funkce zpětného volání "OnComplete ()" , pokud existuje, je volána na konci každé verze vzoru. Můžete zadat zpětné volání k provedení jakékoli akce - včetně změny vzoru nebo stavu akce. Ukážeme vám, jak to funguje později.
#include// Podporované typy vzorů: vzor výčtu {NONE, RAINBOW_CYCLE, THEATER_CHASE, COLOR_WIPE, SCANNER, FADE}; // Podporovány směry otcovy strany: směr výčtu {FORWARD, REVERSE}; // NeoPattern Class - odvozeno od třídy Adafruit_NeoPixel třída NeoPatterns: public Adafruit_NeoPixel { veřejnost: // Proměnné členů: vzor ActivePattern; // který vzor běží směr směr; // směr pro spuštění vzoru dlouhý interval bez znaménka; // milisekundy mezi aktualizacemi nepodepsaný dlouhý lastUpdate; // poslední aktualizace polohy uint32_t Color1, Color2; // Jaké barvy se používají uint16_t TotalSteps; // celkový počet kroků ve vzoru uint16_t index; // aktuální krok ve vzoru void (* OnComplete) (); // Zpětné volání po dokončení vzoru
Konstruktor:
Konstruktor inicializuje základní třídu a (volitelně) ukazatel na funkci zpětného volání.
#include// Konstruktor - zavolá konstruktor základní třídy k inicializaci pruhu NeoPatterns (pixely uint16_t, pin uint8_t, typ uint8_t, void (* zpětné volání) ()) : Adafruit_NeoPixel (pixely, špendlík, typ) { OnComplete = zpětné volání; }
Aktualizátor:
Funkce Update () je velmi podobná funkci Update () v části 1 . Kontroluje čas uplynulý od poslední aktualizace a okamžitě se vrátí, pokud ještě nemusí nic dělat.
Pokud určí, že je čas na aktualizaci schématu, bude se dívat na členské proměnné ActivePattern a rozhodnout se, které funkce aktualizace specifické pro vzor se mají vyvolat.
Pro každé schéma v seznamu budeme muset napsat inicializační funkci a funkci Update ().
// Aktualizace vzoru void Update () { if ((millis () - lastUpdate)> Interval) // čas aktualizace { lastUpdate = millis (); přepínač (ActivePattern) { případ RAINBOW_CYCLE: RainbowCycleUpdate (); přestávka; případ THEATRE_CHASE: TheaterChaseUpdate (); přestávka; případ COLOR_WIPE: ColorWipeUpdate (); přestávka; SKENER: ScannerUpdate (); přestávka; případ FADE: FadeUpdate (); přestávka; výchozí: přestávka; } } }
Zvyšování vzoru
Funkce Increment () sleduje aktuální stav směru a odpovídajícím způsobem zvyšuje nebo snižuje index. Když dosáhne konce vzoru, je obrácen pro restartování vzoru. Funkce zpětného volání OnComplete () je volána, když není null.
// Zvýšení indexu a reset na konci void přírůstek () { if (Směr == DOPŘED) { Index ++; if (Index> = TotalSteps) { Index = 0; if (OnComplete! = NULL) { OnComplete (); // zavolá zpětné volání comlpetion } } } else // Směr == ZPĚT { --Index; pokud (index <= 0) { Index = TotalSteps-1; if (OnComplete! = NULL) { OnComplete (); // zavolá zpětné volání comlpetion } } } }
RainbowCycle
Duhový cyklus používá barevný kruh k vytvoření duhového efektu, který krouží po celé délce pruhu . Jedná se o jednoduchou změnu struktury vzoru RainbowCycle ve vzorku Strand Test Sketch Library.
Inicializace:
Funkce RainbowCycle () inicializuje třídu NeoPatterns pro spuštění vzoru Rainbow Cycle.
ActivePattern je nastaven na RAINBOW_CYCLE.
Parametr „interval“ určuje počet milisekund mezi aktualizacemi, což určuje rychlost vzoru.
Parametr „dir“ je další. Ve výchozím nastavení je nastavena na operaci Vpřed, ale vždy ji můžete změnit na REVERSE .
TotalSteps je nastaven na 255, což označuje počet barev v barevném kruhu.
Index je nastaven na 0, takže začneme první barvou v kruhu.
// Inicializace pro RainbowCycle void RainbowCycle (uint8_t interval, direction dir = FORWARD) {ActivePattern = RAINBOW_CYCLE; Interval = interval; TotalSteps = 255; Index = 0; Směr = dir; }
Aktualizace:
Funkce RainbowCycleUpdate () nastaví každý pixel v pruhu na barvu barevného kruhu. Počáteční bod v kruhu je zvýrazněn indexem.
Funkce Increment () je volána k aktualizaci indexu po zápisu do pruhu volajícího funkci show ().
// Aktualizujte vzor duhového cyklu void RainbowCycleUpdate () { pro (int i = 0; iColorWipe
Vzor ColorWipe vytvoří malířský efekt po celé délce pruhu.
Inicializace:
Funkce ColorWipe () inicializuje objekt NeoPattern a vytvoří vzor ColorWipe.
Parametr color určuje barvu, která se má zobrazit podél pruhu.
Parametr intrval určuje počet milisekund mezi úspěšnými zobrazeními pixelů.
Parametr direction je volitelný a určuje směr zobrazení. Pixely se ve výchozím nastavení zobrazují DOPŘEDU .
TotalSteps je nastaven na počet pixelů v pruhu.
// Inicializace pro ColorWipe void ColorWipe (uint32_t color, uint8_t interval, direction dir = FORWARD) { ActivePattern = COLOR_WIPE; Interval = interval; TotalSteps = numPixels (); Color1 = barva; Index = 0; Směr = dir; }Aktualizace:
Funkce ColorWipeUpdate () nastaví další pixel v pruhu, poté zavolá show () pro zápis do pruhu a Increment () pro aktualizaci rejstříku.
// Aktualizace vzoru vymazání barvy void ColorWipeUpdate () { setPixelColor (index, barva1); ukázat(); Přírůstek (); }TheaterChase
Vzor TheaterChase napodobuje klasický vzor nalezený na plakátech divadel z 50. let. V této variantě můžete určit barvy předního a zadního světla.
Inicializace:
Funkce TheaterChase () inicializuje objekt NeoPattern k provedení schématu TheaterChase.
Parametry color1 a color2 určují barvy popředí a pozadí vzoru.
Parametr přírůstku určuje počet milisekund mezi aktualizacemi vzoru a řídí rychlost efektu „chase“.
Parametr směru je volitelný a umožňuje spustit schéma VPRAVO (výchozí) nebo REVERZNÍ.TotalSteps nastavuje počet pixelů v pruhu .// Inicializace pro divadelní honičku void TheaterChase (uint32_t color1, uint32_t color2, uint8_t interval, direction dir = FORWARD) { ActivePattern = THEATRE_CHASE; Interval = interval; TotalSteps = numPixels (); Barva1 = barva1; Barva2 = barva2; Index = 0; Směr = dir; }Aktualizace:
Funkce TheaterChaseUpdate () rozšiřuje vzor o jeden pixel. Každý třetí pixel získá přední barvu ( color1 ). Zbytek získá barvu2.
Funkce Increment () je volána k aktualizaci Indexu poté, co byly barvy pixelu přidány do pruhu pomocí show ().
// Aktualizace vzoru Chase Theater void TheaterChaseUpdate () { pro (int i = 0; iSkener
Schéma skeneru se skládá z jediné LED, která se pohybuje sem a tam a zanechává za sebou stopu slábnoucích LED.
Inicializace:
Funkce Scanner () inicializuje objekt NeoPattern a provede skenerový vzor.
Parametr barvy je barva pohybujícího se pixelu.
Parametr interval určuje počet milisekund mezi aktualizacemi a řídí rychlost „skenování“.
Skenování je celková zpáteční cesta z jednoho konce proužku na druhý a zpět, bez dodatečné čekací doby na koncích pixelů. Total Steps je tedy nastaven na dvojnásobek počtu pixelů minus 2.
// Inicializace pro SKENER void Scanner (uint32_t color1, uint8_t interval) { ActivePattern = SKENER; Interval = interval; TotalSteps = (Strip-> numPixels () - 1) * 2; Barva1 = barva1; Index = 0; }Aktualizace:
Funkce ScannerUpdate () se opakovaně opakuje mezi pixely v pruhu . Pokud pixel odpovídá aktuální hodnotě Indexu nebo hodnotě TotalSteps - Index, nastavíme pixel na color1.
Jinak pixel „ztmavíme“, což vytvoří efekt blednoucí šmouhy.
Stejně jako všechny ostatní vzory, ScannerUpdate volá funkci show (), aby ji připojila k liště, a funkci Increment () pro rozšíření automatu.
// Aktualizujte vzor skeneru void ScannerUpdate () { pro (int i = 0; iFader
Faderový vzor je jedním z nejžádanějších neopixelových efektů na fórech. Tento vzor vytváří jemný lineární přechod z jedné barvy na druhou.
Inicializace:
Funkce Fade () inicializuje objekt NeoPattern k provedení rozostření.
Parametr color1 určuje počáteční barvu.
color2 určuje koncovou barvu.
Kroky určuje počet kroků od color1 do color2.
interval určuje počet milisekund mezi kroky a řídí rychlost rozmazání.
Směr umožňuje obrátit rozostření tak, aby přecházelo z barvy2 na barvu1.
// Inicializace pro slábnutí void Fade (uint32_t color1, uint32_t color2, uint16_t kroky, uint8_t interval, směr dir = FORWARD) { ActivePattern = FADE; Interval = interval; TotalSteps = kroky; Barva1 = barva1; Barva2 = barva2; Index = 0; Směr = dir; }Aktualizace:
Funkce FadeUpdate () nastaví všechny pixely v pruhu na barvu, která odpovídá dalšímu kroku.
Barva se počítá jako lineární interpolace mezi červenými, zelenými a modrými prvky barev 1 a 2 . Pro urychlení použijeme celá čísla. Abychom minimalizovali chyby, nechali jsme rozdělení na konec.
Stejně jako všechny ostatní vzory, ScannerUpdate zapisuje do pruhu s funkcí show (), funkce Increment () přesouvá stavový stroj.
// Aktualizace vzoru prolínání void FadeUpdate () { uint8_t red = ((Red (Color1) * (TotalSteps - Index)) + (Red (Color2) * Index)) / TotalSteps; uint8_t green = ((Green (Color1) * (TotalSteps - Index)) + (Green (Color2) * Index)) / TotalSteps; uint8_t blue = ((Blue (Color1) * (TotalSteps - Index)) + (Blue (Color2) * Index)) / TotalSteps; ColorSet (Color (červená, zelená, modrá)); ukázat(); Přírůstek (); }Běžné obslužné funkce
Nyní přidáme několik běžných obslužných funkcí, které lze použít v jakémkoli vzoru:
Nejprve máme funkce Red (), Blue () a Green (). Jsou inverzní funkcí funkce Neopixel Color (). Umožňují extrahovat červené, modré a zelené prvky z barvy pixelu.
// Vrátí červenou složku 32bitové barvy uint8_t červená (barva uint32_t) { návrat (barva >> 16) & 0xFF; } // Vrátí zelenou složku 32bitové barvy uint8_t Zelená (barva uint32_t) { návrat (barva >> 8) & 0xFF; } // Vrátí modrou složku 32bitové barvy uint8_t modrá (barva uint32_t) { návratová barva & 0xFF; }Funkce DimColor () používá funkce Red (), Green () a Blue () k oddělení barvy a její transformaci do tlumené verze. Posune červené, zelené a modré prvky barvy pixelu o jeden bit doprava - efektivně je rozdělí na 2. Červená, zelená a modrá po 8. volání „vyprší“, protože jde o 8bitové hodnoty.
Tato funkce se používá k vytvoření efektu pruhu blednutí ve vzoru skeneru.
// Vrátit barvu, ztlumenou o 75% (použitou skenerem) uint32_t DimColor (barva uint32_t) { uint32_t dimColor = Barva (červená (barva) >> 1, zelená (barva) >> 1, modrá (barva) >> 1); vrátit dimColor; }Další funkcí je Wheel () použitý ve vzoru RainbowCycle. Je převzat z příkladu StrandTest.
// Zadáním hodnoty 0 až 255 získáte barevnou hodnotu. // Barvy jsou přechodem r - g - b - zpět do r. uint32_t Wheel (byte WheelPos) { WheelPos = 255 - WheelPos; pokud (WheelPos <85) { návratová barva (255 - WheelPos * 3, 0, WheelPos * 3); } jinak pokud (WheelPos <170) { WheelPos - = 85; návratová barva (0, WheelPos * 3, 255 - WheelPos * 3); } jiný { WheelPos - = 170; návratová barva (WheelPos * 3, 255 - WheelPos * 3, 0); } }Zpět () obrátí směr vzoru.
// Opačný směr vzoru void Reverse () { if (Směr == DOPŘED) { Směr = ZPĚT; Index = TotalSteps-1; } jiný { Směr = Vpřed; Index = 0; } }Nakonec máme funkci ColorSet (), která synchronně nastaví všechny pixely na stejnou barvu. Používá ho Fader Pattern.
// Nastaví všechny pixely na barvu (synchronně) void ColorSet (uint32_t color) { pro (int i = 0; iSpojení
Ukázkový kód v této příručce byl vyvinut s použitím 16 a 24 pixelových obručí a 16 pixelových proužků (ve skutečnosti dvojice pásů Neopixel) připojených ke 3 samostatným pinům Arduino, jak je znázorněno na obrázku níže.
Tlačítka jsou připojena k pinům 8 a 9, aby demonstrovala odezvu na uživatelské vstupy.
Používání NeoPatterns
Prohlásit NeoPatterns
Než začneme, musíme deklarovat několik objektů NeoPattern pro ovládání našich pixelů.
Pomocí schémat zapojení z předchozího odstavce inicializujeme 16-pixelový a 24-pixelový rámeček a 16-pixelový pás složený ze dvou 8-pixelových pruhů .
// Definujte několik NeoPatternů pro dva kroužky a páku // a předat adderess přidružených dokončovacích rutin NeoPatterns Ring1 (24, 5, NEO_GRB + NEO_KHZ800, & Ring1Complete); NeoPatterns Ring2 (16, 6, NEO_GRB + NEO_KHZ800, & Ring2Complete); Stick NeoPatterns (16, 7, NEO_GRB + NEO_KHZ800, & StickComplete);Začněme
Stejně jako u pásů NeoPixel musíme před použitím pásů zavolat funkci begin (), která vše inicializuje. Také nastavíme dvojici vstupních pinů pro naše tlačítka a začneme počáteční vzor pro každý proužek.
// Inicializujte vše a připravte se na spuštění neplatné nastavení () { // Inicializujte všechny pixelové proužky Ring1.begin (); Ring2.begin (); Stick.begin (); // Povolit interní pullupy na vstupech přepínače pinMode (8, INPUT_PULLUP); pinMode (9, INPUT_PULLUP); // Kick off a pattern Ring1.TheaterChase (Ring1.Color (255 255,0), Ring1.Color (0,0,50), 100); Ring2.RainbowCycle (3); Ring2.Color1 = Ring1.Color1; Stick.Scanner (Ring1.Color (255.0.0), 55); }Aktualizace vzorů
Chcete-li, aby věci šly podle vás, musíte pravidelně volat funkci Update () na každém NeoPattern. To lze provést ve funkci loop (), jak jsme ukázali, nebo v obslužném programu přerušení časovače, jak jsme představili v části 2 . To je možné, protože jsme ze vzorů odstranili vnitřní smyčky a zpoždění.
Bylo by nejjednodušší vyvolat aktualizaci funkcí pro každý NeoPatterns, který jste zadali.
// Hlavní smyčka neplatná smyčka () { // Aktualizace zvonění. Ring1.Update (); Ring2.Update (); Stick.Update (); }Interakce uživatelů
Bez vnitřních smyček váš kód stále reaguje na jakoukoli interakci uživatele nebo na externí události. Na základě těchto událostí můžete také okamžitě změnit vzory a barvy.
Aby to bylo zajímavější, použijeme tuto schopnost a rozšíříme naši smyčku, abychom reagovali na stisknutí tlačítka na obou tlačítkách:Stisknutím tlačítka # 1 (pin 8):
- změní vzor Ring1 z THEATER_CHASE na FADE
- změní rychlost RainbowCycle na Ring2
- zčervená lišta
Stisknutím tlačítka # 2 (pin 9):
změní vzor Ring1 z THEATER_CHASE na COLOR_WIPE
změní vzor Ring2 z THEATER_CHASE na COLOR_WIPE
Pokud není stisknuto žádné tlačítko, všechny vzory pokračují standardně.
// Hlavní smyčka neplatná smyčka () { // Aktualizace zvonění. Ring1.Update (); Ring2.Update (); // Přepnutí vzorů na stisknutí tlačítka: if (digitalRead (8) == LOW) // Tlačítko č. 1 stisknuto {// Přepnutí Ring1 na FASE pattern Ring1.ActivePattern = FADE; Ring1.Interval = 20; // Zrychlete duhu na Ring2 Ring2.Interval = 0; // Nastavit stick na všechny červené Stick.ColorSet (Stick.Color (255, 0, 0)); } else if (digitalRead (9) == LOW) // Tlačítko č. 2 stisknuto {// Přepnutí na střídavé barevné ubrousky na prstenech 1 a 2 Ring1.ActivePattern = COLOR_WIPE; Ring2.ActivePattern = COLOR_WIPE; Ring2.TotalSteps = Ring2.numPixels (); // A aktualizuj tbe stick Stick.Update (); } else // Zpět na normální provoz {// Obnovit všechny parametry vzoru na normální hodnoty Ring1.ActivePattern = THEATER_CHASE; Ring1.Interval = 100; Ring2.ActivePattern = RAINBOW_CYCLE; Ring2.TotalSteps = 255; Ring2.Interval = min (10, Ring2.Interval); // A aktualizuj tbe stick Stick.Update (); }}Dokončení zpětných volání
Každý vzor, ponechaný sám sobě, se bude opakovat znovu a znovu. Volitelné ukončení zpětného volání vám dá možnost provádět některé akce na konci každého cyklu vzoru.
Akce provedená na konci zpětného volání může změnit některé aspekty vzoru nebo spustit některé externí události.Zpětná volání Ring1 dokončena
Dokončení zpětných volání Ring1 ovlivňuje činnost Ring1 a Ring2. Zdůrazňuje tlačítko # 2. Pokud je stisknuto, pak:
zrychlí Ring2 snížením jeho intervalu. Tím se efektivně „probudí“.
zpomalí Ring1 a zvýší jeho interval. To ji účinně uspí.
vybere náhodnou barvu z kruhu pro další verzi vzoru Ring1.
Pokud není stisknuto žádné tlačítko, změní se pouze směr standardního vzoru.// Ring1 Dokončení zpětného volání void Ring1Complete () { if (digitalRead (9) == LOW) // Tlačítko č. 2 stisknuto { // Alternativní barevné stírací vzory s Ring2 Ring2.Interval = 40; Ring1.Color1 = Ring1.Wheel (random (255)); Ring1.Interval = 20000; } else // Retrn do normálu { Ring1.Reverse (); } }Zpětná volání Ring2 byla dokončena
Dokončení zpětných volání Ring2 dokončí dokončení zpětných volání Ring1.
Pokud je stisknuto tlačítko # 2, pak:
urychlí Ring1 snížením jeho intervalu. Tím se efektivně „probudí“.
zpomalí Ring2 a zvýší jeho interval. To ji účinně uspí.
vybere náhodnou barvu z kruhu pro další verzi vzoru Ring2.
Pokud tlačítko není stisknuto, jednoduše vybere náhodnou rychlost k další revizi standardního vzoru RainbowCycle Ring2.// Ring 2 Complete Callback void Ring2Complete () { if (digitalRead (9) == LOW) // Tlačítko č. 2 stisknuto { // Alternativní barevné stírací vzory s Ring1 Ring1.Interval = 20; Ring2.Color1 = Ring2.Wheel (random (255)); Ring2.Interval = 20000; } else // Retrn do normálu { Ring2.RainbowCycle (random (0,10)); } }Dokončení zpětných volání baru
Dokončení zpětných volání pruhu vybere náhodnou barvu z kruhu pro další průchod skenovacího vzoru.
// Zpětné zavolání dokončení Stick void StickComplete () { // Náhodná změna barvy pro další skenování Stick.Color1 = Stick.Wheel (náhodný (255)); }Nyní to všechno spojte
Následující kód obsahuje kompletní třídu NeoPattern spolu s některými ukázkovými kódy ve formě náčrtu Arduino. Zkopírujte a vložte tento kód do IDE a připojte své pixely, jak je znázorněno ve schématu připojení.
#include// Podporované typy vzorů: vzor výčtu {NONE, RAINBOW_CYCLE, THEATER_CHASE, COLOR_WIPE, SCANNER, FADE}; // Podporovány směry otcovy strany: enum direction {FORWARD, ZVRÁTIT}; // Třída NeoPattern - odvozeno od třídy třídy Adafruit_NeoPixel NeoPatterns: veřejné Adafruit_NeoPixel {veřejné: // Členské proměnné: vzor ActivePattern; // který vzor běží ve směru Směr; // směr spuštění vzoru bez znaménka dlouhý Interval; // milisekundy mezi aktualizacemi nepodepsané long lastUpdate; // poslední aktualizace pozice uint32_t Color1, Color2; // Jaké barvy se používají uint16_t TotalSteps; // celkový počet kroků ve vzoru uint16_t Index; // aktuální krok v rámci vzoru void (* OnComplete) (); // Zpětné volání po dokončení vzoru // Konstruktor - zavolá konstruktor základní třídy k inicializaci pruhu NeoPatterns (uint16_t pixely, uint8_t pin, uint8_t typ, void (* callback) ()): Adafruit_NeoPixel (pixely, pin, typ) {OnComplete = zpětné volání; } // Aktualizace vzoru void Update () {if ((millis () - lastUpdate)> Interval) // čas aktualizace {lastUpdate = millis (); switch (ActivePattern) {case RAINBOW_CYCLE: RainbowCycleUpdate (); přestávka; případ THEATRE_CHASE: TheaterChaseUpdate (); přestávka; případ COLOR_WIPE: ColorWipeUpdate (); přestávka; případ SKENER: ScannerUpdate (); přestávka; případ FADE: FadeUpdate (); přestávka; výchozí: konec; }}} // Zvýšení indexu a vynulování na konci void Increment () {if (Direction == FORWARD) {Index ++; if (Index> = TotalSteps) {Index = 0; if (OnComplete! = NULL) {OnComplete (); // zavolá zpětné volání soutěže}}} else // Směr == REVERSE {--Index; if (Index <= 0) {Index = TotalSteps-1; if (OnComplete! = NULL) {OnComplete (); // zavolá zpětné volání soutěže}}}} // Obrátit směr vzoru void Obrátit () {if (Směr == DOPŘED) {Směr = ZPĚT; Index = TotalSteps-1; } else {Směr = Vpřed; Index = 0; }} // Inicializace pro RainbowCycle void RainbowCycle (interval uint8_t, směr dir = FORWARD) {ActivePattern = RAINBOW_CYCLE; Interval = interval; TotalSteps = 255; Index = 0; Směr = dir; } // Aktualizace vzoru duhového cyklu void RainbowCycleUpdate () {for (int i = 0; i > 1, Zelená (barva) >> 1, Modrá (barva) >> 1); vrátit dimColor; } // Nastavit všechny pixely na barvu (synchronně) void ColorSet (uint32_t color) {for (int i = 0; i > 16) & 0xFF; } // Vrátí zelenou složku 32bitové barvy uint8_t Zelená (barva uint32_t) {návrat (barva >> 8) & 0xFF; } // Vrací modrou složku 32bitové barvy uint8_t Blue (barva uint32_t) {return color & 0xFF; } // Zadáním hodnoty 0 až 255 získáte barevnou hodnotu. // Barvy jsou přechodem r - g - b - zpět do r. Uint32_t Wheel (byte WheelPos) {WheelPos = 255 - WheelPos; if (WheelPos <85) {return Color (255 - WheelPos * 3, 0, WheelPos * 3); } else if (WheelPos <170) {WheelPos - = 85; návratová barva (0, WheelPos * 3, 255 - WheelPos * 3); } else {WheelPos - = 170; návratová barva (WheelPos * 3, 255 - WheelPos * 3, 0); }}}; void Ring1Complete (); void Ring2Complete (); void StickComplete (); // Definujte některé NeoPatterns pro dva kroužky a páku // a také některé dokončovací rutiny NeoPatterns Ring1 (24, 5, NEO_GRB + NEO_KHZ800, & Ring1Complete); NeoPatterns Ring2 (16, 6, NEO_GRB + NEO_KHZ800, & Ring2Complete); Stick NeoPatterns (16, 7, NEO_GRB + NEO_KHZ800, & StickComplete); // Inicializujte vše a připravte se na spuštění void setup () {Serial.begin (115200); pinMode (8, INPUT_PULLUP); pinMode (9, INPUT_PULLUP); // Inicializace všech pixelStrips Ring1.begin (); Ring2.begin (); Stick.begin (); // Kick off a pattern Ring1.TheaterChase (Ring1.Color (255,255,0), Ring1.Color (0,0,50), 100); Ring2.RainbowCycle (3); Ring2.Color1 = Ring1.Color1; Stick.Scanner (Ring1.Color (255.0.0), 55); } // Main loop void loop () {// Aktualizujte vyzvánění. Ring1.Update (); Ring2.Update (); // Přepnutí vzorů na stisknutí tlačítka: if (digitalRead (8) == LOW) // Tlačítko č. 1 stisknuto {// Přepnutí Ring1 na FADE pattern Ring1.ActivePattern = FADE; Ring1.Interval = 20; // Zrychlete duhu na Ring2 Ring2.Interval = 0; // Nastavit stick na všechny červené Stick.ColorSet (Stick.Color (255, 0, 0)); } else if (digitalRead (9) == LOW) // Tlačítko č. 2 stisknuto {// Přepnutí na střídavé barevné ubrousky na prstenech 1 a 2 Ring1.ActivePattern = COLOR_WIPE; Ring2.ActivePattern = COLOR_WIPE; Ring2.TotalSteps = Ring2.numPixels (); // A aktualizuj tbe stick Stick.Update (); } else // Zpět na normální provoz {// Obnovit všechny parametry vzoru na normální hodnoty Ring1.ActivePattern = THEATER_CHASE; Ring1.Interval = 100; Ring2.ActivePattern = RAINBOW_CYCLE; Ring2.TotalSteps = 255; Ring2. Interval = min (10, Ring2.Interval); // A aktualizuj tbe stick Stick.Update (); }} // ---------------------------------------------- -------------- // Rutiny dokončení - zavolání po dokončení vzoru // ---------------------- -------------------------------------- // Dokončení Ring1 Callback void Ring1Complete () {if ( digitalRead (9) == LOW) // Tlačítko č. 2 stisknuto {// Alternativní barevné stírání vzorků s Ring2 Ring2.Interval = 40; Ring1.Color1 = Ring1.Wheel (random (255)); Ring1.Interval = 20000; } else // Obnovit normální {Ring1.Reverse (); }} // Dokončení zpětného volání Ring 2 void Ring2Complete () {if (digitalRead (9) == LOW) // Tlačítko č. 2 stisknuto {// Alternativní vzory stírání barev s Ring1 Ring1.Interval = 20; Ring2.Color1 = Ring2.Wheel (random (255)); Ring2.Interval = 20000; } else // Obnovit normální {Ring2.RainbowCycle (random (0,10)); }} // Zpětné volání dokončení Stick void StickComplete () {// Náhodná změna barvy pro další skenování Stick.Color1 = Stick.Wheel (random (255)); } Zdroj: https://learn.adafruit.com/multi-tasking-the-arduino-part-3