本記事では、安全性と信頼性が極めて高く求められる組み込みシステムにおいて、振動モーター(バイブレータ)を制御するための実践的なコーディング手法を紹介します。自動車、医療機器、産業機器などで標準的に用いられる**MISRA C:2012(Motor Industry Software Reliability Association)**の「命令(Directives)」および「ルール(Rules)」を厳守した、堅牢な実装モデルを段階的に解説します。
1. 基本的なバイブレータ制御の実装
まずは、PWM(パルス幅変調)を用いて振動強度を制御する最もシンプルなモジュールです。
実装の前提
- マイコン: STM32, RL78, Aurix 等の汎用組み込みマイコン。
- 制御方式: PWM Duty比(0.1%単位、0〜1000)による強度調整。
- 安全性: 未初期化状態での動作防止、範囲外入力のガード。
/*=============================================================================
* ファイル名 : vibrator_control.c
* 概要 : 振動モーター制御モジュール(MISRA C:2012 準拠)
*============================================================================*/
#include <stdint.h> /* Rule 21.1: 固定幅整数型の使用 */
#include <stdbool.h>
#include "vibrator_hw.h"
/* 定数定義(Rule 8.9: 局所的な定数はファイル内に限定) */
#define VIBRATOR_MAX_DUTY UINT16_C(1000) /* 100.0% */
#define VIBRATOR_DEFAULT_DUTY UINT16_C(300) /* 30.0% */
typedef uint16_t VibratorDuty_t;
/* 内部状態変数(Rule 8.7: staticによる外部参照の制限) */
static VibratorDuty_t current_duty = VIBRATOR_DEFAULT_DUTY;
static bool is_vibrator_initialized = false;
/* 静的関数プロトタイプ */
static void Vibrator_SetPwmDuty(VibratorDuty_t duty);
/**
* @brief 振動モーター制御の初期化
*/
void Vibrator_Initialize(void)
{
Vibrator_Hw_Init(); /* ハードウェア依存部 */
Vibrator_SetPwmDuty(VIBRATOR_DEFAULT_DUTY);
is_vibrator_initialized = true;
}
/**
* @brief 振動強度の設定
* @param duty 0-1000 (0.0%-100.0%)
*/
void Vibrator_SetIntensity(uint16_t duty)
{
VibratorDuty_t safe_duty;
/* 防御的プログラミング:範囲チェック(Rule 1.3 / 14.4) */
if (duty > VIBRATOR_MAX_DUTY)
{
safe_duty = VIBRATOR_MAX_DUTY;
}
else
{
safe_duty = duty;
}
if (is_vibrator_initialized)
{
Vibrator_SetPwmDuty(safe_duty);
current_duty = safe_duty;
}
}
/**
* @brief ハードウェアレジスタへの書き込み(内部用)
*/
static void Vibrator_SetPwmDuty(VibratorDuty_t duty)
{
/* Rule 11.3: volatileポインタを介したメモリアクセス */
uint32_t const reg_val = ((uint32_t)duty * PWM_PERIOD_COUNTS) / VIBRATOR_MAX_DUTY;
*PWM_CCRx_REG = reg_val;
}2. 通知パターン生成とキューイング
単一の振動だけでなく、「ブッ、ブッ」という短通知や**「ドクン、ドクン」という心拍風**のパターンを非同期で実行するための機能を実装します。
パターン定義の構造
パターンは、振動のON時間・OFF時間・強度の組み合わせをテーブル(const構造体配列)として定義します。これにより、コード変更なしに新しい振動表現を追加でき、保守性が向上します。
typedef struct {
VibratorDuty_t duty;
uint16_t on_ms;
uint16_t off_ms;
} VibratorStep_t;
/* パターン定義(ROM領域への配置を推奨) */
static const VibratorStep_t pattern_heartbeat[2] = {
{ UINT16_C(500), UINT16_C(60), UINT16_C(80) },
{ UINT16_C(300), UINT16_C(80), UINT16_C(300) }
};
