2020年3月23日月曜日

電磁調理器の信号線を引き出してArduinoで制御してみた


背景

アイリスオーヤマの電磁調理器(IHクッキングヒーター)が約5000円で売られています。



以前、これの1つ前の型(以前勤めていた会社の備品)をソレノイドで制御したり、スピーカーを外して操作音を消したりしたことがあります。

信号線を引き出せばソレノイドを使わずともArduinoで制御出来ると思ったので、新しい型の電磁調理器を買って改造してみました。
備忘録を兼ねて情報を共有します。

使ったもの

  • アイリスオーヤマ 電磁調理器(IHクッキングヒーター1400W IHK-T35)
    改造対象です。
  • ドライバー
    電磁調理器のケースを開けるのに使います。
  • 耐熱電子ワイヤー + ワイヤストリッパ
    信号線の引き出しに使います。
  • ハンダごて + はんだ
    信号線引き出しのためのワーやーを基板に付けます。
  • ビニールテープ + マジック + ハサミ
    引き出した信号線に名前を書いて貼ります。
  • Arduino Nano + USB miniBケーブル
    信号線に対して、信号を読み取ったり、信号を書き込んだりします。
  • Analog Discovery2
    信号を解析します。
  • USBポートが付いたPC
    Arduinoへのプログラム書き込みと、AnalogDiscoveryを利用した波形の読み取りに利用します。
  • ブレッドボード
    信号線をArduinoなどの部品と接続します。
  • n-ch mosfet + ダイオード + 1kΩ抵抗
    ボタンの操作と同様の信号を作る回路を作ります。
  • ジャンパワイヤ
    ブレッドボードに刺した部品や信号線を接続します。

中を見る

信号線の引き出しと構造解析のめに分解します。

電磁調理器本体裏側のネジを取ります。


ラベルにネジ穴のような凹みがありますが、ネジ穴では無いのでラベルは破らなくても良いです。


開きました。


底側の調査

コイルの上にはサーミスタらしき物が設置されていました。
この抵抗を読み取れれば、鍋底の温度が分かるかもしれません。


ネジを外してコイルを持ち上げ、コイルと基板を接続するコネクタ2つを外すと、本体の基板が見えます。



ネジを外して裏側を見ると、 こうなっていました。


サーミスタに接続するコネクタは、片方が5V、片方が3kΩを通してGNDに接続していることがテスターで調べたことにより分かりました。
ということで、3kΩでGNDに繋がっている線を引き出します。


裏側だとこの辺です。
ここに耐熱電子ワイヤをはんだ付けして、信号線を引き出しました。


スピーカーの横にある表側へ繋がるコネクタは、端がVCCで2番目がGNDのようです。


操作音を消したい方は、端の方にあるスピーカーのハンダをハンダごてで溶かしてスピーカーを引き抜いてください。


表側の調査

表側はガラスの天板にプラスチックの枠が付いている構造です。
中央にはサーミスタの伝導性を高めるのが目的だと推測できるグリスが塗られています。


8個のLEDと4個のスイッチを5本の信号線で制御するようです。
4本のネジで留められています。





基板の裏側中央にはシフトレジスタSN74LS164があり、これを利用して5本の信号線で複数のLEDとボタンを制御しているようです。


テスターで調べつつ、役割を書き込みました。


コネクタの線はこのようになっていました。
  1. VCC(5V)
  2. GND
  3. シフトレジスタのCLK
  4. シフトレジスタのAB
  5. LEDのGND(カソード)

回路図を書くとこうなります。
(KEY4とR12が飛ばされているので、製品によってはボタンが増えそうです。)


コネクタの5本とシフトレジスタの1〜8に耐熱電子ワイヤをはんだ付けして信号を引き出します。


信号線を出す

底側と表側を合わせた状態にしないと動作確認しにくいため、穴を空けて信号線をケースの外に引き出します。

電源ボタンの下に信号線を引き出すための穴を空けました。
写真の穴では足りずに後で大きくしたので、この写真の1.5〜2倍位の穴を空けるのが良いです。


ケースの外に出した線には、何の役割か分かるように役割を書いたビニールテープを貼り付けていきます。


全部出ました。


底と表を合わせます。


引き出した信号線をブレッドボードに刺して、解析します。


信号を解析

オシロスコープ(Analog Discovery2)を利用して信号の様子を見たり、実験したりして、分かったことを共有します。

電磁調理器に100Vが供給されていれば、VCCから電源OFFでも5Vが給電される

ボタンの状態を監視するために、コンセントに繋がっていれば5Vが給電されるようです。


1.5ミリ秒ごとにLED_GNDがLOWになり、CLK+ABでシフトレジスタの値が更新され、ボタンの状態を確認している

