ビット演算によるレジスタ・フラグ操作
| 設計内容分類 | 組み込みソフトウェアにおけるC言語記述 |
|---|
実現したい仕様・課題
マイコンのレジスタや制御フラグでは、1つの変数(レジスタ)の中の特定ビットだけを操作したい場面が頻出します。値を丸ごと代入すると他のビットの設定を破壊してしまい、周辺機能が意図せず停止・変化する不具合につながります。目的のビットだけを安全に操作したいというのが課題です。
設計のポイント
特定ビットの操作は、ビット演算の定型パターンで記述します。ビットnのセットは reg |= (1 << n);(OR演算:対象ビットのみ1になり他は保持)、クリアは reg &= ~(1 << n);(反転マスクとのAND:対象ビットのみ0)、反転は reg ^= (1 << n);(XOR)、判定は if (reg & (1 << n)) です。複数ビットのフィールドを書き換える場合は、いったんフィールドをマスクでクリアしてから値をORで書き込みます(reg = (reg & ~MASK) | (value << pos);)。ビット位置やマスクは数値の直書きではなく、#defineやenumで意味のある名前を付けて定義し、コード上で「どの機能のビットを操作しているか」が読めるようにします。実装上の注意として、レジスタへのビット操作は内部的に読み出し・変更・書き戻し(リード・モディファイ・ライト)の手順であるため、同じレジスタをメインと割り込みの両方から操作する場合は途中で割り込まれると更新が失われる競合が起こり得ます。競合の可能性がある箇所は割り込み禁止で保護するか、マイコンが備えるセット専用/クリア専用レジスタ(書いたビットだけが反映されるレジスタ)を利用します。また、書き込み専用レジスタは現在値を読み出せないため、設定値を保持するシャドウ変数を設けて管理します。シフト量が型のビット幅以上になる記述は未定義動作のため、32bit幅なら (1UL << n) のように定数の型にも注意します。
【コード例】
#define LED_BIT (1U << 3)
#define MODE_MASK (3U << 4)
reg |= LED_BIT; // ビットセット(他ビット保持)
reg &= ~LED_BIT; // ビットクリア
reg ^= LED_BIT; // ビット反転
if (reg & LED_BIT) { ... } // ビット判定
// フィールド書き換え:クリアしてからOR
reg = (reg & ~MODE_MASK) | (2U << 4);
補足情報
設計のポイント 一覧
組み込みソフトウェアにおけるC言語記述のポイント
- リングバッファで受信データを取りこぼさない
- switch-caseによるステートマシンの実装
- 割り込みハンドラは短く書く
- constを活用する(ROM配置と書き換え防止)
- ビット演算によるレジスタ・フラグ操作
- 固定幅整数型(stdint.h)を使う
- volatile修飾子を正しく使う
- 構造体の宣言にpackedを指定する
- ソースコードのエンディアン変換
- sizeofを使用する
- 特殊文字の記述にエスケープ文字を使用する
- 変数の初期化漏れを防ぐ
- 外部バスの使用
- sprintf関数を使う
- 列挙型(enum)を使う
- 構造体を使う
- 標準関数を使う
- 条件演算子を使う
- インクリメント演算子を使う
- C言語記述の際はアプリ層とドライバ層に分ける



