
![]() |
Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
|
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[18.206.194.21] |
![]() |
|
Сообщ.
#1
,
|
|
|
Решил хитро преобразовывать данные протокола SBUS в байты и обратно. Через объявление структуры и объединение. Но что-то пошло не так...
![]() Значения в одном канале для SBUS есть 11-битное число. Отправка же всех данных по USART идёт побайтно. ![]() ![]() #pragma pack(push, 1) // typedef struct tag_sbus_dat { BYTE StartByte; WORD ch0 : 11; WORD ch1 : 11; WORD ch2 : 11; WORD ch3 : 11; WORD ch4 : 11; WORD ch5 : 11; WORD ch6 : 11; WORD ch7 : 11; WORD ch8 : 11; WORD ch9 : 11; WORD ch10 : 11; WORD ch11 : 11; WORD ch12 : 11; WORD ch13 : 11; WORD ch14 : 11; WORD ch15 : 11; BYTE FlagsByte; BYTE EndByte; } SBUS_DAT; #pragma pack(pop) typedef union { BYTE byte[25]; SBUS_DAT msg; } Sbus_msg; Sbus_msg Sbus_Data; Общее количество бит в структуре должно быть 200, что соответствует 25 байт (размер посылки в SBUS). Задумка такая: формирую значения всех 16 каналов, и выбрасываю их на USART в виде 25 байтов. И в обратном направлении: Читаю 25 байтов с USART и тут же получаю 11-битные значения всех 16 каналов. Но на 10 канале число не соответствует реальному. И размер структуры : ![]() ![]() printf("sizeof data is %d\n", sizeof(Sbus_Data)); Вместо 25 байтов выдает 36. Где тут засада, не могу понять... ![]() |
Сообщ.
#2
,
|
|
|
С битовыми полями не все так просто. По стандарту там многое зависит от реализации. Вот кусочек стандарта "Стандарт-Си++ 2017 (ISO-IEC_14882-2017)" (обрати внимание на выделенное красным):
Цитата 12.2.4 Bit-fields 1. A member-declarator of the form identifieropt attribute-specifier-seqopt : constant-expression brace-or-equal-initializeropt specifies a bit-field; its length is set off from the bit-field name by a colon. The optional attribute-specifier-seq appertains to the entity being declared. The bit-field attribute is not part of the type of the class member. The constant-expression shall be an integral constant expression with a value greater than or equal to zero. The value of the integral constant expression may be larger than the number of bits in the object representation (6.9) of the bit-field’s type; in such cases the extra bits are padding bits (6.9). Allocation of bit-fields within a class object is implementation-defined. Alignment of bit-fields is implementation-defined. Bit-fields are packed into some addressable allocation unit. [ Note: Bit-fields straddle allocation units on some machines and not on others. Bit-fields are assigned right-to-left on some machines, left-to-right on others. —end note ] 2. A declaration for a bit-field that omits the identifier declares an unnamed bit-field. Unnamed bit-fields are not members and cannot be initialized. [ Note: An unnamed bit-field is useful for padding to conform to externally-imposed layouts. —end note ] As a special case, an unnamed bit-field with a width of zero specifies alignment of the next bit-field at an allocation unit boundary. Only when declaring an unnamed bit-field may the value of the constant-expression be equal to zero. 3. A bit-field shall not be a static member. A bit-field shall have integral or enumeration type (6.9.1). A bool value can successfully be stored in a bit-field of any nonzero size. The address-of operator & shall not be applied to a bit-field, so there are no pointers to bit-fields. A non-const reference shall not be bound to a bit-field (11.6.3). [ Note: If the initializer for a reference of type const T& is an lvalue that refers to a bit-field, the reference is bound to a temporary initialized to hold the value of the bit-field; the reference is not bound to the bit-field directly. See 11.6.3. —end note ] 4. If the value true or false is stored into a bit-field of type bool of any size (including a one bit bit-field), the original bool value and the value of the bit-field shall compare equal. If the value of an enumerator is stored into a bit-field of the same enumeration type and the number of bits in the bit-field is large enough to hold all the values of that enumeration type (10.2), the original enumerator value and the value of the bit-field shall compare equal. А вот кусочек из "Стандарт-Си-2018 (ISO-IEC_ 9899-2018)": Цитата 6.7.2.1 Structure and union specifiers ... 11.An implementation may allocate any addressable storage unit large enough to hold a bit-field. If enough space remains, a bit-field that immediately follows another bit-field in a structure shall be packed into adjacent bits of the same unit. If insufficient space remains, whether a bit-field that does not fit is put into the next unit or overlaps adjacent units is implementation-defined. The order of allocation of bit-fields within a unit (high-order to low-order or low-order to high-order) is implementation-defined. The alignment of the addressable storage unit is unspecified. ... Я попробовал в онлайн-компиляторе твой код, предварительно изменив твои типы на типы из стандартной библиотеки - там все как ты хотел: ![]() ![]() #include <cstdio> #include <cstdint> #pragma pack(push, 1) // typedef struct tag_sbus_dat { uint8_t StartByte; uint16_t ch0 : 11; uint16_t ch1 : 11; uint16_t ch2 : 11; uint16_t ch3 : 11; uint16_t ch4 : 11; uint16_t ch5 : 11; uint16_t ch6 : 11; uint16_t ch7 : 11; uint16_t ch8 : 11; uint16_t ch9 : 11; uint16_t ch10 : 11; uint16_t ch11 : 11; uint16_t ch12 : 11; uint16_t ch13 : 11; uint16_t ch14 : 11; uint16_t ch15 : 11; uint8_t FlagsByte; uint8_t EndByte; } SBUS_DAT; #pragma pack(pop) typedef union { uint8_t byte[25]; SBUS_DAT msg; } Sbus_msg; int main() { Sbus_msg Sbus_Data; printf("sizeof data is %ld\n", sizeof(Sbus_Data)); return 0; } https://onlinegdb.com/Cyn-Rqok- |
Сообщ.
#3
,
|
|
|
Majestio, спасибо.
У меня стандарт Си++ 17 Сходил по твоей ссылке. Там вижу реально размер структуры 25 байт. Скопировал твой код себе. Запустил - всё равно 35 байтов. ![]() Использую MSVC 2017. Видимо придётся отказаться от хитрого плана и перекодировать всё вручную. ![]() |
Сообщ.
#4
,
|
|
|
Цитата DrUnkard @ Видимо придётся отказаться от хитрого плана и перекодировать всё вручную. Думаю, имеет смысл погуглить про особенности именно MSVC 2017. |
Сообщ.
#5
,
|
|
|
Я тут другое поискал. Нашел ручную кодировку / раскодировку SBUS. Буду применять ее и не заморачиваться своими хитростями.
![]() Кому интересно - тут Функции: ![]() ![]() bool SBUS::read(uint16_t* channels, bool* failsafe, bool* lostFrame) void SBUS::write(uint16_t* channels) https://github.com/TheDIYGuy999/SBUS/blob/m...er/src/SBUS.cpp Спасибо всем добрым людям. ![]() |
Сообщ.
#6
,
|
|
|
Цитата Majestio @ Думаю, имеет смысл погуглить про особенности именно MSVC 2017. Ну в догонку ... Мелкомягкие имеют свою точку зрения на упаковку битовых полей. |