Vraag:
Waar staat deze notatie voor? Draad.lezen () << 8 | Draad.lezen ()
Julio
2017-03-28 01:42:34 UTC
view on stackexchange narkive permalink

Ik gebruik de testcode van de Arduino-site om ruwe waarden te krijgen van een MPU-6050-accelerometer + gyro. In de lus zijn er deze regels om de volgende gegevens uit de registers te halen:

  Wire.requestFrom (MPU_addr, 14, true); // vraag in totaal 14 registersAcX = Wire.read () <<8 | Wire.read (); // 0x3B (ACCEL_XOUT_H) & 0x3C (ACCEL_XOUT_L) AcY = Wire.read () <<8 | Wire.read (); // 0x3D (ACCEL_YOUT_H) & 0x3E (ACCEL_YOUT_L) AcZ = Wire.read () <<8 | Wire.read (); // 0x3F (ACCEL_ZOUT_H) & 0x40 (ACCEL_ZOUT_L) Tmp = Wire.read () <<8 | Wire.read (); // 0x41 (TEMP_OUT_H) & 0x42 (TEMP_OUT_L) GyX = Wire.read () <<8 | Wire.read (); // 0x43 (GYRO_XOUT_H) & 0x44 (GYRO_XOUT_L) GyY = Wire.read () <<8 | Wire.read (); // 0x45 (GYRO_YOUT_H) & 0x46 (GYRO_YOUT_L) GyZ = Wire.read () <<8 | Wire.read (); // 0x47 (GYRO_ZOUT_H) & 0x48 (GYRO_ZOUT_L)  

Hex-nummers geven natuurlijk het adres van elk register aan. Ik kan echter niet begrijpen hoe, als de eerste instructie alleen vraagt ​​van de MPU_addr (constante), deze verandert in de opeenvolgende registers. Is het dat <<8 | zoiets als een som of een logica maakt OF om het register te veranderen om te lezen?

Met vriendelijke groet!

Links 8 bits verschuiven, dan bitsgewijs OF. Zet twee 8-bits waarden om in één 16-bits waarde.
Ik probeer gewoon het duplicaat te vinden waarvan ik weet dat het er is (want ik heb het beantwoord). Het dichtst dat ik nu kan vinden is: http://arduino.stackexchange.com/questions/19243/and-syntax-in-arduino/19244
Een belangrijk ding om op te merken is echter dat het gebruik van `Wire.read ()` binnen de shifting en ORing op die manier niet goed is. Er is geen garantie dat de `Wire.read ()` functies in de juiste volgorde worden aangeroepen. U moet eerst variabelen inlezen en vervolgens met die variabelen werken. http://en.cppreference.com/w/cpp/language/eval_order
Ik begrijp het, het is een punt waar ik rekening mee moet houden met mijn eigen ontwerp. Maar eigenlijk werk ik liever met variabelen dan met functies. Bedankt voor het advies!
@Majenko, weet je het zeker? Ik heb geprobeerd die pagina te lezen over de volgorde van evaluatie, maar het is erg moeilijk te begrijpen voor mij. Omdat het dezelfde functie is die twee keer wordt aangeroepen en het een I / O-functie is, moet de compiler begrijpen dat er een bestelling is. De oorsprong van de code is hier: http://playground.arduino.cc/Main/MPU-6050#short
In de praktijk is het meestal ok, maar er zijn geen garanties. En wat in de ene versie van de compiler werkt, stopt mogelijk in een andere. Ook is de Arduino-speeltuin niet de meest betrouwbare bron voor code van goede kwaliteit.
Twee antwoorden:
Edgar Bonet
2017-03-28 14:21:51 UTC
view on stackexchange narkive permalink

Gewoon een paar punten toevoegen aan het antwoord van Michel Keijzers.

De uitdrukking Wire.read () << 8 neemt de waarde die wordt geretourneerd door Wire.read () , wat een int is, en 8 bits naar links verschuift, wat overeenkomt met vermenigvuldigen met 256. Als u een 32-bits microcontroller gebruikt (bijv. een Arduino Due), is veilig. De meeste Arduino's zijn echter gebaseerd op een 8-bits AVR-chip. Op hen is een int 16-bits en kan deze alleen waarden bevatten tot 32767. Als de beginwaarde groter is dan 127, dan veroorzaakt de bitverschuiving een overloop met gehele getallen met teken, die inC en C ++ zijn ongedefinieerd gedrag (lees: "illegale operatie"). Het is waarschijnlijk dat alles goed verloopt en u het verwachte resultaat krijgt, maar het is onverstandig om ooit te vertrouwen op ongedefinieerd gedrag in C of C ++.

