To je právě případ té kolize. Sám AccelStepper funguje dobře i s více motory, protože s tím autor knihovny počítal a s vědomím, že je v Arduinu sám, to napsal tak, že to funguje. Ale v jednoduché (přímočaré) kombinaci s něčím dalším, co zdržuje, už ne. Ono není divu: v dokumentaci pro funkci
run
se píše:
You must call this as frequently as possible, but at least once per minimum step time interval, preferably in your main loop. Note that each call to run() will make at most one step, and then only when a step is due, based on the current speed and the time since the last step.
přičemž obě dvě věty jsou důležité. S tím displejem zjevně dochází k tomu, že příští zavolání
stepper.run()
nastane až tak pozdě, že si i člověk všimne zacukání. Třeba.
AccelStepper to dělá tak, že s každým zavoláním
run()
zjistí, jestli od minulého kroku uplynul aspoň čas spočítaný při posledním kroku podle rychlosti a nastaveného zrychlení, pokud ne, nic nedělá, pokud ano, udělá právě jeden krok a spočte, za jak dlouho má zase udělat. Čili aby to bylo plynulé, musí se všechno ostatní v aplikaci (zde výpis na displej) v tomhle čase stihnout a to včetně režie vlastního Arduina. To vše bez použití přerušení. Jakmile se k tomu přidá něco dalšího, co může principiálně trvat dlouho, tak mezi dvěma zavoláními
stepper.run()
uplyne víc času, než by mělo a když to udělá ten jeden krok, tak ten bude trvat déle, než měl.
Pokud se to má opravit, je potřeba do toho hrábnout tak, aby:
1. se kroky prováděné AccelStepperem neřídily co nejčastějším voláním
run()
a testováním, jestli už je čas na krok, ale hodinami (budíkem), který se nastaví na čas, kdy se má udělat další krok
2. jakákoli další činnost v aplikaci nezakazovala přerušení (nebo jen na dobu opravdu nezbytně dlouhou k přijetí události, její vyřízení pak musí být už s přerušeními povolenými). Když nebude ovlivňovat to přerušení, tak pak nebude vadit, když by trvala dlouho, protože ji třeba přeruší ten budíček od motorů, ale pak se to po obsloužení motoru zas vrátí do téhle činnosti tam, kde se přerušila
3. vykonání obsluhy přerušení pro budík na krok krokáče nebylo tak dlouhé, že by ovlivnilo nepříznivě tu činnost v 2. nebo dokonce nebylo tak dlouhé, že by mezitím už byl čas na další budík.
ad 1 - to bych si já asi napsal sám, ale chápu, že hrabat se v cizích knihovnách není snadné, takže bych na Vašem místě zkusil najít, kdo to už udělal před náma, třeba
iAccelStepper.
ad 2 - tohle záleží na tom, jak se bude s displejem komunikovat. Bacha na SoftwareSerial, ten používá přerušení PCINT0-3 a v rámci obsluhy při příjmu se v něm zdrží a při odesílání zakazuje přerušení ("turn off interrupts for a clean txmit") přičemž to posílání po seriové lince je opravdu pomalé. Bacha na Serial (=HardwareSerial), ten dělá to bufferování jak jsem psal před časem a navíc pro vyřizování bufferu používá přerušení od USARTu (naštěstí ještě docela rozumně). Bacha na SPI, i2c, KZR, PZR a další, nevím sice konkrétně, jak je pro Arduino implementované, ale cosi mi říká, že tam budou podobné nabíhačky.
ad 3 - tady by mohlo nastat, že kvůli přerušení od budíku krokáče nebude komunikace s displejem na plynulá a rozsype se (tj. displej to přestane dobře přijímat). Tím by vzniknul začarovaný kruh, jehož rozetnutí by zřejmě už vyžadovalo gilhadem zmíněný postup zapomenout na Arduino a napsati si to celé sám ...
Ještě abych se ujistil, že ten projekt chápu dobře:
Kód je z příkladu "Bounce"?
Driver pro krokáč je ovládaný dvěma signály a je připojený na piny 4 (step) a 7 (direction)? (správněji by měl být konstruktor volaný místo s jedničkou s hodnotou
AccelStepper::DRIVER
z příslušného výčtového typu)
Driver krokuje na náběžnou hranu signálu step?