CLKは1.5ms毎に情報を送信していました。


1.5ms毎にくる信号のCLK(青色)とAB(黄色)を詳しく見ると、速い信号 -> ゆっくり目の信号 -> 速い信号で状態が変わっていました。
最初の速い信号でボタン状態測定用出力を設定、ゆっくり目の信号でボタンの状態を測定、終わりの速い信号でLEDの状態を設定、という処理を行っていると自分は推測します。


CLK(青色)とLED_GND(黄色)を見ると、CLKが振動している間はLED_GNDがHIGHになり、LEDが光らない状態になっていました。


LED_GNDがLOWになったときのLEDの状態を見れば、電磁調理器の現在状況を把握できます。

MOSFET + ダイオードの回路でボタン操作と同様の信号を出せる

MOSFET単体だと逆流する信号の流れを止められずに期待通りに動作しませんでしたが、ダイオードを追加によりMOSFETのゲート操作でボタンと同様の動きをさせられました。
下記の繋ぎ方をすると、加熱電源ボタンを押したのと同じ信号をPIN_POWER_NORMALに送信でき、電源のON・OFF制御ができました。


サーミスタは100℃で約700mV、20℃で約120mVになる

鍋の水を沸騰させて、数分放置したときの電圧は約700mVでした。


室温20℃弱の部屋に放置したときの電圧は約120mVでした。


電源ON時はサーミスタの電圧に波が出る

内蔵されたマイコンの電圧測定処理の影響なのか、コイルの昇圧の影響なのか、電源がONの時は波が出ました。
自分が見た時はOFF時の電圧は波の中央位の値だったので、電源ON時にサーミスタの電圧を測る際は、複数回測定して平均値を取るのが良さそうです。


Arduinoに繋げる

LEDの状況把握、ボタンの操作、サーミスタの電圧測定を行う回路を組みます。

回路図はこちらです。



繋げるとこうなりました。


Arduinoのプログラム

先ほどの回路図の接続から信号を制御し、下記の動作を繰り返し行うプログラムです。
ボタン操作と同じ動作をしたあとは、シリアル通信で情報を送信しています。
  1. 加熱電源操作
  2. 弱く x 2
  3. 強く x 5
  4. 加熱電源操作
  5. 10秒待つ
