メロディーをつける

2020年12月16日

使ってる加湿器は安価な沸騰式の物、給水警告は赤色のLEDランプのみ
加湿器が置いてあるのは机に向かっていると背中側なので見えない!
メロディーとかブザー実装するの数十円でしょ?なんで付けないの?

加湿器メロディー追加ガジェット

ブザーかなんか仕込んで音なる様に改造しちゃおうと思ったけど、そういえば
居間で使ってるのも同じようにLEDだけの給水警告だったなと思い出して
それなら外付けで警告灯を感知して音を鳴らすガジェット作れば良いじゃん!

で作ったんです、赤色LEDを読み取ってガジェット側の赤色LEDを点灯させてメロディーを流す、ボタンを押すとLEDは点灯したままでメロディーが消える、給水や加湿器の電源をOFFにして本体の給水警告LEDが消灯するとガジェット側のLED消灯、メロディーOFFという物、常時監視なのでプロトタイプはUSB給電式

スポンサーリンク

部品と製作過程

フリスクケース風のケースを買ってきてパーツ選定をして、プロトタイプだからケガキ線とか隠さず穴明けして、専用のユニバーサル基板に部品配置をして確認

回路図とコード

int spk = 2; //スピーカー
int ssw = 0; //ストップスイッチ
int led = 1; //LED
int cds = A3; //cds
int vol = A2; //可変抵抗

int vol_val = 0; //可変抵抗値
int cds_val = 0; //cds値
int ssw_val = 0; //ストップスイッチ値
int load_flg = 0; //動作フラグ

void setup() {
  pinMode(spk, OUTPUT);
  pinMode(ssw, INPUT_PULLUP);
  pinMode(led, OUTPUT);
}

void loop() {
  vol_val = analogRead(vol); //可変抵抗値(0-1023)
  cds_val = analogRead(cds); //cds値(0-1023)
  ssw_val = digitalRead(ssw); //ストップスイッチ値(HIGH & LOW)

  if(load_flg <= 1){
    if(cds_val < vol_val){
      if(ssw_val == HIGH){
        load_flg = 1;
      }else{
        load_flg = 2;
      }
    }else{
      load_flg = 0;
    }
  }else{
    if(cds_val > vol_val){
      load_flg = 0;
    }
  }
  load_main(load_flg);
}

int load_main(int val){
  if(val == 0){
    digitalWrite(led, LOW);
    digitalWrite(spk, LOW);
  }
  if(val == 1){
    digitalWrite(led, HIGH);
    digitalWrite(spk, HIGH);
  }
  if(val == 2){
    digitalWrite(led, HIGH);
    digitalWrite(spk, LOW);
  }
}

機能説明、右にある黒い大丸がスピーカー、その左の透明なのが赤色LED、その左下が光検知レベル調整用の可変抵抗、その左上がメロディーストップ用のスイッチ
光検知レベル調整用可変抵抗をつけておかないと、取り付ける環境が限られちゃいます、警告灯が付いていない状態で室内光では動作しないギリギリの所を各自設定できるようにということです
家電本体の警告灯が点灯すると、裏にあるCdSセルで光を感知して赤色LEDとメロディーON、その状態でスイッチを押すと赤色LEDがON、メロディーはOFF、警告灯が消灯すると、赤色LEDがOFF、メロディーもOFF

コードの行ごとの説明(基本的に上から下に向かって実行されます)
1-5は使用するマイコンの端子に名前を付けている場所
プログラムの中では例えば"spk"の中には数字の"2″が格納されています
行4と5は間違った書き方なんですが、何故かエラーが出ないのでスルーしていますw
本来[int]とはIntegerの略で整数という意味なんです、なので代入できるのは整数だけなので[A3]とか[A2]は代入できません、
ここの正しい書き方は[int cds = 3;]と[int vol = 2;]です、この値は行19,20で呼び出されます

7-10はプログラム内で使う値の名前付けと初期化をしています
12-16はプログラムが起動すると最初に1度だけ実行される部分で、デジタル入出力を行う3つのピンの初期設定をしています"OUTPUT"は出力をする端子"INPUT"は読み取る端子
18-39は繰り返し実行されるプログラムの中枢です
19-21はそれぞれの端子に繋がっている部品の情報を読み取っています、コードの後ろにある"//"以降は説明用のコメントです
行19は光検知レベル調整用可変抵抗の値、行20はCdSセル光可変抵抗器の値、行21はスイッチの状態
行23は「もしもload_flgが1と同じかそれより小さければ」という意味、初回起動時はload_flgは0なので行24へ、ここでload_flgが2なら行33に飛んでさらに「もしもCdSセル光可変抵抗器の値が光検知レベル調整用可変抵抗の値より大きければ」本体の警告灯は点灯していないのでload_flgを0に設定して行38へ、CdSセルは検知した光が明るいほど値は小さくなります
行24は「もしもCdSセル光可変抵抗器の値が光検知レベル調整用可変抵抗の値より小さければ」行25へ、逆なら行28へ、行25は「もしもスイッチが押されたら」load_flgを1にして行38へ、行28はload_flgを2にして行38へ
行38の中身は41-54、これまで設定してきたload_flgが行41以降はvalになります、行42は「もしもvalが0なら」赤色LEDもメロディーもOFF"LOW"とはその端子に電流を流さないという意味、流すなら"HIGH"です、行46は「もしもvalが1なら」赤色LEDもメロディーもON、行50は「もしもvalが2なら」赤色LEDはON、メロディーはOFF、この3つのどれかの処理をしたら、行39に戻って、行18に戻ってというのをループします

