реклама на сайте
подробности

 
 
> Побитовый сдвиг данных в структуре, Как реализовать
kt368
сообщение Oct 25 2011, 07:15
Сообщение #1


Местный
***

Группа: Свой
Сообщений: 454
Регистрация: 13-10-10
Из: Киев
Пользователь №: 60 135



Здравствуйте! Имеется юнион, содержащий структуру в которой находятся данные, которые необходимо предать по SPI. Можно ли в цикле сдвигать структуру влево и передавать на ножку МК старший бит структуры?
Вот код юниона и структуры:
Код
struct SPI_TX_str {
    unsigned dch2        :1;
    unsigned ch2        :1;
    unsigned dch1        :1;
    unsigned ch1        :1;
    unsigned ch2_disp    :8;
    unsigned ch1_disp    :8;
};

struct all {
    unsigned sw                :4;
    unsigned ch2_disp        :8;
    unsigned ch1_disp        :8;
};

union SPI_union {
    struct all             all;
    struct SPI_TX_str     bits;
};
union SPI_union TXdata

И можно ли мне сделать для данного случая такой юнион, к которому я смогу обращаться типа такого:
Код
TXdata=0bxxxxxxxxxxxxxxxxxxxx;
?
Т.е чтобы записывать во все переменные, которые входят в состав структуры (которая в юнионе) при помощи одной команды на Си, как написано выше. Если б был тип данных, который занимал настраиваемое количество бит, то сделав юнион с таким типом данных я б смог его сдвигать. Может я что-то не так говорю?
Заранее спасибо.
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов (1 - 11)
редактор
сообщение Oct 25 2011, 07:41
Сообщение #2


Местный
***

Группа: Участник
Сообщений: 356
Регистрация: 9-06-07
Пользователь №: 28 315



Сдвигать структуру побитово я бы не стал. Если очень надо, то придется писать свою функцию. Но при этом следует учесть что при распределении памяти за счет выравнивания в данной структуре могут появиться "дырки" от неиспользуемых бит.


--------------------
Хорошую систему делают из стандартных блоков нестандартно мыслящие инженеры.
Go to the top of the page
 
+Quote Post
ukpyr
сообщение Oct 25 2011, 08:20
Сообщение #3


Профессионал
*****

Группа: Участник
Сообщений: 1 264
Регистрация: 17-06-08
Из: бандустан
Пользователь №: 38 347



Цитата
И можно ли мне сделать для данного случая такой юнион, к которому я смогу обращаться типа такого
можно, добавьте в юнион байтовый массив, его и сдвигайте
Go to the top of the page
 
+Quote Post
dxp
сообщение Oct 25 2011, 11:24
Сообщение #4


Adept
******

Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343



Цитата(ukpyr @ Oct 25 2011, 15:20) *
можно, добавьте в юнион байтовый массив, его и сдвигайте

Небезопасный хак. Порядок распределения битовых полей в структуре отдан на откуп реализации. При сдвиге, если есть "дырки", то может возникать попадание мимо поля, либо искажение его значения (если оно не один бит). Ну, и с переносимостью даже между версиями одного и того же компилятора тоже могут быть вопросы.

Интересно, а зачем так делать?


--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
Go to the top of the page
 
+Quote Post
kt368
сообщение Oct 26 2011, 05:18
Сообщение #5


Местный
***

Группа: Свой
Сообщений: 454
Регистрация: 13-10-10
Из: Киев
Пользователь №: 60 135



Так хотелось сделать для удобного в применении хранилища с передаваемыми данными. Ладно, лучше (и быстрее) будет на асме десяток строк написать.
Go to the top of the page
 
+Quote Post
ViKo
сообщение Oct 26 2011, 05:47
Сообщение #6


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Добавить к объединению переменную uint32_t. Её и сдвигать. Только лишний байт в памяти появится. Но и его можно для чего-нибудь задействовать.

P.S. Хотел поинтересоваться - а почему не существует переменных uint24_t?
Go to the top of the page
 
+Quote Post
777777
сообщение Oct 26 2011, 18:47
Сообщение #7


Профессионал
*****

Группа: Участник
Сообщений: 1 091
Регистрация: 25-07-07
Из: Саратов
Пользователь №: 29 357



Цитата(kt368 @ Oct 25 2011, 11:15) *
Здравствуйте! Имеется юнион, содержащий структуру в которой находятся данные, которые необходимо предать по SPI. Можно ли в цикле сдвигать структуру влево и передавать на ножку МК старший бит структуры?

Можно, для этого заводишь указатель на эту структуру и присваиваешь ему адрес соответствующей переменной:

union SPI_union TXdata;
uint8_t* pData = (uint8_t*)&TXdata;

После этого можешь передавать данные в SPI:

SPDR = *pData++;

После чего pData сдвигается на следующий байт той структуры.
ЗЫ. Замечание о порядке распределения полей справедливо (вплоть до того, слева направо они располагаются или справа налево), поэтому проверять это нужно экспериментально.
Go to the top of the page
 
+Quote Post
dxp
сообщение Oct 27 2011, 04:02
Сообщение #8


Adept
******

Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343



Цитата(kt368 @ Oct 26 2011, 12:18) *
Так хотелось сделать для удобного в применении хранилища с передаваемыми данными. Ладно, лучше (и быстрее) будет на асме десяток строк написать.