De juiste manier om de verschuiving uit te voeren is om de beginwaarde naar een niet-ondertekend gegevenstype te casten, wat altijd veilig is vs. overflows, en doe dan de shift, zoals in

  ((uint16_t) Wire.read ()) << 8  

Je mag de buitenste haakjes weglaten als je de prioriteiten van je operator kent.

Het tweede punt betreft het reeds genoemde feit dat de volgorde van de reads niet gespecificeerd is. De eenvoudigste oplossing is om één leesopdracht uit te voeren, zoals in:

  AcX = (uint16_t) Wire.read () << 8; // lees eerst MSBAcX | = Wire.read (); // dan LSB  

Het is vermeldenswaard dat de eerste instructie een impliciete cast heeft van uint16_t (het resultaat van de verschuiving) naar int16_t (het type AcX ). Dit kan ook overlopen als de verschoven waarde groter is dan 32767. er treedt echter een overloop op tijdens een conversie in niet ongedefinieerd, maar eerder implementatie gedefinieerd gedrag . Dit betekent dat de auteurs van de compiler moeten beslissen en documenteren wat er gebeurt. Arduino code wordt meestal gecompileerd door gcc, en de gcc docs documenteren dit gedrag als

Het resultaat van, of het signaal opgewekt door, het omzetten van een geheel getal naar een getekend geheel getal type wanneer de waarde niet kan worden weergegeven in een object van dat type (C90 6.2.1.2, C99 en C11 6.3.1.3).

Voor conversie naar een type met breedte N, de waarde is gereduceerd modulo 2 ^ N om binnen het bereik van het type te zijn; er wordt geen signaal gegeven.

Dit is precies wat we hier willen, en aangezien het de meest efficiënte keuze is voor een two-complement-architectuur, lijkt het onwaarschijnlijk dat een andere compiler een andere keuze zou maken.

Wat een geweldige uitleg!
Michel Keijzers
2017-03-28 01:52:24 UTC
view on stackexchange narkive permalink

1 << 3 betekent dat de waarde 1 3 keer naar links is verschoven. Dus 1 in binair getal is 0000001, 3 plaatsen naar links verschoven is 00001000. En 0001101 << 3 wordt 1101000.

De | commando is een logica of (waarbij bits 1 zijn als een van de bits 1 is, bijv. 001100 | 001001 = 001101.

Waarschijnlijk geeft elke Wire.read () de volgende byte. Voor de eerste regel: Acx = Wire.read () << 8 | wire.read () betekent dat één byte (meestal de eerste byte) wordt gelezen, de ene byte naar links wordt verschoven en de andere (meestal volgende byte) gelezen wordt rechts geplaatst. het resulteert erin dat de eerste twee gelezen bytes in AcX worden gepositioneerd. Het is semantisch hetzelfde als Wire.read () * 256 + Wire.read (), maar normaal is een bitverschuiving gemakkelijker voor een computer, hetzelfde als | en de + operator.

Ik snap het, het lijkt alsof je zei dat het een woord samenstelt met die twee bytes, omdat het gegevensblad van het item aangeeft dat in elk paar het ene register de hoge bits heeft en het andere de lage bits. Dank je.
Graag gedaan, en ja, de hoge 8 bits gaan naar het eerste deel van het paar, en de volgende (lage) 8 bits gaan naar het tweede deel.
“Voor de eerste regel: Acx = Wire.read () << 8 | wire.read () betekent dat de eerste byte wordt gelezen, één byte naar links wordt verschoven en de volgende gelezen byte rechts wordt geplaatst. ”is onjuist. Het zou in plaats daarvan moeten zeggen: “Voor de eerste regel:` Acx = wire.read () << 8 | wire.read () `betekent dat twee bytes worden gelezen, ** een ervan ** wordt gebruikt als MSB en ** de andere ** als LSB”. Dat wil zeggen, volgens de C-norm N1570 §6.5.2 is het zonder haakjes ongedefinieerd welke `wire.read ()` de eerste is en welke de tweede. Het is natuurlijk vaak zo dat ze in de door u genoemde volgorde worden gebruikt, maar het is hier niet gedefinieerd.
@jwpat7 ja je hebt gelijk ... ik zal het antwoord bijwerken


Deze Q&A is automatisch vertaald vanuit de Engelse taal.De originele inhoud is beschikbaar op stackexchange, waarvoor we bedanken voor de cc by-sa 3.0-licentie waaronder het wordt gedistribueerd.
Loading...