改造案

スリープ機能を付ければ電池でも動くんじゃない?
このケースは電池スペース付きのも売ってるよ!
LED付きスイッチにすればスペース少しあくしやってみよう!
そう思って電池の配置とその他のパーツの配置を検討して良い感じになったので
スリープを試してみよう!…

スポンサーリンク
#include <avr/sleep.h>
#include <avr/interrupt.h>

int spk = 2; //スピーカー
int ssw = 0; //ストップスイッチ
int led = 1; //LED
int cds = A3; //cds
int vol = A2; //可変抵抗

int vol_val = 0; //可変抵抗値
int cds_val = 0; //cds値
int ssw_val = 0; //ストップスイッチ値
int load_flg = 0; //動作フラグ

void setup() {
  pinMode(spk, OUTPUT);
  pinMode(ssw, INPUT_PULLUP);
  pinMode(led, OUTPUT);
}

void sleepNow()
{
  GIMSK |= _BV(PCIE);     // Enable Pin Change Interrupts
  PCMSK |= _BV(PCINT3);   // Use PB3 as interrupt pin
  ADCSRA &= ~_BV(ADEN);   // ADC off
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  sleep_enable();         // Sets the Sleep Enable bit
  sei();                  // Enable interrupts
  sleep_cpu();            // sleep

  cli();                  // Disable interrupts
  PCMSK &= ~_BV(PCINT3);  // Turn off PB3 as interrupt pin
  sleep_disable();        // Clear SE bit
  ADCSRA |= _BV(ADEN);    // ADC on

  sei();                  // Enable interrupts
}

ISR(PCINT0_vect) {
}

void loop() {
  sleepNow();
  vol_val = analogRead(vol); //可変抵抗値(0-1023)
  cds_val = analogRead(cds); //cds値(0-1023)
  ssw_val = digitalRead(ssw); //ストップスイッチ値(HIGH & LOW)

  if(load_flg <= 1){
    if(cds_val < vol_val){
      if(ssw_val == HIGH){
        load_flg = 1;
      }else{
        load_flg = 2;
      }
    }else{
      load_flg = 0;
    }
  }else{
    if(cds_val > vol_val){
      load_flg = 0;
    }
  }
  load_main(load_flg);
}

int load_main(int val){
  if(val == 0){
    digitalWrite(led, LOW);
    digitalWrite(spk, LOW);
  }
  if(val == 1){
    digitalWrite(led, HIGH);
    digitalWrite(spk, HIGH);
  }
  if(val == 2){
    digitalWrite(led, HIGH);
    digitalWrite(spk, LOW);
  }
}

スリープ追加しただけなのに動かない…なんで??
やりたいことは、加湿器の給水LEDがOFFの時はスリープ、給水LEDがONになると復帰というもの
某サイトからのコピペなのでこのスリープコードがあってるかは検証出来てないんだけど、それ以前の問題があったんです、これスリープ出来ないじゃん!!
ATtiny85でPB3を割り込みピンにすると監視できるのはChangeだけ、監視対象のピンの電圧が変化したら復帰という物
監視対象はCdSセル(光可変抵抗器)これは当たる光の強さが強いほど抵抗値が低くなるという性質があるんだけど、所謂化学反応なので動きがアナログなんです
例えば部屋の中で部屋の照明があって、まわりで人が動いて、風が吹いて、室温が上がって、様々な要因で明るさは変化するので常時CdSが出す値は変化してるんですよ、プログラム上でなら許容範囲を設定できるんだけど、この割り込みというのは単純に変化があったらという感知しかできないので、常時スリープ解除状態、さらに仮にスリープが上手くいったとしても、CdSセルは検知するのに電源が必要なので、スリープしちゃうと光の変化を検知できない!ATtiny85を使う方法ではスリープは無理=電池駆動は無理という結論

検討中のとプロトタイプ

電池駆動を捨てると、今の半分くらいのサイズに出来るので、具合の良いケースを探して小型化をしようと思います、回路は一緒、部品も一緒なのでケースさえ選定出来ればすぐ作れる