Optimalizálja a digitalwrite arduino, robotosha

Optimalizálja a digitalWrite-et az Arduino-n

Optimalizálja a digitalwrite arduino, robotosha

Ma megpróbálom tesztelni a digitalWrite aktuális sebességét az Arduino Mega2560-on, és megmondom, hogyan lehet felgyorsítani a programot 50-szer! Az Arduino Mega2560 debug kártya magjában az AT2560 mikrokontroller. 16 MHz-es órajelet használva. Ha ezeket a 16 millió oszcillációt egy időintervallumra fordítjuk, akkor egy meglehetősen kis időszakot kapunk, amely 62,5 ns-nek felel meg. Gyors, de az Arduino ugyanolyan sebességgel végez műveleteket? Lássuk.

A parancsok, amelyeket a vezetékezés nyelvén írunk. az összeállítás folyamatában egyszerűbb parancsokká alakulnak át, az úgynevezett gépi kódot, amelyet a mikrokontroller már közvetlenül hajt végre. A mikrokontroller néhány parancsát a mikrokontroller egy órai ciklusában hajtják végre, néhánynak több ciklusra és végrehajtási időre van szükségük. Ezért véleményünk szerint egy egyszerű parancsot vagy funkciót a mikrokontroller végez néhány, esetleg néhány tíz vagy több száz ciklussal. Ráadásul a számítások mellett olvasási / írási műveletekre van szükség a memóriában, így a parancsfeldolgozás átlagos gyakorisága jelentősen eltér a mikrokontroller órafrekvenciájától. A kérdés az, hogy mennyi.

Próbáljuk kideríteni, mennyi egyszerű parancs az Arduino - digitalWrite digitális kimenet értékének megváltoztatására. Tegyünk néhány kísérletet. Az első kísérletben hajtsa végre a következő kódot.

Ez a kód villog a fedélzeten található LED-ről és csatlakoztatja a 13. tűhöz. Mi csak felváltva változtatjuk meg a kijárat állapotát. Ha futtatjuk ezt a kódot, látni fogjuk, hogy a LED folyamatosan világít, de valójában nem. A LED be- és kikapcsolása csak az, hogy a szemünk nem érzékeli a 25 Hz-nél nagyobb rezgéseket, és ilyen jelenségeket látunk az állandóan égő LED-ként, a jel működési ciklusa által meghatározott fényerővel.

Annak érdekében, hogy lássuk, mi történik a 13. kimeneten, az oszcilloszkópot használom. A 13 pólusú jel oszcillogramja így néz ki:

Optimalizálja a digitalwrite arduino, robotosha

Úgy tűnik, hogy a digitalWrite (13, HIGH) parancs 6,6 μs-ban és a digitalWrite (13, LOW) 7,2 μs-ban kerül végrehajtásra. Összesen 13,8 mikrosekundum. Ez sokkal hosszabb, mint 62,5 ns, sőt, 220-szor hosszabb. Látható továbbá, hogy a LOW állapot (7,2 μs) hosszabb ideig tart, mint a HIGH állapot (6,6 μs).

Tegyük a következő kísérletet.

Ennek a kódvégrehajtásnak köszönhetően a 13 pólusú jel oszcillogramja így néz ki:

Optimalizálja a digitalwrite arduino, robotosha

Az egyetlen HIGH utasítás eléri a 6,8 μs-ot - a várakozásokhoz hasonlóan (6,6 μs). Két egymást követő parancs, amely a kimenetet LOW állapotba helyezi 13,8 μs, valamivel kisebb, mint a várható 14,4 μs (7,2 × 2).

Mit fogsz kapni? Hurokhurokban (). a digitalWrite funkció használatával. legfeljebb 72 kHz frekvenciát változtathatunk meg, és bizonyos esetekben ez a frekvencia például alacsonyabb lehet, mint a második esetben - kb. 37 kHz. Ez a frekvencia sokkal kisebb, mint az óra 16 MHz, de ha időzítő megszakításokat használ. akkor jelentősen növelhetjük ezt a számot.

A vezetékes nyelvben a digitalWrite funkció végrehajtása enyhén szólva nem optimális. Ha megvizsgálja az Assembler implementációját, számos ellenőrzést talál, különösen azt, hogy ellenőrizze, szükséges-e kikapcsolni a PWM időzítőt az előző analóg írási () függvény után. A leggyorsabb megvalósítás, de ugyanakkor a leginkább időigényes írás, az Assemblerben lehet. De az Assemlerre vonatkozó kód írása - még mindig erőszak a magadon. Nem az összeszerelési kód hibakereséséről beszélek. Az egyik kompromisszum lehet olyan optimalizált könyvtárak használata, amelyek különböző I / O funkciókat valósítanak meg. További publikációimban áttekintem néhány ilyen könyvtárat.

A késleltetés másik oka maga a loop () függvény. Ha a hurokban () belül minden parancs végrehajtásra kerül, akkor implicit módon végrehajtunk egy másik kódot, amely visszatér a parancsok végrehajtásához. Ezért a hurok () végén két azonos állapotból származó szekvenciaidõ nem egyenlõ az egyetlen állapotváltás idõtartamainak összegével - itt a mikrokontroller még mindig végrehajt olyan utasításokat, amelyek visszatérnek a ciklus kezdetéhez.

Annak érdekében, hogy csökkentse a kimenet állapotának megváltoztatásához szükséges időt, használhat közvetlen írásparancsokat a portregiszterben. Ha módosítani szeretné a csapok értékek 8-13 használják PORTB regiszter számára, amelybe az adatok írására szó (két legkevésbé szignifikáns bit adat szó, azaz 1 és 2 bit nem használt, és a fennmaradó hat - csak meghatározott állam a digitális portok 8-13) . A digitális pólusok állapotának 0-ról 7-re történő megváltoztatására PORTD-t használunk.

