Kérdés:
Meg tudná valaki magyarázni ezt a furcsa kinézetű kódot, amelyet az időzítők beállításához használtak?
The Guy with The Hat
2014-02-24 08:06:06 UTC
view on stackexchange narkive permalink

A mások által írt vázlatok megtekintése közben időnként találkozom valamennyire így néző kóddal:

  TCCR1A = 0; TCCR1B = 0; TCNT1 = 34286; TCCR1B | = (1 << CS12); TIMSK1 | = (1 << TOIE1);  

Csak annyit tudok, hogy van valami az időzítéssel / időzítőkkel (szerintem). Hogyan tudom megfejteni - és létrehozni - az ilyen kódot? Mik a TCCR1A , TCCR1B , TCNT1 , CS12 , TIMSK1 és TOIE1 ?

Nem tudok elég választ adni, de: http://electronics.stackexchange.com/questions/92350/what-is-the-difference-between-tccr1a-and-tccr1b között, .php? topic = 134602.0, és http://stackoverflow.com/questions/9475482/pulse-width-modulation-pwm-on-avr-studio. Nem tudom, láttad-e ezeket már.
Töltse le eszközének „Teljes” adatlapját az [Atmel webhelyről] (http://atmel.com/), és olvassa el az időzítőkről szóló fejezeteket. Az adatlap véleményem szerint meglepően jó olvasni.
Három válaszokat:
Connor Wolf
2014-02-24 09:54:06 UTC
view on stackexchange narkive permalink

Ez nem furcsa kinézetű. Így néz ki valójában a normál MCU-kód.

Amit itt talál, az példa a memória-leképezett perifériák fogalmára. Alapvetően az MCU hardver speciális helyekkel rendelkezik az ahhoz rendelt MCU SRAM címterében. Ha ezekre a címekre ír, a címre írt bájt bitjei n vezérlik a periférikus m viselkedését.

Alapvetően bizonyos memóriabankokban szó szerint kevés vezeték fut az SRAM cellától a hardverig. Ha "1" -et ír erre a bitre abban a bájtban, akkor ez az SRAM cellát logikai magasra állítja, majd bekapcsolja a hardver egy részét.

Ha megnézi az MCU fejlécét , nagy nagy táblázatok vannak a keyword<-> cím leképezésekről. Így oldják meg a fordítás idején az olyan dolgokat, mint a TCCR1B stb. ...

Ezt a memória-leképezési mechanizmust rendkívül széles körben használják az MCU-k. Az arduino ATmega MCU-ját használja, csakúgy, mint a PIC, ARM, MSP430, STM32 és STM8 MCU sorozatokat, valamint sok olyan MCU-t, amelyeket nem ismerek azonnal.


Az Arduino kód a furcsa dolog, olyan funkciókkal, amelyek közvetett módon hozzáférnek az MCU vezérlő regiszterekhez. Bár ez némileg "szebb" kinézetű, ugyanakkor sokkal lassabb és sokkal több programterületet is igénybe vesz.

A titokzatos állandókat mind nagyon részletesen leírja az ATmega328P adatlap, amit akkor érdemes elolvasnia, ha bármi másra kíváncsi, mint az arduino csapok általi váltása.

Válasszon ki részleteket a fent linkelt adatlapból:

enter image description here enter image description here enter image description here

Tehát például a TIMSK1 | = (1 << TOIE1); beállítja a TOIE1 bitet a TIMSK1 mezőben. Ezt úgy érhetjük el, hogy az 1-es bináris kódot ( 0b00000001 ) TOIE1 bitekkel balra toljuk, a fejlécfájlban pedig a TOIE1 -ot 0-ként definiáljuk. ezután bitenként OR OR beillesztésre kerül a TIMSK1 aktuális értékébe, amely gyakorlatilag ezt az egy bitet magasra állítja.

A TIMSK1 0. bitjének dokumentációja, láthatjuk, hogy le van írva:

Ha ezt a bitet egyre írják, és az állapotregiszterben az I-flag be van állítva (a megszakítások globálisan engedélyezve vannak), akkor engedélyezve van az Időzítő / Számláló1 túlcsordulás megszakítása . A megfelelő megszakítási vektort (lásd: „Megszakítások”, 57. oldal) akkor hajtjuk végre, amikor a TIFR1-ben található TOV1 jelző be van állítva.

Az összes többi sort ugyanúgy kell értelmezni.


Néhány megjegyzés:

Olyanokat is láthat, mint a TIMSK1 | = _BV (TOIE1); . A _BV () egy általánosan használt makró, amely eredetileg az AVR libc implementációból származik. A _BV (TOIE1) funkcionálisan megegyezik a (1 << TOIE1) -val, a jobb olvashatóság érdekében.

Emellett sorokat is láthat, például mint: TIMSK1 & = ~ (1 << TOIE1); vagy TIMSK1 & = ~ _BV (TOIE1); . Ennek ellentétes funkciója van: TIMSK1 | = _BV (TOIE1); , mivel leteszi a TOIE1 bitet a TIMSK1 kód>. Ezt úgy érhetjük el, hogy a _BV (TOIE1) által előállított bitmaszkot veszünk, bitenként NEM műveletet hajtunk végre rajta ( ~ ), majd ANDingeljük a TIMSK1 ezzel a NOTED értékkel (ami 0b11111110).

Ne feledje, hogy ezekben az esetekben a (1 << TOIE1) vagy a _BV (TOIE1) értékek teljes mértékben feloldódnak a fordítási időpontban em>, így funkcionálisan egyszerű konstanssá redukálódnak, és ezért nincs szükség végrehajtási időre a futás közbeni kiszámításhoz. kód, amely részletezi a hozzárendelt regiszterek működését. Itt van egy meglehetősen egyszerű soft-SPI rutin, amelyet nemrég írtam:

  uint8_t transactByteADC (uint8_t outByte) {// Egy bájtot visz át az ADC-hez, és egy bájtot kap egyszerre // nem semmi a chip-select // MSB-vel először, az adatok az emelkedő élen vannak ütemezve uint8_t loopCnt; uint8_t retDat = 0; for (loopCnt = 0; loopCnt < 8; loopCnt ++) {if (outByte & 0x80) // ha az aktuális bit magas PORTC | = _BV (ADC_MOSI); // adatsor beállítása else PORTC & = ~ (_BV (ADC_MOSI)); // másképp állítsa ki aztByte << = 1; // és helyezze át a kimeneti adatokat a következő iterációra retDat << = 1; // váltás a visszaolvasott adatok fölé PORTC | = _BV (ADC_SCK); // Állítsa magasra az órát, ha (PINC & _BV (ADC_MISO)) // a retDat | = 0x01 beviteli sor mintája; // és állítsa be a bitet a retval-ban, ha a bemenet magas PORTC & = ~ (_BV (ADC_SCK)); // alacsony óra beállítása} return retDat;}  
A

PORTC az a regiszter, amely a kimeneti csapok értékét szabályozza az ATmega328P PORTC -ján belül. A PINC az a regisztráció, ahol a PORTC input értéke elérhető. Alapvetően ilyen dolgok történnek belsőleg, amikor a digitalWrite vagy a digitalRead függvényeket használja. Van azonban egy felkutatási művelet, amely az arduino "pin-számokat" tényleges hardver-pin-számokká alakítja át, ami valahol 50 órás ciklus tartományába esik. Ahogy valószínűleg sejteni is lehet, ha gyorsan akarsz haladni, kissé nevetséges egy 50 órás ciklus pazarlása egy olyan műveletre, amelynek csak 1 szükséges.

A fenti funkció valószínűleg valahol a 100 birodalmába kerül. -200 óra ciklus 8 bit átviteléhez. Ez 24 pin-írást és 8 olvasást jelent. Ez sok-sokszor gyorsabb, mint a digital {stuff} függvények használata.

Ne feledje, hogy ennek a kódnak az Atmega32u4 (Leonardo-ban használt) esetén is működnie kell, mivel több időzítőt tartalmaz, mint az ATmega328P.
+1 Kiváló válasz !! Kérem, fejtse ki egy kicsit, hogy mit ért "Arduino kód a furcsa dolog" alatt? Mi az egyedülálló az Arduino kódban, ez általában nem található meg más platformokon?
@Ricardo - Valószínűleg a kis MCU beágyazott kód több mint 90% -a közvetlen regisztrációt használ. Közvetett segédfunkciókkal végzett dolgok végrehajtása nagyon nem az IO / perifériák manipulálásának általános módja. Van néhány eszközkészlet a hardveres vezérlés elvonatkoztatásához (például az Atmel ASF), de általában ezt azért írják, hogy a lehető legnagyobb mértékben fordítsák össze, hogy csökkentse a futásidejű általános költségeket, és szinte mindig megköveteli a perifériák tényleges megértését az adatlapok elolvasásával.
Alapvetően az arduino dolgok, mondván, hogy "itt vannak olyan funkciók, amelyek X-et csinálnak", anélkül, hogy valóban foglalkoznék azzal, hogy hivatkozunk a tényleges dokumentációra, vagy arra, hogy a hardver * hogyan * csinálja a tetteit, nagyon nem normális. Megértem, hogy bevezető eszközként értéket képvisel, de a gyors prototípus-készítés kivételével valójában soha nem valósítják meg a tényleges szakmai környezetben.
Hogy világos legyen, az a dolog, amely szokatlanná teszi az arduino kódot a beágyazott MCU firmware számára, nem * egyedi * az arduino kóddal szemben, ez az átfogó megközelítés függvénye. Alapvetően, ha már tisztában van a * tényleges * MCU-val, a dolgok megfelelő elvégzése (pl. A hardverregiszterek közvetlen használata) alig, vagy anélkül vesz igénybe további időt. Mint ilyen, ha valódi MCU fejlesztőket szeretne megtanulni, sokkal jobb, ha csak leül és megértette, hogy mi az MCU * valójában *, hanem inkább valaki más * absztrakciójára hagyatkozik, amely általában szivárog.
Alapvetően az egész arduino rendszert többé-kevésbé úgy tervezték, hogy lehetővé tegye az alacsony belépési korlátot a * nem * programozók számára. Ezt jól csinálja, ugyanakkor nem tesz jó munkát arra, hogy a végfelhasználókat arra kényszerítse, hogy valóban megértsék a hardvert, pusztán azért, mert ez ellentmond az alacsony belépési korlátoknak. Tudomásul veszem, hogy ez értékes lépcsőfok lehet (és ez is) az emberek számára, akik a szoftverek / MCU-k megtanulása felé tartanak, de bárki, aki használja, nem szabad azt illúzióval élnie, hogy az arduino mód szükségképpen a legjobb, sőt néha jó módja annak, amit csinál.
Vegye figyelembe, hogy lehet, hogy itt kissé cinikus vagyok, de sok olyan viselkedés, amelyet az arduino közösségben látok, anti-mintákat programoz. Sok "copy-paste" programozást látok, a könyvtárakat fekete dobozként kezelem, és csak általános gyenge tervezési gyakorlatokat tapasztalok a közösségben általában. Természetesen meglehetősen aktív vagyok az EE.stackexchange szolgáltatásban, így kissé ferde nézetem lehet, mivel vannak moderátor eszközeim, és mint ilyenek sok zárt kérdést látok. Az arduino kérdésekben, amelyeket ott láttam, határozottan elfogult a "mondd meg, mit javítsak a C&P-nek", és inkább "miért nem működik ez" felé.
Valószínűleg azt is érdemes megjegyezni, hogy a C ++ használata * kissé * szokatlan. A legtöbb kis MCU munka csak tiszta C-ben történik.
Megvan! Nem volt világos számomra, hogy mit neveztek közvetett hozzáférésnek a nyilvántartásokhoz Arduino-ban, de most már tudom, hogy ez a `digitalWrite () 'típusú absztrakciók. Csökkenti a belépési korlátot, de később gátjává válik a továbbjutásnak. De a válasz nagyszerű előrelépés az akadály elhárításában. Legalább nekem.
@Ricardo - Igen. Az egyik dolog, amit nagyon szeretek * tenni az arduinóban, mint oktatási eszközben, az az, hogy munkakörnyezetet kínál a hardverrel való közvetlen játékhoz, anélkül, hogy a leggyakrabban leginkább irritáló részével kellene foglalkoznia: a kezdeti felvetéssel. Olyan platformokon dolgoztam, ahol csak egy internetszolgáltató volt, és nincs működő példa. Meg kell próbálni elhárítani, hogy miért próbálok működni a soros hibakereső felület, valódi hibakeresési felület nélkül. Rendkívül könnyen használható platform könnyen használható soros libekkel.
TheDoctor
2014-02-24 09:07:30 UTC
view on stackexchange narkive permalink

TCCR1A az időzítő / számláló 1 vezérlő regiszter A

TCCR1B a B időzítő / számláló vezérlő regiszter B

TCNT1 az 1. időzítő / számláló számlálóértéke

CS12 az 1. időzítő / számláló 3. óra kiválasztási bitje

A TIMSK1 az 1. időzítő / számláló megszakítási maszk regisztere

TOIE1 az 1. időzítő / számláló túlcsordulás megszakításának engedélyezése

Tehát a kód engedélyezi az időzítő használatát / számláló 1 62,5 kHz-en és az értéket 34286-ra állítja. Ezután engedélyezi a túlcsordulás megszakítását, így amikor eléri a 65535 értéket, elindítja a megszakítási funkciót, amely valószínűleg ISR (timer0_overflow_vect)

VENKATESAN
2020-01-18 22:44:35 UTC
view on stackexchange narkive permalink

A CS12 értéke 2, mivel a TCCR1B regiszter 2. bitjét képviseli.

(1 << CS12) felveszi az 1 (0b00000001) értéket, és kétszer eltolja balra a (0b00000100) megszerzéséhez. A műveletek sorrendje azt írja elő, hogy a () elemben a dolgok történjenek először, tehát ezt a A "| =" kiértékelésre kerül.

(1 << CS10) felveszi az 1 (0b00000001) értéket, és 0-szor eltolja balra a (0b00000001) megszerzéséhez. A műveletek sorrendje azt írja elő, hogy a () elemben először a dolgok történjenek , így ezt a "| =" kiértékelése előtt végezzük.

Tehát most kapjuk a TCCR1B | = 0b00000101-et, ami megegyezik a TCCR1B = TCCR1B | 0b00000101.

Mivel a "|" "OR", a TCCR1B-ben a CS12 kivételével az összes bit nincs hatással.



Ezt a kérdést és választ automatikusan lefordították angol nyelvről.Az eredeti tartalom elérhető a stackexchange oldalon, amelyet köszönünk az cc by-sa 3.0 licencért, amely alatt terjesztik.
Loading...