Więc po 2 dniach próby nie mogę tego obejść.
Więc używam magistrali CAN do przesyłania danych akcelerometru i danych czasu (funkcja micros (), jeśli poniżej 71 minut wyprowadzi dane, które mogą mieć długość bez znaku), jednak muszę wysłać dane jako bajty. udało mi się przesunąć nieco 16-bitową liczbę int do 2 bajtów, ale mam problem z ekstrapolacją tej metody (dodam ją później) na użycie długich. Mam problemy ze zrozumieniem metody unii, ponieważ jestem nowy w tworzeniu własnych funkcji, więc jak czy moglibyście to osiągnąć? Tak prosto, jak to tylko możliwe 🙂
Komentarze
- odejmujesz maksymalny bajt 3 od sumy, a od które odejmują maksymalny bajt 2, aby uzyskać bajt 3. bajt 4 to po prostu maksymalny bajt 4 minus liczba minus maksymalny bajt 3 +1.
Odpowiedź
Możesz osiągnąć to, co chcesz, używając bitshifting i bit-mądre i operatory.
Oto przykład, który pozwala wyodrębnić poszczególne bajty zmiennej long
. Myślę, że rozszerzenie go na zmienne o różnej długości powinno być proste:
void loop() { long a=0x12345678, c=0; byte b[4]; Serial.println("Original:"); Serial.println(a,HEX); delay(1000); Serial.println("Individual bytes:"); for (int i=0; i<4; i++) { b[i]=((a>>(i*8)) & 0xff); //extract the right-most byte of the shifted variable Serial.println(b[i],HEX); delay(1000); } for (int i=0; i<4; i++) { c+=b[i]<<(i*8); } Serial.println("Reconstructed:"); Serial.println(c,HEX); delay(1000); }
W zależności od oczekiwanej kolejności bajtów (duży lub mały endian), możesz trzeba zmienić kolejność bajtów przed wysłaniem lub po odebraniu.
Komentarze
- Bardzo prosta i łatwa do zrozumienia zasada, więc dziękuję, jednak pod " zrekonstruowano " drukuje tylko 5678?
- Czy skopiowałeś fragment kodu z mojej odpowiedzi? Ponieważ jeśli uruchomię kod na moim nodemcu, otrzymam właściwą odpowiedź.
- Tak, skopiowałem i wkleiłem kod, dodałem void setup (); i Serial.begin (9600); aby kod działał na moim arduino nano
- domyślnie na 8-bitowym AVR, po prawej stronie równa się domyślnie arytmetyka int, która jest podpisana szesnastobitowo. Więc rzuciłem tablicę na uint32_t w pętli. Nie jestem pewien, czy to najbardziej efektywny sposób, ale działa! Dziękuję za pomoc
- tak dobrze. Nie myślałem ' o kontrolerze arduino, kiedy próbowałem na nodemcu.
Odpowiedz
Typ union
jest podobny do struct
z tą różnicą, że każdy z członków elementu zajmuje ta sama pamięć. Jeśli zdefiniujesz struct
tak, aby miał 2 elementy – jeden typ 4-bajtowy i jedną 4-elementową tablicę typu jednobajtowego, możesz łatwo odwołać się do tych samych danych jako całość 4-bajtowego elementu lub według własnego uznania.
union packed_long { long l; byte b[4]; };
To jest typ, więc musisz zadeklarować zmienną jako ten typ:
packed_long mydata;
Teraz masz dwa podelementy mydata
: l
i b[]
.
Aby zapisać swoją wartość long
, napisz do l
część:
mydata.l = myaccel.getY();
Aby uzyskać dostęp do każdego z 4 bajtów:
byte1 = mydata.b[0]; byte2 = mydata.b[1]; byte3 = mydata.b[2]; byte4 = mydata.b[3];
Po stronie odbiorczej bierzesz każdy z 4 bajtów:
mydata.b[0] = canbus.read(); mydata.b[1] = canbus.read(); mydata.b[2] = canbus.read(); mydata.b[4] = canbus.read();
O ile otrzymujesz bajty w tej samej kolejności w którym je wysłałeś, możesz teraz uzyskać dostęp do swojej long
wartości w mydata.l
.
Rzeczywisty rozmiar różnych typy jest zależy od kompilatora i architektury, więc możesz również chcieć zdefiniować swoją wartość jako zmienną o określonym rozmiarze, aby mieć pewność, że zawsze pracujesz z 32-bitowymi bitami: int32_t
(32-bitowa liczba całkowita ze znakiem ) lub uint32_t
(32-bitowa liczba całkowita bez znaku).
Odpowiedź
Sposobem wysłania długiego jest zamaskowanie i wysłanie bajtu LSB (standard CAN), a następnie przesunięcie następny w pozycji LSB, dla 4 bajtów:
uint32_t data; // Send to CAN bus LSB-first // This method is destructive; data should be a temp if the // Arduino is to retain the data after sending it. for( uint8_t b = 4; b > 0; --b ){ sendByte(data & 0xFF); // send curr byte data >>= 8; // shift that byte away } // Read from CAN bus for( uint8_t b = 4; b > 0; --b ){ data >>= 8; // make room for byte data |= (readByte() << 8); // read next higher byte } //
Komentarze
- OK, więc standard CAN jest najpierw LSB. Skoro znasz CAN, z tego, co mogę znaleźć, wysyłają pakiet 8-bajtowy, czy tylko jeden lub dwa z nich to dane? Czy więc w sumie 16 bajtów informacji będzie potrzebnych 8 pakietów?
- Złapałeś mnie! To ' wszystko, co wiem o magistrali CAN, a to pochodzi z Wikipedii . W Internecie jest dużo dokumentacji dotyczącej magistrali CAN; bibliografia tego artykułu ' to dobry początek.
- 8 bajtów to rozmiar ładunku danych standardowej ramki can. więc potrzebujesz dwóch standardowych ramek do przesłania 16 bajtów informacji. nowszy can-fd obsługuje 64 bajty danych na ramkę.