És ismét az oszcilloszkóp segítségéért fordulunk:

Optimalizálja a digitalwrite arduino, robotosha

Mint látható, a frekvencia 4 MHz-ről 1 MHz-re csökkent. A MAGAS állapotban levő tartózkodási idő nem változott, és még mindig 62,5 ns (az oszcillogramon egyszerűen látható, Wid (1)<100.0ns ). Следовательно, остальное время уходит на возврат к началу, и на это уходит в восемь раз больше времени, то есть 8 тактов. Вывод: функция loop не столь уж и эффективна.

Ebben a példában négyszeres sebességnövekedést értünk el, de ez korlátozó eset. Valójában néhány óraszámot mentünk el, és amikor a hurok belsejében lévő kód végrehajtási ideje nő, a programidő csökkentésének hatása jelentősen csökken.

Szóval, hadd foglaljam össze:

  • A digitalWrite helyett a portregiszterek segítségével jelentősen megnövelheti a program sebességét.
  • Egy végtelen hurok használatával, miközben (1) beágyazott a hurokba (), a hurok minden egyes fordulóján el tudunk menteni néhány processzort.

Hogyan értékeli ezt a kiadványt? (64 szavazat, átlag értékelése: 4.86 tól 5)

További információ a témáról

Ez minden bizonnyal jó. Csak ezzel, az arduino munkájának lényege elvész - a kényelem és a távolság a mikrokontroller architektúrájától. Ha gyors és kompakt kódot szeretne írni, akkor biztosan ne írja a vezetékeket. )))))

köszönöm szépen segített. Kíváncsi vagyok, hogyan vezet az arduino miatt ebben az esetben? 84 MHz-es órajelsebességgel.

Elméletileg a program sebessége a 84MHz / 16MHz = 5,25-szoros órajel-frekvencia növekedésével arányosan növekedni fog.

míg a () tényleg működik!

találkozott egy cikken, úgy döntött, hogy ellenőrizni fogja. mivel van egy oszcilloszkóp, azt gondoltam, hogy miért ne, de hadd nézzem.

a kiküldött írások nem működtek (nano v3.1). Nem tudom, hogyan működik a μ, nem találtam a szükséges portot.

de amíg () igazán a különbség kiderült. egy egyszerű példában, ha alacsony alacsony, ha anélkül, addig egy további 290 ns keletkezik. talán nem sok, de még mindig. valószínűleg a hurok () művelet eredménye.

akkor a kérdés az, miért kell egyáltalán?

nem tudta, hogy így egyszerűen lehet megoldani az mk-t (DDRB = B10000000).

köszönöm az ötletet)

Mit csinálunk a vezetékezés nyelvének romlása, amelynek ereje egyszerű. Amikor megpróbáljuk maximalizálni a vezérlő képességek használatát, például a nyilvántartásaival való közvetlen munkát, akkor el kell térni a vezetékezés ideológiájától. Ha teljesítményre van szüksége, akkor jobb, ha tiszta C / C ++-t írsz, és maximalizálod a mikrokontroller architektúrájának jellemzőit.

Huzal nélkül a vázlaton a huzalozás megtagadja a fordítást és hibát okoz.

Nos, az arduino az első lépés a mikroszkópia elsajátításában.

A jövőben az arduino következtetéseinek "térképét" a pins_arduino.h fájlban írjuk le, de számos ilyen fájl létezik, van egy bázis, amely a mappában található

Néhány arduin (Leonardo, mega, micro, stb.) Vannak kivételek számukra, vannak azok a fájlok, amelyek hazudnak

A port neve (PORTA, PORTB.) Meg van adva az állandó tömbben a digital_pin_to_port_PGM

A bitmaszk a digitális_pin_to_bit_mask_PGM tömbben lévő portban (valójában ez a bitszám).

Az index világos a semmiből.

Tehát vegye figyelembe a kimenet számát: 13, nézd meg, mi van

digital_pin_to_bit_mask_PGM [13] = _BV (5)

_BV az AVR csomagban bejelentett makró

#define _BV (bit) (1 <

és csak a zárójelben lévő számra van szükségünk

Kapd el a PortB-t, az 5-ös bit

Szerencsére az eredmények kiderült, hogy majdnem igazak, de csak egy hozzáadással:

„Mi lehet menteni néhány ciklusban a processzor minden szakaszában a munka ciklus segítségével beágyazott a loop () végtelen ciklus while (1)”, de akkor el fogja veszíteni, mi tesz minket funkció serialEvent. Nevezetesen a soros portokon lévő bemeneti adatok feldolgozása leáll.

Egy másik lehetőség az, hogy lehetővé tegyük a fúziónak, hogy az órajelet a kimenetre küldje, a 16 MHz-et pedig azonnal megkapja a hardver.

Az érdekes megoldásból egy RC órajelet generálhat egy lánccal, és programozhatóan változtathatja meg a frekvenciát a frekvencia korrekció rögzítésével. Ha a külső RC lánc megváltoztatja az RC vagy a tápfeszültség paramétereit, akkor egy olyan frekvencia-generátort kapunk, amely simán változik és pontosan önkalibrálódik legalább a kvarcból másodpercenként, még a GPS-műholdakból is.

A cikket frissíteni kell. az idő megy. változtatásokat hajtanak végre. A cikk közzététele után 3 évig tartott. kód

digitalWrite (13, HIGH);

digitalWrite (13, LOW);

gyorsabb. a teljes idő kb. 7 nsec, a frekvencia kb. 150 kHz. (IDE 1.8.1, UNO R3 328 16 MHz).

és igen. mint fent említettük - a közvetlen regiszter parancs parancskódja nem működik.