Küsimus:
Kuidas lenduvaid muutujaid Arduinos õigesti kasutada?
daltonfury42
2015-12-17 00:00:53 UTC
view on stackexchange narkive permalink

Tegin Arduino Unoga väikest projekti. See hõlmas katkestusi, kuna kasutan koodereid, et mõõta, kui palju diferentsiaalrataste süsteem edasi liigub. Minu robot liigub ainult edasi. Nii et ma kasutan igast kooderist ainult ühte kanalit. Siin on minu kaks katkestamise rutiini:

  ISR (INT0_vect) {encoderRPos = encoderRPos + 1; } ISR (INT1_vect) {encoderLPos = encoderLPos + 1;}  

Muutujad encoderRPos ja encoderLPos on tüüpi kõikuvad int . Saan aru, et muutujad, mis läbivad muutusi mis tahes katkestusrutiinis, peavad olema tüübilt kõikuvad. Selle eesmärk on hoiatada neid muutujaid kasutavaid koodi teisi osi, et see võib igal ajal muutuda.

Kuid minu koodis toimunu oli natuke kummaline ja ma ei suutnud seda seletada. Vasakpoolse ratta abil liigutatud kauguse arvutamiseks toimige järgmiselt.

  #define distancePerCount 0.056196868 float SR = distancePerCount * (encoderRPos - encoderRPosPrev); ujuk SL = distancePerCount * (kooderLPos - kooderLPosPrev); kooderRPosPrev = kooderRPos; encoderLPosPrev = encoderLPos;  

Kuid kui jadamonitorile printin järgmise, märkan kõrvalekaldeid:

enter image description here

Kui vaadata kolmandat veergu, on (SL) selle väärtus mõnda aega liiga kõrge. See häirib kõiki minu arvutusi.

Ainus vihje, mille saan, kui võtan saadud SL väärtuse (3682), mis on alati konstant, ja arvutan tagasi (encodeLPos - encoderLPosPrev) , Saan 65519,66, mis on lähedal unsigned int maksimaalsele väärtusele. Mis tähendab, et (encoderLPos - encoderLPosPrev) põhjustab ülevoolu, samas kui mõlemad väärtused, mille erinevus võetakse, on ainult kuskil 5000!

Ja mul õnnestus see lahendada. See oli õnneks. Nii muutsin koodi:

  static int encoderRPosPrev = 0; staatiline int kodeerijaLPosPrev = 0; int diffL = (kooderLPos - kooderLPosPrev);
int diffR = (kooderRPos - kooderRPosPrev); ujuk SR = distancePerCount * diffR; ujuk SL = distancePerCount * diffL; kooderRPosPrev = kooderRPos; encoderLPosPrev = encoderLPos;  

Ma ei saa juhtunust aru. Kas lenduvate muutujate kohta oleksin midagi teada pidanud?

Värskenda: siin on kogu kood, kui soovite kunagi pilgu heita. Ja see töötab väga hästi pärast selle muutmist vastuvõetud vastuses pakutuks.

Teie küsimus ütleb, mis on väljundi kolmas veerg ... millised on muud veerud? Muutke küsimust ja lisage veerupäised
@jwpat7 eemaldasin need tahtlikult, sest see ajab lugeja ainult segadusse. Kuid küsimusele on Majenko juba hästi vastanud.
Juppidest on raske üksikasjalikke vastuseid anda. "kas saaksite selgitada, miks see ei juhtu juhuslikult, vaid iga kord, kui koodi käin Samuti, miks see annab konkreetse väärtuse? - Ma saaksin seda ilmselt teha, kui näeksin kogu koodi. Vahepeal lugege seda: http://www.gammon.com.au/interrupts
@NickGammon Siin sa lähed: http://paste.ubuntu.com/14085127/
"3683 / .056196868 = 65537", nii et tundub, et see kasvas valel hetkel, jah? Juurdepääs muutujale, mida selles koodis võib katkestuse käigus mitu korda muuta, seega oleks kohaliku koopia hankimine ajal, mil katkestused on välja lülitatud, palju turvalisem.
@NickGammon Jah, sellega ma lõpuks ka tegelesin.
üks vastus:
Majenko
2015-12-17 00:08:37 UTC
view on stackexchange narkive permalink

Peate õppima kriitiliste jaotiste kohta.

