【概要】
millis() 関数は、Arduino環境においてマイコンボードの電源投入(またはリセット)時からの経過時間をミリ秒(ms)単位で取得する関数です。この関数は、実行を停止させる delay() 関数とは対照的に、現在の時刻を返すのみであるため、非同期的なタスク処理(マルチタスクのシミュレーション)を実装する際の基礎的なツールとして利用されます。
【仕様】
- 戻り値:
unsigned long(32ビット符号なし整数) - 単位: ミリ秒 (ms)
- 初期状態: システム起動直後の値は0から開始し、約1ミリ秒ごとにインクリメントされる。
- 分解能: 1ミリ秒。それ以下の精度が必要な場合は
micros()を使用する。 - 最大値: 4,294,967,295 ms。これは約49.71日に相当する。
【技術的特徴】
- 非ブロッキング動作:
delay()はCPUの実行を一時停止させるのに対し、millis()は現在の時刻を取得するだけであるため、取得した時刻と前回の実行時刻を比較することで、特定の時間が経過したか判定する手法が一般的です。 - ハードウェアとの関連: 内部的には、ハードウェアタイマーのカウント値をミリ秒単位に変換して取得しています。
- 比較表:
| 関数 | 特徴 | 主な用途 |
|delay()| 実行を一時停止。同期処理。 | 単純な待機、タイミングの調整。 |
|millis()| 現在時刻を返す。非同期処理。 | 周期的なタスク、複数の同時動作。 |
|micros()| マイクロ秒単位の時刻を返す。 | 高速な信号処理、精密なタイミング。 |
【注意点】
- オーバーフロー(Rollover):
millis()は約49.7日で最大値に達し、0に戻ります。この挙動を考慮しない計算(例:millis() > threshold)は、オーバーフロー発生時に誤作動を引き起こします。正しく動作させるには、常に差分を比較する手法(例:currentMillis - previousMillis >= interval)を用います。この手法であれば、オーバーフローが発生しても正しく動作します(無符号整数の減算特性を利用)。 - データ型の遵守: 戻り値は
unsigned longです。int型などの小さな型に代入すると、約32.7秒でオーバーフローが発生するため、必ず適切なデータ型を使用してください。 - 割り込みの影響:
millis()は通常、タイマー割り込みによって更新されます。極めて高い精度が必要な極短時間の計測では、割り込みのレイテンシが影響を与える可能性があることに留意してください。
【サンプルコード】
/*
* millis() を使用した非ブロッキングのLED点滅処理
* delay() を使用せず、他の処理を同時に実行可能な構造です。
*/
unsigned long previousMillis = 0;
const long interval = 1000;
int ledState = LOW;
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
}
void loop() {
unsigned long currentMillis = millis();
// 1000ms(1秒)経過したか判定
if (currentMillis - previousMillis >= interval) {
// 前回の実行時刻を更新
previousMillis = currentMillis;
// 状態を反転
if (ledState == LOW) {
ledState = HIGH;
} else {
ledState = LOW;
}
digitalWrite(LED_BUILTIN, ledState);
// ここに他の処理を記述しても、点滅のタイミングは維持される
}
}
【活用例】
- 状態遷移マシン (FSM): 特定の入力条件を満たした後、一定時間待機してから次の状態へ遷移するロジックの実装。
- 周期的なセンサーサンプリング: センサーの値を一定の周期(例:50msごと)で取得しつつ、他の通信処理や表示処理を並行して実行する。
- 通信プロトコルのタイムアウト処理: 送信後のレスポンス待ち時間を計測し、一定時間を経過しても応答がない場合にエラー処理を実行する実装。


コメント