2016年1月8日金曜日

赤外線リモコンとLチカがあれば聴覚障害でもOK

私みたいに耳が悪いと何が不便って後ろで何が起こっているかわからないんですよね。「声をかける」というのが他人の注意を喚起する上で如何に有効なものであることか(詠嘆)。10mぐらい離れた人同士が会話しているのって、ほんと魔法みたいに見えます。

で、以前、赤外線リモコンのボタンを押すとLEDが点滅して誰かが呼んでいることを知らせてくれるデバイスを作りました。結構便利でした。

でもね、所詮はLED、仕事に夢中になっていると気づかないことも。

ということで、作りました。少し大きなリモコン付きのLチカを。


ビデオでは最大1wぐらいにおさえていますが、フル点灯30wの状態を直接見ると目が痛いです。

■材料■

プラットフォームはmbed、LPC1114FN28とLEDドライバと電源、それに赤外線受光器です。

以前、「普通の基板に表面実装パワーLEDを並べて何ワットぐらい点灯できるか?」を調べようとElecrowで起こした基板を引っ張りだしてきました。うーん、まだホームリフロー試行錯誤中だったので表面実装のハンダが汚いorz せっかく基板を作るのだからとファン駆動回路やPIR接続ピンなどインタフェースがてんこ盛りになっており、その1つとして「赤外線受光器インタフェース」も付いてます(実は基板見るまですっかり忘れてた)。よくある5v電源3ピンの赤外線受光器を挿すだけで使えます。なお、私が買ったものは5v電源を与えてもVoutが3vまでしか上がらないものだったので直結していますが製品や電源電圧によって異なります。買ってきたら出力電圧を確かめてもし3.3vを越えるようならば電源を3.3vにするか出力を抵抗で分圧してください。



手前の黒い直方体はDC/DCです。24vから3.3vまで落とすとさすがに通常の三端子レギュレータはかなり熱くなります。

LEDドライバはCL6807を3セット、電流検出用のシャント抵抗は0.1ΩなのでLED 7個ずつの各ストリングには1Aまで流せます。電源24vではVfの7倍にはちょっと足りないのですが、そこはマージン見越して動かしてます。なお、CL6807は秋月の「1000mA 可変定電流パワーLEDドライバーキット」にも使われています。このキット、我が家の洗面台の自動点灯LEDにも使っていますが、安定していて使いやすいです。ただし、マイコンから制御するためには多少の改造が必要です。CL6807はバラでも売ってますし、プリント基板を起こさなくてもSOT89-5用基板とSBD、シャント抵抗(0.1 - 1.0Ω)、4.7μFの積層セラミックコンデンサ、ユニバーサル基板があれば自作も可能です。なおメーカーの応用回路例には書いてないのですが、LEDへの出力の両端にパスコン(1μF)をつけると点灯が安定します。

なお基板の裏には放熱器を高品質グリースで貼り付けてありますが、これぞ焼け石に水。フルパワーにすると室温20度でも基板温度は50度を越えていきます。我ながら何をしたかったのかわからない基板です(笑)。

■ソフト■

AQ0802、IR Receiverなどのライブラリを使って、組み立てました。ループは1秒間に10回まわっていて、Lチカの基本周期となっています。リモコンの信号を受けると、「あと何回点滅させるか」という変数に値を代入します。その変数が偶数なら点灯、奇数なら消灯、という決まりにすることで、0.1秒ごとにペカペカ点滅します。これだと複数のLEDを逆相や追いかけるように点滅させるのがラクです。
// Bright board
// ver 0.0 ボードのテスト用。ボリューム輝度調整、温度による出力制限など
//
// ver 0.1 2016-01-08 IR Receiverを追加してリモコン通知機能として実装
//
#include "mbed.h"
#include "AQM0802.h"
#include "ReceiverIR.h"
// PWM Outputs
PwmOut white(dp18);
PwmOut warm(dp1);
PwmOut yobi(dp24);
PwmOut fan(dp2);
// LCD
I2C i2c(dp5, dp27);
AQM0802 lcd(i2c);
// IR Receiver
ReceiverIR irReceiver(dp4);
// Analog input
AnalogIn vol(dp9);
AnalogIn sensor(dp13);
//
// temperature calc
//
const float ReferenceVoltage = 3.3;
float readTmpSensor() {
return (sensor*ReferenceVoltage - 1.951) * -121.95121951219512 - 30.0;
}
//
// main
//
int main() {
uint8_t buf[32]; // string convesion buffer
uint8_t hex[20]; // hex convertion buffer
white.period_ms(1.0); // set all pwm freq. 1khz
warm.period_ms(1.0);
yobi.period_ms(1.0);
fan.period_ms(1.0);
white = 1.0; // turn off all pwm ports
warm = 1.0;
yobi = 1.0;
fan = 1.0;
RemoteIR::Format format; // received format identity
int bitcount; // number of bits
lcd.cls();
int countWhite = 0; // led blinking flag / counter
int countWarm = 0;
while(1) {
if (irReceiver.getState() == ReceiverIR::Received) { // check ir receiver
// got signal
bitcount = irReceiver.getData(&format, buf, sizeof(buf) * 8);
// convert to hex string
int len = bitcount > 8 ? 8 : bitcount;
int p = 0;
hex[0] = 0;
for (int i = 0; i < len; i++) {
char temp[4];
sprintf(temp, "%02x", buf[i]);
hex[p++] = temp[0];
hex[p++] = temp[1];
}
hex[p] = 0; // end of c string
hex[8] = 0; // 念のため
lcd.locate(0,1);
// turn on if defined signal
hex[8] = 0;
if (strcmp((char *)hex, "10eff807") == 0) {
countWarm = 8; // button 'A'
} else if (strcmp((char *)hex, "10ef7887") == 0) {
countWhite = 16; // button 'B'
} else if (strcmp((char *)hex, "10ef58a7") == 0) {
countWhite = 19; // button 'C'
countWarm = 20;
} else {
lcd.print((char *)hex);
}
}
//
// volume
//
float a = vol;
int i = a * 1000;
char buf[32];
// display volume value
// lcd.locate(0, 0);
// sprintf(buf, "vol%5d", i);
// lcd.print(buf);
//
// temperature sensor
//
float tmp = readTmpSensor();
i = tmp;
lcd.locate(0, 1);
sprintf(buf, "tmp%5d", i);
lcd.print(buf);
//
// fan's control : turn of if temperature over 30.0 degree
//
fan = (tmp >= 30.0) ? 1.0 : 0;
//
// if temperature is over 35.0, limit the output power
//
if (tmp >= 35.0) {
float hosei = (40.0 - tmp) / 5.0;
if (hosei > 1.0) hosei = 1.0;
if (hosei < 0) hosei = 0.0;
a = a * hosei;
}
// reverse pwm duty
a = 1.0 - a;
//
// check led
// if counter is even, turn on. and decrement the counter for next loop
if (countWhite > 0) {
white = (countWhite % 2) == 0 ? a : 1.0;
countWhite --;
}
if (countWarm > 0) {
warm = (countWarm % 2) == 0 ? a : 1.0;
countWarm --;
}
// loop period is 0.1 sec
wait_ms(100);
}
}

0 件のコメント:

コメントを投稿

注: コメントを投稿できるのは、このブログのメンバーだけです。