Szia,
Nézzük sorban. Köszönöm az elismerést. :-)
A kód az abszolút mezitlábas minimum és alapvetően az elvek bemutatásán túl igazából semmilyen sztenderdnek nem felel meg, mert nem kezel különleges helyzeteket, illetve nincsenek benne olyan funkciók, hogy pl. a prellt kivédje. Ez egy kicsit komplikáltabb, pár nap múlva lesz róla film.
Ha a filmben említett 2-es fázisban szempont a gomb figyelése, akkor teljesen más eljárás szerint kell megcsinálni, mert itt elágazás kerül a kódba. A 2-es fázisból vissza tud menni az 1-es fázisba is. Ennek a kiváltó eseménye az 1-es gomb megnyomása. Emiatt a 2-es állapothoz hozzá kell rendelni két, párhuzamosan futó vizsgálatot: az idő leteltét és a gomb1 benyomását. Ha akkor ebből az állapotból az idő letelte triggereli ki a gépet, akkor a 0 állapotba, ha a gomb megnyomása, akkor az 1 állapotba kerül. Több lehetséges módon lehet implementálni, mindegyiknek van előnye és hátránya, de szerencsére delay() ezekhez sem kell. Például:
https://create.arduino.cc/editor/Timtomm/36b9aa7e-1432-4933-8e0a-4c1c9989ec38/preview
Itt már azért észnél kell lenni, hogy mit és hogyan figyelünk, mert ha pl. az állapot vizsgálatát kifelejtjük (bízva abban, hogy a while úgyis kiléptet), akkor bajban leszünk, mert úgy is kikapcsoljuk a 2-es relét, hogy azt nem kellene.
A delay() használata ilyen hosszú távú kivárásokra teljesen indolokatlan, sőt, alapvetően káros, ezt elmondtam a filmben. Rövidebb kivárásokat (ahogy itt lent javasolták), pl. a prellből fakadó nemkívánatos események elkerülésére lehet használni, de csak ügyes programszervezéssel (bár ezt is inkább hardveresen érdemes megoldani).
A 2-es gomb figyelése egy teljesen másik irány. Tisztázni kell, hogy mikor fordulhat elő, hogy valaki megnyomja, milyen befolyása van arra, hogy az 1-es gomb be van-e nyomva, illetve milyen befolyása van az állapotokra. Ki lehet-e lépni abból a szekvenciából, amit a 2-es gomb megnyomása indít, illetve az pontosan mikor (a megnyomáskor vagy az elengedéskor) indul-e.
Alapszabályként:
-- minden állapotban csak azt vizsgáljuk, ami az állapotból való kilépést indukálhatja. A példában ez csak az 1-es gomb vagy az idő lejárta volt, de ahogy komplikálódik a helyzet, más is lehet (1-es gomb ÉS az idő együtt, 2-es gomb stb.),
-- delay()-t csak néhány esetben érdemes használni (lásd a korábbi példát erre a prellmentesítésnél),
-- egy bizonyos bonyolultságon túl a sok-sok egymásba ágyazott feltétel elkerülésére érdemes szétválasztani és saját beágyazott függvénybe kiszervezni magát az állapotváltozáshoz kapcsolódó cselekményt (pl. a relék behúzását vagy elengedését), a loop-ban pedig kizárólag az állapotváltozások triggereinek ellenőrzését bennehagyni (abból is csak a legkevesebbet),
-- az elágazások kezeléséhez több lehetséges eljárás van (elágazáskezelés), a while zárt ciklus, a do/while elöl nyitott ciklus, az if egyedi elágazás, a switch/case többpontos strukturált ellenőrzés, mindegyiknek más előnye és hátránya van,
-- alapvetően időkritikus bemenet-érzékeléshez megszakítást használunk, ami aztán az egészet alapjaiban átstrukturálja, mert teljesen jelentősen más logika mentén kell kezelni, ekkor be tud jönni a kvázi többszálúság, sőt, az is, hogy pl. idővezérelt megszakítással váltsunk bizonyos állapotok között. Ezzel létrehozható kvázi multitasking is, mert az MCU végzi a maga dolgát (valamit), és a gombnyomásokhoz kapcsolódó állapotváltozásokkor csak az ahhoz tartozó változtatást csinálja meg egy második állapotgépben, ami aztán újabb külső (gombnyomás) vagy belső (lejáró idő) interruptok alapján teszi a dolgát. A delay() és egy belső interrupt között annyi a differencia, hogy a delay() alatt még akkor sem tudsz semmit csinálni, ha szeretnél, a belső idővezérelt interrupttal viszont azt csinálsz, amit csak akarsz. Erre az Atmega328p elfogadhatóan alkalmas, de nem az Arduino keretrendszerben.