待機電流の極めて少ない非接触スイッチ

待機電流の極めて少ない非接触スイッチ

待機電流の極めて少ない非接触スイッチ

はじめに

野外に設置する防水仕様のIoT機器において、電源スイッチを取り付ける際、ケースにスイッチの取り付け穴をできるだけ開けたくないという要望がある。そのためケースの防水カバーのネジを外して基板上の電源スイッチをON/OFFしなければならない手間があった。そこでケースに穴を開けることなく、ケースの外から磁石により電源ON/OFFが可能な非接触スイッチを実現することを考えた。


動作仕様

  • スイッチのON/OFF動作がLEDの点滅の仕方で分かるようにする。
  • 磁石の接近を検出し、さらに一定時間近づけたままにするとOFF→ON、ON→OFFとスイッチの状態が変わるようにする。
  • スイッチ状態変化後の待機時の消費電流が極力少なくなるようにする。

実現方法

  • スイッチにはPチャネルMOSFETを使用し、電源ラインのプラス側をON/OFFする。
  • スイッチ制御には時間計測やLED点滅制御が容易で、かつ待機中は低消費電流化できるマイコンを使用する。
  • マイコンは低速クロックで駆動し、待機時にはスリープモードを使用し消費電流を押さえる。
  • 磁石の検出にはリードスイッチを使用する。

部品の選定

安価で秋月電子通商などで入手が容易であることを考慮し、以下の部品で組み立てることにした。

  • 磁石検出:表面実装用リードスイッチ SP3-1A16
  • スイッチ:PchチップMOSFET DMG3415U(20V4A)
  • マイコン:AVRマイコン ATTINY202-SSNR
  • その他 :SOP8(1.27mm)DIP変換基板、ユニバーサル基板、LED、C、R少々

回路図と基板の組み立て

上記部品を使用して構成した回路図を図1に示す。電源ON/OFF可能な電圧はマイコンが動作可能な5V以下である。GPIO0にリードスイッチ、GPIO1にLED、GPIO3にMOSFETスイッチが接続される。GPIO5はATTinyマイコンの書込みインタフェース UPDI(Unified Program and Debug Interface)である。

図1 回路図

25mm×15mmのユニバーサル基板上に部品を実装した様子を写真1に示す。

写真1 基板外観

ATtiny202に書き込むスケッチ

スケッチの生成はGeminiを使用して行った。Geminiに指定した要件は以下の通り。

  • クロック周波数は超低速クロック 32.768 kHz にセットする
  • 通電後はMOSFETスイッチをOFFにしsleepさせる
  • 磁石を検出したらマイコンを起動しLEDを点灯する
  • 検出したまま3秒経過するとMOSFETスイッチをONの通電状態とする
  • ONになったことが分かるようにLEDを長い間隔で2回点滅させる
  • ONにした後にはマイコンをsleepさせる。
  • 通電状態で磁石を3秒間検出するとMOSFETスイッチをOFFの非通電状態とする
  • OFFになったことが分かるようにLEDを短い間隔で5回点滅させる
  • OFFにした後にはマイコンをsleepさせる。

以上の要件で生成(一部手直し)したスケッチをリスト1に示す。

#include <avr/sleep.h>
#include <avr/power.h>
#include <util/delay.h>

// ピンの定義
const int BUTTON_PIN = 0; // 物理2番ピン (PA6)
const int LED_PIN    = 1; // 物理3番ピン (PA7)
const int POWER_PIN  = 3; // 物理5番ピン (PA2)
const unsigned long LONG_PRESS_COUNT = 10; // クロック調整による実時間約3秒

// 現在の電源状態を保持するフラグ(false = OFF, true = ON)
bool isPowerOn = false;

void goToStandbySleep() {
  set_sleep_mode(SLEEP_MODE_STANDBY);
  // 物理2番ピン(PA6)のピン割り込みをLOWレベル検出に設定
  PORTA.PIN6CTRL = PORT_ISC_LEVEL_gc;
  sleep_enable();
  sei();
  sleep_cpu(); // sleep(タイマーも全停止)
  // ----------- wakeup後 -----------
  sleep_disable();
  // チャタリングによる連続割り込みループを防ぐため、即座に割り込みを禁止
  PORTA.PIN6CTRL = PORT_ISC_INTDISABLE_gc;
  PORTA.INTFLAGS = PORT_INT6_bm; // 割り込みフラグをクリア
}

// ボタン押下(PA6)の割り込みサービスルーチン(wakeup時に必須)
ISR(PORTA_PORT_vect) {
  PORTA.INTFLAGS = PORT_INT6_bm;
}