#define PIN_LED_GND 2
#define PIN_CLK 3
#define PIN_AB 4
#define PIN_SIG_1 A0
#define PIN_SIG_2 A1
#define PIN_SIG_3 A2
#define PIN_SIG_4 A3
#define PIN_SIG_5 10
#define PIN_SIG_6 11
#define PIN_SIG_7 12
#define PIN_SIG_8 13
#define PIN_POWER_NORMAL 8
#define PIN_POWER_OIL 7
#define PIN_POWER_UP 6
#define PIN_POWER_DOWN 5
#define PIN_ANALOG_THERMISTOR 6 // analog pin
#define BUFFER_MS_TO_DETECT_OFF 1000UL
#define ANALOG_MAX 1023
#define VOLT_100C 0.7
#define VOLT_20C 0.12
class PowerState {
public:
unsigned long changedAt;
bool powerNormal = false;
bool powerOil = false;
bool isError = false;
unsigned long readErrorAt;
int level = 0;
PowerState() {
changedAt = 0;
powerNormal = 0;
powerOil = false;
readErrorAt = 0;
level = 0;
};
void updateChangedAt() {
changedAt = millis();
}
void updateByReadingPins() {
bool level1 = digitalRead(PIN_SIG_1);
bool level2 = digitalRead(PIN_SIG_2);
bool level3 = digitalRead(PIN_SIG_3);
bool level4 = digitalRead(PIN_SIG_4);
bool level5 = digitalRead(PIN_SIG_5);
bool level6 = digitalRead(PIN_SIG_6);
bool powerNormal = digitalRead(PIN_SIG_7);
bool powerOil = digitalRead(PIN_SIG_8);
int level = 0;
if (level6 && !level5) level = 0; // check 5 to detect error
else if (level6) level = 6;
else if (level5) level = 5;
else if (level4) level = 4;
else if (level3) level = 3;
else if (level2) level = 2;
else if (level1) level = 1;
if (level1 && !level2 && level6) {
this->readErrorAt = millis();
if (!this->isError) {
this->isError = true;
this->updateChangedAt();
}
} else if (powerOil) {
if (!this->powerOil || this->level != level) {
this->powerOil = true;
this->powerNormal = false;
this->level = level;
this->updateChangedAt();
}
} else if (powerNormal) {
if (!this->powerNormal || this->level != level) {
this->powerOil = false;
this->powerNormal = true;
this->level = level;
this->updateChangedAt();
}
} else {
// LEDが消えていてもエラー時の点滅の場合があるので、一定時間LEDが消えていたら電源OFFと判定する
if ((this->powerNormal || this->powerOil) && (!this->isError || millis() - this->readErrorAt > BUFFER_MS_TO_DETECT_OFF)) {
this->powerOil = false;
this->powerNormal = false;
this->isError = false;
this->updateChangedAt();
}
}
}
void printInfo(HardwareSerial *serial) {
String powerStr = "power: ";
powerStr += powerNormal ? "on normal" : powerOil ? "on oil" : "off";
serial->println(powerStr);
serial->println("level: " + String(level));
String errorStr = "isError: ";
errorStr += isError ? "true" : "false";
serial->println(errorStr);
serial->println("changedAt: " + String(this->changedAt));
}
};
PowerState powerState = PowerState();
void onFallingLedGnd() {
powerState.updateByReadingPins();
}
void setup() {
pinMode(PIN_CLK, INPUT);
pinMode(PIN_AB, INPUT);
pinMode(PIN_LED_GND, INPUT);
pinMode(PIN_SIG_1, INPUT);
pinMode(PIN_SIG_2, INPUT);
pinMode(PIN_SIG_3, INPUT);
pinMode(PIN_SIG_4, INPUT);
pinMode(PIN_SIG_5, INPUT);
pinMode(PIN_SIG_6, INPUT);
pinMode(PIN_SIG_7, INPUT);
pinMode(PIN_SIG_8, INPUT);
pinMode(PIN_POWER_NORMAL, OUTPUT);
pinMode(PIN_POWER_OIL, OUTPUT);
pinMode(PIN_POWER_DOWN, OUTPUT);
pinMode(PIN_POWER_UP, OUTPUT);
attachInterrupt(digitalPinToInterrupt(PIN_LED_GND), onFallingLedGnd, FALLING);
Serial.begin(9600);
}
void switchPower(int pin) {
digitalWrite(pin, HIGH);
delay(100);
digitalWrite(pin, LOW);
delay(10);
}
float readVolt() {
return (float) analogRead(PIN_ANALOG_THERMISTOR) * 5 / ANALOG_MAX;
}
float voltToTemperature(float v) {
float c = (((v - VOLT_20C) / (VOLT_100C - VOLT_20C)) * (100 - 20)) + 20;
return c;
}
void printInfo() {
powerState.printInfo(&Serial);
float v = readVolt();
float c = voltToTemperature(v);
Serial.println("Thermistor volt: " + String(v) + "v");
Serial.println("Temperature: " + String(c) + "C");
Serial.println("at " + String(millis()));
Serial.println();
}
void loop() {
switchPower(PIN_POWER_NORMAL);
printInfo();
delay(500);
switchPower(PIN_POWER_DOWN);
printInfo();
delay(500);
switchPower(PIN_POWER_DOWN);
printInfo();
delay(1000);
switchPower(PIN_POWER_UP);
printInfo();
delay(500);
switchPower(PIN_POWER_UP);
printInfo();
delay(500);
switchPower(PIN_POWER_UP);
printInfo();
delay(500);
switchPower(PIN_POWER_UP);
printInfo();
delay(500);
switchPower(PIN_POWER_UP);
printInfo();
delay(500);
switchPower(PIN_POWER_NORMAL);
printInfo();
delay(10000);
}

動作の様子

電源のON・OFF、強弱調整ができています。



USBでPCに接続すれば電磁調理器の状態を確認できます。



このように、「電源の状態、強さ、エラーの有無、状態変化時の時間、サーミスタの電圧、その電圧から推測できる温度」を取得できます。
power: on normal
level: 6
isError: false
changedAt: 21165
Thermistor volt: 0.31v
Temperature: 45.92C
at 21283

power: off
level: 6
isError: false
changedAt: 21828
Thermistor volt: 0.31v
Temperature: 46.59C
at 21944

まとめ

アイリスオーヤマの電磁調理器の下記の情報をArduinoで取得や制御できました。
  • 電源のON・OFF
  • 強弱の調整
  • 現在の強さ
  • エラー
  • 天板(コイル上部のサーミスタ)の温度(大まかな計算式なので誤差±10℃)
シフトレジスタを利用してLEDの制御とボタンの情報取得する形式だったので手間取りましたが、Arduinoで制御できる仕組みを作れて良かったです。

更新履歴

2020.04.04
表側の基板の回路図のコネクタのピン割り当て順が逆だった(5Vが割り当てられていたのは1番ではなく最後の5番だった)ので修正しました。
MOSFET + ダイオードの説明文が途中で終わっていたので追記しました。
2020.06.13
利用していたシフトレジスタの型番を間違えてSN74HC164としていたので、正しくSN74LS164に修正しました。

0 件のコメント :