упаковывать биты в структуру c ++ / arduino - PullRequest
0 голосов
/ 25 мая 2018

У меня есть структура:

typedef struct {
  uint8_t month;  // 1..12 [4 bits]
  uint8_t date;   // 1..31 [5 bits]
  uint8_t hour;   // 00..23 [5 bits]
  uint8_t minute; // 00..59 [6 bits]
  uint8_t second; // 00..59 [6 bits]
} TimeStamp;

, но я бы хотел упаковать ее, чтобы она занимала только 4 байта вместо 5.

Есть ли способ сдвига битов для созданияболее плотная структура?

Может показаться, что это немного, но это входит в EEPROM, поэтому 1 сохраненный байт - это дополнительные 512 байт на странице размером 4 КБ (и я могу использовать эти дополнительные 6 бит, оставшиеся для чего-то другого).

Ответы [ 4 ]

0 голосов
/ 25 мая 2018

Если вы можете справиться с точностью до двух секунд, формат метки времени MS-DOS использовал 16 бит для хранения даты (год-1980 как 7 бит, месяц как 4, день как 5) и 16 бит для времени (часпять минут шесть как пять секунд.На процессоре, таком как Arduino, может быть возможно написать код, который разделяет значения через 16-битную границу, но я думаю, что код будет более эффективным, если вы сможете избежать такого разделения (как MS-DOS сделал, приняв двухсекундныйточность).

В противном случае, как было отмечено в другом ответе, использование 32-разрядного числа секунд, поскольку некоторое базовое время часто будет более эффективным, чем попытка отслеживать вещи в «формате календаря».Если все, что вам когда-либо нужно, - это переходить от одной даты в календарном формате к следующей, сделать код может быть проще, чем код для преобразования между календарными датами и линейными датами, но если вам нужно сделать что-то еще (дажешаг назад от даты к предыдущей) вам, вероятно, будет лучше конвертировать даты в / из линейного формата, когда они вводятся или отображаются, а в остальном просто работать с линейными числами секунд.

Работа слинейные числа секунд можно сделать более удобными, если вы выберете в качестве базовой даты 1 марта високосного года.Затем, хотя дата превышает 1461, вычтите ее из даты и добавьте 4 к году (16-битное сравнение и вычитание эффективны на Arduino, и даже в 2040 году цикл все равно может занять меньше времени, чем одно деление 16x16).Если дата превышает 364, вычтите 365 и увеличьте год, и попробуйте сделать это в два раза больше [если дата - 365 после третьего вычитания, оставьте ее].

Требуется некоторая осторожность, чтобы все углыслучаи работают правильно, но даже на небольшом 8-битном или 16-битном микро преобразовании могут быть удивительно эффективными.

0 голосов
/ 25 мая 2018

Битовые поля - один из "правильных" способов сделать это в целом, но почему бы просто не хранить секунды с начала года?4 байта достаточно, чтобы удобно хранить их;на самом деле 4 байта достаточно для хранения секунд между 1970 и 2038 годами. Извлечение из него другой информации - простое упражнение, если вы знаете текущий год (который вы можете хранить вместе с остальной информацией до тех пор, покапоскольку диапазон времени, в котором вы заинтересованы, охватывает менее 70 лет (и даже тогда вы можете просто сгруппировать временные метки в диапазоны 68 ​​лет и сохранить смещение для каждого диапазона).

0 голосов
/ 25 мая 2018

Другое решение состоит в том, чтобы хранить значения в одной 32-битной переменной и извлекать отдельные элементы со сдвигом битов.

uint32_t timestamp = xxxx;

uint8_t month = timestamp & 0x0F;
uint8_t date = (timestamp & 0x1F0) >> 4;
uint8_t hour = (timestamp & 0x3E00) >> 9;
uint8_t minute = (timestamp & 0xFC000) >> 14;
uint8_t second = (timestamp & 0x3F00000) >> 20;
0 голосов
/ 25 мая 2018

То, что вы ищете, это битовые поля.

Они выглядят так:

typedef struct {
  uint32_t month  : 4;   // 1..12 [4 bits]
  uint32_t date   : 5;   // 1..31 [5 bits]
  uint32_t hour   : 5;   // 00..23 [5 bits]
  uint32_t minute : 6;   // 00..59 [6 bits]
  uint32_t second : 6;   // 00..59 [6 bits]
} TimeStamp;

В зависимости от вашего компилятора, чтобы вписаться в 4 байта без заполненияразмер членов должен быть 4 байта (т.е. uint32_t) в этом случае.В противном случае члены структуры будут дополнены, чтобы не переполняться на границе каждого байта, что приведет к структуре из 5 байтов, если используется uint8_t.Использование этого в качестве общего правила должно помочь предотвратить несоответствия компилятора.

Вот ссылка MSDN, которая немного углубляется в битовые поля:

битовые поля C ++

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...