void setup() {
  // 未使用ピン(PA1, PA3)の入力バッファを無効化して省電力化
  PORTA.PIN1CTRL = PORT_ISC_INPUT_DISABLE_gc;
  PORTA.PIN3CTRL = PORT_ISC_INPUT_DISABLE_gc;
  // メインクロックを手動で内蔵32kHz(OSCULP32K)に変更
  _PROTECTED_WRITE(CLKCTRL.MCLKCTRLA, CLKCTRL_CLKSEL_OSCULP32K_gc);
  _PROTECTED_WRITE(CLKCTRL.MCLKCTRLB, 0x00); // 分周なし
  pinMode(BUTTON_PIN, INPUT);
  pinMode(LED_PIN,    OUTPUT);
  pinMode(POWER_PIN,  OUTPUT);
  digitalWrite(LED_PIN,   LOW);
  digitalWrite(POWER_PIN, HIGH); // 初期状態はHighで電源OFF
  // 初回電源ON時、すぐにスリープさせます
  goToStandbySleep();
}

void loop() {
  // スリープから復帰するとここからスタート
  // ----------------------------------------------------
  // 【1. 起動直後の長押し判定】
  // ----------------------------------------------------
  unsigned long pressCounter = 0;
  bool isLongPressed = true;
  digitalWrite(LED_PIN, HIGH); // 磁石を検出したことが分かるようにLEDを点灯
  while (pressCounter < LONG_PRESS_COUNT) {
    if (digitalRead(BUTTON_PIN) == HIGH) {
      isLongPressed = false;
      break;
    }
    _delay_ms(10); // 1MHz計算の10msは、32kHz環境では実時間「312.5ms」になる
    pressCounter++;
  }
  // 3秒長押しされていなければ、状態を変えずにそのままSleepに戻る
  if (!isLongPressed) {
    digitalWrite(LED_PIN, LOW);
    goToStandbySleep();
    return; // loopの先頭(goToStandbySleep)へ
  }
  // ----------------------------------------------------
  // 【2. トグル動作:電源状態の反転処理】
  // ----------------------------------------------------
  if (isPowerOn == false) {
    // 現在OFFなら「電源ON」にする
    isPowerOn = true;
    digitalWrite(POWER_PIN, LOW); // MOSFET制御信号Lowで電源ON
    // LEDを長い間隔で2回点滅して通知
    for (int i = 0; i < 3; i++) {
      digitalWrite(LED_PIN, HIGH);
      _delay_ms(20);
      digitalWrite(LED_PIN, LOW);
      _delay_ms(20);
    }
  } else {
    // 現在ONなら「電源OFF」にする
    isPowerOn = false;
    digitalWrite(POWER_PIN, HIGH); // MOSFET制御信号Highで電源OFF
    // LEDを短い間隔で5回点滅して通知
    for (int i = 0; i < 6; i++) {
      digitalWrite(LED_PIN, HIGH);
      _delay_ms(6);
      digitalWrite(LED_PIN, LOW);
      _delay_ms(6);
    }
  }
  // ----------------------------------------------------
  // 【3. 処理完了:即座にスタンバイへ】
  // ----------------------------------------------------
  // ボタンが押しっぱなしの状態でスリープに入ると即復帰してしまうため、
  // 一度ボタンが離される(HIGHになる)まで完全に待ちます
  while (digitalRead(BUTTON_PIN) == LOW) {
    _delay_ms(5);
  }
  _delay_ms(5); // 離された瞬間のチャタリング防止
  // 再び次の「3秒長押し」を待つためにsleepします
  goToStandbySleep();
}
リスト1 ATtiny202に書き込むスケッチ

実際のIoT機器に組み込み動作を確認する

防水ケースに組み込んだIoT機器に本スイッチを実装した状態を写真2に示す。ケースの外から磁石を近づけると、本スイッチのLEDが点滅し、スイッチの状態が確認できる。

写真2 実装例

待機時の電流測定

電源電圧3.3VのIoT機器の電源スイッチとして適用したときの本スイッチの消費電流をPPK2により測定した。図2にOFF時の消費電流、図3にON時の消費電流を示す。スイッチ状態がOFFでsleepした時の平均消費電流は0.19uA、スイッチ状態がONでsleepした時の平均消費電流は0.27uAと、極めて少ない待機電流となることが確認できた。

図2 OFF状態での待機電流(3.3V時)
図3 ON状態での待機電流(3.3V時)