Тогда, как уже посоветовали, сделать union, где объявить структуру и массив. При работе с полями использовать структуру, а при пересылках - массив.

Только структуру надо будет объявить пакованной (обычно делается через #pragma директиву компилятора), иначе на другом конце, если там другая платформа, весьма вероятны ошибки, т.к. размещение полей в структуре очень зависит от платформы (в основном из-за требований к выравниванию данных в памяти).

Указанный способ с union является самым простым способом сериализации. И не факт, что он будет самым эффективным, если использовать пакованный структуры. Возможно, явная упаковка полей в пакеты при отправке будет и получше.


--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
Go to the top of the page
 
+Quote Post
kt368
сообщение Oct 27 2011, 05:57
Сообщение #9


Местный
***

Группа: Свой
Сообщений: 454
Регистрация: 13-10-10
Из: Киев
Пользователь №: 60 135



Цитата(dxp @ Oct 27 2011, 07:02) *
Только структуру надо будет объявить пакованной
А что это значит?
Go to the top of the page
 
+Quote Post
dxp
сообщение Oct 27 2011, 09:05
Сообщение #10


Adept
******

Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343



Цитата(kt368 @ Oct 27 2011, 12:57) *
А что это значит?

Почти на всех (если не на всех) процессорах, имеющих разрядность данных больше 8 бит (1 байт), существует требование по выравниванию данных. Например, однобайтовые слова могут располагаться по любым адресам, двухбайтовые - по адресам, кратным 2, четырёхбайтные (а также, например, массивы, структуры, объединения) - кратным 4. Поэтому, если объявить на какой-нить 32-разрядной платформе:

Код
struct TSlon
{
    char a;
    long b;
};


то в памяти физически это будет лежать так, что 'a' займёт один байт под адресу, кратному 4, потом будет три незанятых байта, а 'b' будет лежать по следующему адресу, кратному 4. Т.е. казалось бы sizeof структуры должен быть равен 5, а в реальности он будет равен 8.

Теперь представьте себе, что вы эту структуру отправляете на платформу, где нет такого требования и все данные лежат подряд без паддинга ("дырок"). Ясно, что получив сырой массив из байт, дальнейшая интерпретация полей будет неверной. Чтобы избавиться от этого, можно компилятору сказать, чтобы он принудительно упаковывал данные всегда без "дырок", тогда битовое представление будет правильным везде (кроме случаев с разным big/little endian). Для этого у подавляющего большинства компиляторов существует специальная директива - нечто вроде #pragma packed, как оно точно называется и используется, надо смотреть в документации на конкретный компилятор.

Пакованные структуры значительно менее эффективны в использовании - тут компилятору приходится самому (при обращении к полям) каждый раз упаковывать/распаковывать. К тому же, как уже говорилось ранее, #pragma директивы - вещь платформеннозависимая, поэтому переносимости тут тоже нет. Учитывая вышесказанное, имеет смысл подумать над собственным способом сериализации, возможно, он окажется более подходящим, хотя и потребует написания кода руками.


--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
Go to the top of the page
 
+Quote Post
neiver
сообщение Oct 31 2011, 12:07
Сообщение #11


Местный
***

Группа: Участник
Сообщений: 214
Регистрация: 22-03-10
Из: Саратов
Пользователь №: 56 123



Использовать объединения для приведения типов это уже само по себе грязный хак.
Код
union MyUnion{
   Type1 a;
   Type2 b;
};
...
union MyUnion var;
var.a = something;
do_something_with(var.b);

По стандарту объединение - это лишь указание компилятору, что его поля могут разделять общую память, и обещание (с стороны программиста) не использовать эти поля одновременно. Гарантируется, что записывая "а", мы его сможем прочитать, записывая "b" мы сможем прочитать его. А записывая "а", а после читая "b" мы нагло обманываем компилятор и можем за это получить по ушам. Шибко умный оптимизатор может заметить, что выражение var.a инициализируется, но нигде не используется и выкинет его инициализацию, после чего значение var.b будет не определено. Хотя часто такой код работает до поры до времени, пока не изменился уровень/флаги оптимизации, не обновился компилятор и т.д.
Единственно надежный способ (уже указан выше) это преобразовывать указатель на структуру в указатель на char:
Цитата
union SPI_union TXdata;
uint8_t* pData = (uint8_t*)&TXdata;

После этого можешь передавать данные в SPI:

SPDR = *pData++;

Go to the top of the page
 
+Quote Post
dxp
сообщение Oct 31 2011, 13:45
Сообщение #12


Adept
******

Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343



Цитата(neiver @ Oct 31 2011, 19:07) *
Единственно надежный способ (уже указан выше) это преобразовывать указатель на структуру в указатель на char:

Ну, дык любое ручное преобразование типов - это тоже хак. Как быть, если в структуре есть "дырки"? Единственный действительно надёжный способ подготовки данных для передачи - это явная упаковка данных в массив для отправки. А указанный способ более прямо реализуется путём использования memcpy объекта в буфер передатчика, хотя это работает только для POD типов (как и вариант с ручным преобразованием указателя).


--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
Go to the top of the page
 
+Quote Post

Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 20th June 2025 - 09:48
Рейтинг@Mail.ru


Страница сгенерированна за 0.01456 секунд с 7
ELECTRONIX ©2004-2016