Tõenäoliselt juhtub see, et katkestuste rutiinid muudavad muutujaid arvutuste keskel. Teie „parandus“ vähendab lenduvate muutujatega arvutamiseks kuluvat aega, vähendades kokkupõrke tõenäosust.

Peaksite lenduvad muutujad kopeerima kohalikesse muutujatesse, mille katkestused on selleks keelatud. lühike periood.

  cli (); int l = encoderLpos; int r = encoderRpos; sei ();  

Kuna Arduino on 8-bitine protsessor matemaatiliste toimingute sooritamiseks 16-bitiste väärtustega kulub mitu monteerimisjuhist. Ujuv punkt on veelgi hullem, kasutades lihtsaks lisamiseks paljusid palju juhiseid. Jagamine ja korrutamine kasutavad oluliselt rohkem. Katkestusel on selle juhiste loendi ajal palju võimalusi tulistada. Tehes sellist ülesannet ja kasutades seejärel oma arvutustes uusi kohalikke muutujaid, on lenduvate muutujatega tegelemiseks vajalikud juhised absoluutse miinimumini. Lülitades katkestused ülesande ajal garanteerite, et muutujaid ei saa nende kasutamise ajal kunagi muuta. Seda koodijuppi nimetatakse kriitiliseks jaotiseks .

See võib lihtsalt nii olla. Lihtsalt mõtlesin, kas saaksite selgitada, miks see ei juhtu juhuslikult, vaid iga kord, kui koodi käivitan? Samuti, miks see annab konkreetse väärtuse?
Siin on suurepärane viide kliendile / seile. http://www.nongnu.org/avr-libc/user-manual/optimization.html#optim_code_reorder. Mälutõkke korral pole ülaltoodud koodis lenduvat deklaratsiooni tegelikult vaja. Siin on mõnus lugemine sellel teemal. https://www.kernel.org/doc/Documentation/volatile-considered-harmful.txt
@MikaelPatel kena, kuid mitte MCU-de jaoks asjakohane. Selles olukorras on vaja kõikuvat, et kompilaator ei saaks optimeerida juhtumeid, kus ta arvab, et seda ei kasutata (väärtus ei muutu kunagi). Cli / sei on selleks, et muuta operatsioon aatomi WRT-ks ainsaks teisteks teostatavateks lõimideks (katkestusteks).
Kas proovisite koodi kompileerida nii volatiilse kui ka ilma? Kuid kriitilise sektsiooniga (cli / sei). Mida ma püüan arutada, on mälutõkke mõiste ja see, kuidas see tagab kompilaatorilt kõikuva juurdepääsu (ja korrektse järjestuse) muutujate volatiilseks kuulutamisega. Enamikule programmeerijatest õpetatakse, et kõik ISR-i juurde kuuluvad muutujad tuleb kuulutada kõikuvateks, kuid selles loos on palju muud.
Ma ei usu, et kompilaatoril on palju ideid selle kohta, mida cli () ja sei () teevad ja kuidas see mõjutaks selliseid asju nagu optimeerimine muutujatest, mida ei tohiks optimeerida. Kõik sei () ja cli () teevad manipuleerimist oma registris oleva globaalse katkestuse lubamise lipuga. Nad ei tee koodivoo jaoks midagi.
Lõppude lõpuks kaardistavad nad lihtsalt monteerimisjuhise: "# define sei () __asm__ __volatile__ (" sei ":::" memory ")"
See on maagiline sõna "mälu", mis ütleb koostajale, et see on ka mälutõke. https://gcc.gnu.org/onlinedocs/gcc/Volatiles.html
See peatab käskude ümberkorraldamise. Sellel pole kahtlustatavat surnud koodi täielikku eemaldamist.
@MikaelPatel Siin on üks äärmuslik näide (äärmuslik, nii et see sunnib sellist optimeerimist nagu ma olen pärast demonstreerimist): http://pastebin.com/u9bfiN4R
@Majenko See oli äärmuslik näide. Kas proovisite nii lenduvaid kui ka cli / sei? Vastunäide on Cosa / RTT https://github.com/mikaelpatel/Cosa/blob/master/cores/cosa/Cosa/RTT.cpp, sellel pole kõikuvat. Selle asemel sünkroonitakse kõik juurdepääsud.


See küsimus ja vastus tõlgiti automaatselt inglise keelest.Algne sisu on saadaval stackexchange-is, mida täname cc by-sa 3.0-litsentsi eest, mille all seda levitatakse.
Loading...