|
Побитовый сдвиг данных в структуре, Как реализовать |
|
|
|
Oct 25 2011, 07:15
|
Местный
  
Группа: Свой
Сообщений: 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; ? Т.е чтобы записывать во все переменные, которые входят в состав структуры (которая в юнионе) при помощи одной команды на Си, как написано выше. Если б был тип данных, который занимал настраиваемое количество бит, то сделав юнион с таким типом данных я б смог его сдвигать. Может я что-то не так говорю? Заранее спасибо.
|
|
|
|
|
 |
Ответов
(1 - 11)
|
Oct 25 2011, 11:24
|

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

|
Цитата(ukpyr @ Oct 25 2011, 15:20)  можно, добавьте в юнион байтовый массив, его и сдвигайте Небезопасный хак. Порядок распределения битовых полей в структуре отдан на откуп реализации. При сдвиге, если есть "дырки", то может возникать попадание мимо поля, либо искажение его значения (если оно не один бит). Ну, и с переносимостью даже между версиями одного и того же компилятора тоже могут быть вопросы. Интересно, а зачем так делать?
--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
|
|
|
|
|
Oct 26 2011, 18:47
|

Профессионал
    
Группа: Участник
Сообщений: 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 сдвигается на следующий байт той структуры. ЗЫ. Замечание о порядке распределения полей справедливо (вплоть до того, слева направо они располагаются или справа налево), поэтому проверять это нужно экспериментально.
|
|
|
|
|
Oct 27 2011, 04:02
|

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

|
Цитата(kt368 @ Oct 26 2011, 12:18)  Так хотелось сделать для удобного в применении хранилища с передаваемыми данными. Ладно, лучше (и быстрее) будет на асме десяток строк написать. Тогда, как уже посоветовали, сделать union, где объявить структуру и массив. При работе с полями использовать структуру, а при пересылках - массив. Только структуру надо будет объявить пакованной (обычно делается через #pragma директиву компилятора), иначе на другом конце, если там другая платформа, весьма вероятны ошибки, т.к. размещение полей в структуре очень зависит от платформы (в основном из-за требований к выравниванию данных в памяти). Указанный способ с union является самым простым способом сериализации. И не факт, что он будет самым эффективным, если использовать пакованный структуры. Возможно, явная упаковка полей в пакеты при отправке будет и получше.
--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
|
|
|
|
|
Oct 27 2011, 05:57
|
Местный
  
Группа: Свой
Сообщений: 454
Регистрация: 13-10-10
Из: Киев
Пользователь №: 60 135

|
Цитата(dxp @ Oct 27 2011, 07:02)  Только структуру надо будет объявить пакованной А что это значит?
|
|
|
|
|
Oct 27 2011, 09:05
|

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 директивы - вещь платформеннозависимая, поэтому переносимости тут тоже нет. Учитывая вышесказанное, имеет смысл подумать над собственным способом сериализации, возможно, он окажется более подходящим, хотя и потребует написания кода руками.
--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
|
|
|
|
|
Oct 31 2011, 12:07
|
Местный
  
Группа: Участник
Сообщений: 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++;
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|