struct c ++ / arduinoにビットをパックします
私は構造体を持っています:
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;
しかし、5ではなく4バイトしか消費しないようにパックしたいと思います。
ビットをシフトしてより厳密な構造を作成する方法はありますか?
大したことではないように思えるかもしれませんが、EEPROMに保存されるため、1 KBを節約すると4 KBページで512バイトが余分に節約されます(残りの6ビットは他の何かに使用できます)。
探しているのはビットフィールドです。
次のようになります。
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
)でなければなりません。そうしないと、uint8_t
を使用している場合、構造体のメンバーは各バイト境界でオーバーフローしないようにパディングされ、5バイトの構造体になります。これを一般的なルールとして使用すると、コンパイラの矛盾を防ぐことができます。
ビットフィールドについて少し詳しく説明したMSDNリンクを次に示します。
ビットフィールドは、一般的にこれを行うための1つの「正しい」方法ですが、年の初めから数秒だけを保存するのはなぜですか?これらを快適に保存するには4バイトで十分です。実際、1970年から2038年までの秒を保存するには4バイトで十分です。その年から他の情報を取得するのは、現在の年を知っている限りは簡単な練習です。関心のある時間範囲は70年未満です(さらに、タイムスタンプを68年の範囲にグループ化し、各範囲のオフセットを保存することもできます)。
別の解決策は、1つの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;
2秒の精度を処理できる場合、MS-DOSタイムスタンプ形式では16ビットを使用して日付(1980年を7ビット、月を4、日を5)、時間を16ビット(時間を5、分は6、秒は5)。 Arduinoのようなプロセッサでは、16ビット境界を越えて値を分割するコードを書くことができるかもしれませんが、そのような分割を避けることができればコードはより効率的だと思います(MS-DOSが2秒を受け入れることでしたように)正確さ)。
そうでない場合は、別の回答で述べたように、32ビットの秒数を使用すると、「カレンダー形式」で物事を追跡しようとするよりも、いくつかの基本時間がより効率的であることが多いためです。カレンダー形式の日付から次の日付に進める必要がある場合、それを行うコードは、カレンダーの日付と線形日付を変換するコードよりも簡単かもしれませんが、他の多くのことを行う必要がある場合(偶数日付から前の日付に戻ります)入力または表示されたときに日付を線形形式に変換したり、日付を線形形式に変換したりする必要があります。そうでなければ、単に秒の線形数で動作します。
うるう年の3月1日を基準日として選択すると、線形の秒数での作業がより便利になります。次に、日付が1461を超えている間に、日付からその日付を減算し、年に4を加算します(Arduinoでは16ビットの比較と減算が効率的であり、2040でもループは単一の16x16除算よりも時間がかかりません)。日付が364を超える場合は、365を減算して年を増やし、さらに2回まで試行します[3回目の減算後の日付が365の場合、そのままにします]。
すべてのコーナーケースが正しく機能するように注意する必要がありますが、8ビットまたは16ビットの小さなマイクロでも、変換は驚くほど効率的です。