どうも、電子工作系YouTuberのなかしーです。
先日、Arduinoでテレビのリモコンを作る動画をYouTubeに公開しました。ブログを見て頂いている方にも参考になるような内容だと思ったので文章にしてみました!
ちなみにこの記事はGoogleなどで検索しても出てこないように設定しています。つまり、ブログやYouTubeを見て頂いている方限定です。
YouTubeチャンネルはこちら
いつもありがとうございます!
動画内ではタクトスイッチを押すとテレビの電源を付けたり、消したりできるような回路とプログラミングの作り方を紹介しています。
もちろん、プログラムを変更することでチャンネルやボリュームなどの割り当ても可能です。僕はテレビを見ないのであんまり嬉しさがありませんが・・・
それは置いておいて、テレビのリモコンの仕組みを理解するとラジコンカーのように遠隔操作が可能になります。
無線といえば電波を使う方法があります。例えば、WiFiやBluetoothなどですね。ただ、モジュールが高かったり、設定がめんどくさかったりするので用途にyもよりますが、あんまり使いたくないはずです。
しかし、テレビのリモコンは光を使った赤外線通信で必要なのは送信用の赤外線LEDと赤外線を受信するセンサーの2つだけ。価格も数百円と電波のモジュールに比べると安価です。
ただ、1つ欠点があるとすれば双方向の通信が不可ということです。リモコンから一方的に指示を送信するような構図で光が遮られない環境下であれば、間違いなく赤外線通信を選んだ方が良いでしょう。
赤外線通信の送信回路
赤外線通信には赤外線LEDを任意の周波数のパルスで駆動させる必要があります。LEDなので電流値に応じて光の強度が強くなります。
マイコンの出力はせいぜい20mAで、動画中で使った赤外線LEDは定格電流(IF)が100mAと5倍まで流せたのでトランジスタを使いました。
順方向電圧が1.35Vだったので抵抗値は計算上37Ω以上を使えばOKだったので、100Ωの抵抗を2つ並列に繋いで50Ωにしています。実は同じ抵抗を並列に繋げると半分になるので覚えておくと便利ですよ。
あとはスイッチ回路は10kΩでプルダウンして、スイッチを押すと+5VがArduinoに入力されるようにしています。
赤外線通信の送信プログラミング
赤外線には通信フォーマットがあります。いわゆる型みたいなものです。この型に合わせてデータを送信して、受信側が応答するみたいなイメージです。
こちらのフォーマットはNECフォーマットの図で日立、東芝、三洋などが対応しているそう。パナソニックやシャープは家電製品協会フォーマット。ソニーは独自のフォーマットを使用しています。
PSPのメモリースティックの時もそうでしたけど、ソニーさんは独自の規格がお好きなようで。
リーダーコードは赤外線通信の始まりで、その後に送られてくるカスタムコードとデータを受信側は受け取ります。受け取ったデータの宛先を確認して自分宛であれば相応しい処理を実行します。
カスタムコードが宛先に該当します。
赤外線センサーを使って僕の家にあるTOSHIBA製のREGZAのリモコンを調査したところカスタムコードが(0x40)で電源ボタンを押した時のデータが(0x12)となっていました。
カスタムコードとデータの送り方はこんな感じです。
今回のプログラムで難しかったのは、赤外線LEDを38kHzで点滅させつつ、1Tの待機時間を作るところ。
tone関数を使えば38kHzに対応できることに気づいてArudinoで作ってみたんですけど、tone関数とdelayを同時に使うとdelayの秒数が2倍で実行されていました。noTone関数を実行したあとのdelayは引数通りだったのでややこしかったです。
tone関数の中身を除けなかったのでオシロスコープを見ながら待機時間の調整を行いました。結構力技みたいな感じでした(笑)
それで作ったプログラムがこちらになります。
#define SW 2
#define IR_LED 5
#define frequency 38000
/*テスト用*/
#define LED 3
void LED_ON(void);
void LED_OFF(void);
void T_Wait(unsigned char wait_time);
void LED_Send_Reader(void);
void LED_Send_Data(unsigned char data);
void LED_Send_Stop(void);
void IR_Send(void);
/*グローバル変数*/
unsigned char Customcode = 0;
unsigned char Customcode_Checksum = 0;
unsigned char Data = 0;
unsigned char Data_Checksum = 0;
void setup() {
Customcode = 0x40;
Customcode_Checksum = 0xBF;
Data = 0x12;
Data_Checksum = 0xED;
pinMode(IR_LED, OUTPUT);
pinMode(SW, INPUT);
/*テスト用*/
pinMode(LED, OUTPUT);
}
void loop() {
if (digitalRead(SW) == 1) {
IR_Send();
while(digitalRead(SW) == 1);
}
}
void LED_ON(void) {
tone(IR_LED, frequency);
digitalWrite(LED, HIGH);
}
void LED_OFF(void) {
noTone(IR_LED);
digitalWrite(LED, LOW);
}
void T_Wait(unsigned char wait_time) {
while(wait_time != 0) {
delayMicroseconds(270); /*本来は562*/
wait_time--;
}
}
void LED_Send_Reader(void) {
LED_ON();
T_Wait(16);
LED_OFF();
T_Wait(16);
}
void LED_Send_Data(unsigned char data) {
int i = 0;
for(i = 0; i < 8; i++) {
LED_ON();
T_Wait(1);
LED_OFF();
if ((data & 0x01) == 0x01) {
T_Wait(6);
} else {
T_Wait(2);
}
data = data >> 1;
}
}
void LED_Send_Stop(void) {
LED_ON();
T_Wait(1);
LED_OFF();
}
void IR_Send(void) {
/*リーダーコード*/
LED_Send_Reader();
/*カスタムコード*/
LED_Send_Data(Customcode);
LED_Send_Data(Customcode_Checksum);
/*データ*/
LED_Send_Data(Data);
LED_Send_Data(Data_Checksum);
/*ストップビット*/
LED_Send_Stop();
}
プログラムのポイントはデータをLSBから送信するところです。関数LED_Send_Data()です。
LSBというのはビットの重みが一番軽いもの表で言うところのB0で、MSBがその反対で、B7になります。
赤外線通信もシリアル通信と同様1ビットずつしかデータを送信できません。
NECフォーマットではLSBから送信するようになっていたので、データの下位1ビットだけマスクしてデータが’0’なのか’1’なのか判定して、結果に応じて待機時間の処理を実行するようにしています。
その後、データをLSB側へ1ビットだけシフトするという処理を合計8回実行するようにしています。この動きが分かればソフトウェアUARTを作れるようになります。
カスタムコードとデータの調べ方
オシロスコープがあれば簡単に調べられるんですけど、赤外線センサーを使えばオシロスコープなしでも解析が可能です。その解析機を作った動画はこちらです。
動画で作ったプログラムはこちらです。
#include
LiquidCrystal lcd(3, 4, 5, 6, 7, 8);
#define Sensor 2
struct format {
unsigned int header_High;
unsigned int header_Low;
unsigned char custom_code;
unsigned char custom_code_checksum;
unsigned char data;
unsigned char data_checksum;
};
struct format receive_data;
void judge(unsigned char *data);
void setup() {
lcd.begin(16, 2);
pinMode(Sensor, INPUT);
}
void loop() {
/*ヘッダーの判定*/
receive_data.header_Low = pulseIn(Sensor, HIGH);
if ((receive_data.header_Low > 4053) && (receive_data.header_Low < 4954)) {
judge(&receive_data.custom_code);
judge(&receive_data.custom_code_checksum);
judge(&receive_data.data);
judge(&receive_data.data_checksum);
if((receive_data.custom_code + receive_data.custom_code_checksum) != 0xFF) {
//エラー
} else {
if((receive_data.data + receive_data.data_checksum) != 0xFF) {
//エラー
}
}
lcd.clear();
lcd.setCursor(0,0);
lcd.print(receive_data.data);
} else {
//エラー
}
}
void judge(unsigned char *data) {
int i = 0;
unsigned bit_data = 0;
*data = 0;
for (i = 0; i < 8; i++) {
if(pulseIn(Sensor, HIGH) > 619) {
bit_data = 1;
} else {
bit_data = 0;
}
*data |= bit_data << i;
}
}
ちなみに、僕は電子工作にオシロスコープは必須だと考えています。理由はとして専用モジュールが増えてマイコンにICを繋げるだけで済むような感じになっています。データのやり取りはシリアル通信を行っているため、オシロスコープを使わないと送受信の状態を確認できないからです。
オシロスコープなしで不具合を発見することは到底困難でしょう。ぶっちゃけ高いですけど、オシロスコープなしで電子工作をやるなんて考えられません。僕は引っ越しの時にオシロスコープをメルカリで売却したんですけど、YouTubeを始めるにあたって再度購入しています。つまり、2台目の購入です(笑)
オシロスコープの選び方についてはこちらの記事にまとめてあります。
>>オシロスコープのおすすめを紹介【比較するポイントは3つだけ】
参考:PICでもテレビのリモコンを作ってみた
一度Arduinoでテレビのリモコンを作ろうとしたんですが、勘違いしてArduinoでは性能的に無理だと思っていました。そこでPICを使ってテレビのリモコンを作ってみました。
Arduinoは標準ライブラリが充実しているから動かすためのプログラミングは超絶簡単ですけど、詳細な仕様が決まっている今回のような赤外線通信の場合はPICを使った方が簡単でしたし、色んなことが使えます。
Arduinoはdelay関数を使っているので他の処理にガンガン影響が出ますが、PICならタイマ割り込みを使って待機時間を作りだせば良いので他の処理も同時進行可能です。
この動画を作ったきっかけはNHKの集金です。僕は一切テレビを見ておらず、テレビ線を繋いでいないのに受信できる環境があれば支払う必要性があるらしいです。しかも法律で定められているそうな。
このご時世にいかがなものかと・・・
Arduino関連のおすすめ記事
>>Arduinoをゼロから勉強する方法を紹介【参考書は不要】
>>【Arduino入門キット】電子工作の勉強におすすめ【こんなに安くていいの?】
>>Arduinoの勉強に役立つ本の選び方【現役エンジニアが解説】
当ブログで人気のArduino入門キット