前回の記事で使う赤外線の仕組みや回路を作るうえで使用するギミックについて紹介しました。
iotblog5296.hatenablog.com
今回は実際にリモコンを作成していきます。
使用する部品
使用した部品です。
各部品にリンクが貼ってあるのでクリックすると飛べます。
- ATmega328p(8MHz)
- タクトスイッチ
- ダイオード(逆流防止用)
- 抵抗(プルダウン抵抗用)
- 赤外線LED
- スライドスイッチ(電源のON/OFF用)
- XHコネクタ 2P(オス)
- XHコネクタ 2P(メス)
- DCDCコンバータ(秋月電子製)
- 電池ばね
- ソフト書換用コネクタ(メス)
- ソフト書換用コネクタ(オス)
- なべねじ M3×10(ホームセンターで購入)
基板作成
一度ユニバーサル基板に手配線で回路を作成して、初めはうまくいっていたのですが渡り線がちぎれて再度配線し直したりソフトを書き換えたりしていたらあまりにも酷使し過ぎたのか反抗期を迎えてボタンを押しても何も反応してくれなくなりました。
色々原因を調べていたのですが原因が全く分からず当方に暮れてしまい最終的にただのガラクタと化してしまいました。
配線の接触不良の可能性が高そうだったのでその要因を潰してやろうと今回は基板から作成していきたいと思います。
回路
実際の回路図です。

ATmega328pのピンの配置がわかりにくいですが、ネットに落ちている画像とピンの配置と見比べるとわかると思います。
J1の6ピンはRESET,MOSI,MISO,SCKなど、Arduinoからソフトを書き換えるときに接続しやすくするためにXHコネクタを使用します。
J3の3ピンがコネクタですが、今回使用するマイコンのmin電圧が2.9Vなのですが単四のeneloop(1.2V/個)を1-2本で動かそうとすると電圧が足りないため、秋月電子で販売しているDCDCコンバータで5Vに昇圧して使用します。
DCDCコンバータのシンボルとフットプリントは面倒だったのでコネクタで代用しています。
部品配置&パターン配線
回路が完成したら実際に基板に配置して部品同士をパターンで繋ぎます。

作成した基板データを中国の基板メーカーのJCLPCBに発注しました。
jlcpcb.com
基板が届いたので部品を取り付けました。


ソフト作成
全てのボタンの動作確認をしていないのでもしかしたらどこか動作しない箇所があるかもしれないです。その場合はコメント等頂けると幸いです。
#include <IRremote.h> // ライブラリのインクルード
IRsend irsend; // IR送信オブジェクトの生成
//keymatrix関係の変数
const int rowNum = 6;
const int colNum = 3;
//keymatrix関係の宣言
const int rowPin[rowNum]={5,6,7,8,9,10}; //6行
const int colPin[colNum]={0,1,2}; //3列
//変数
int i,j,x,a,b,result;
int switching=1; //切り替えスイッチ用変数
int delayt=300; //delay時間
//各リモコンの出力
//シーリングライト
//ON/OFF
uint16_t irDataA[85] = {2200,750, 5600,900, 1600,400, 1550,450, 550,450, 550,450, 600,400, 600,400, 600,450, 550,450, 1550,450, 550,450, 550,450, 600,400, 600,450, 550,450, 550,450, 600,450, 550,450, 1550,450, 550,450, 550,450, 550,450, 550,500, 550,450, 550,450, 550,450, 550,450, 550,500, 550,450, 550,450, 550,450, 550,500, 500,500, 550,450, 1550,450, 550,450, 1500,500, 1500,500, 500,500, 1500,450, 550,500, 500};
//明るく
uint16_t irDataB[85] = {2200,800, 5550,900, 1600,400, 1600,400, 600,400, 600,400, 600,450, 550,450, 600,400, 600,400, 1600,400, 600,400, 600,450, 550,450, 550,450, 600,400, 600,400, 600,450, 550,450, 550,450, 600,400, 600,400, 600,450, 550,450, 1550,450, 550,450, 550,450, 600,400, 600,450, 550,450, 550,450, 550,450, 600,400, 600,450, 550,450, 550,450, 600,400, 1600,400, 1550,450, 550,450, 600,400, 600,450, 500};
//暗く
uint16_t irDataC[85] = {2150,800, 5600,900, 1550,400, 1600,400, 600,400, 600,450, 600,400, 600,400, 600,400, 600,450, 1550,400, 600,450, 550,450, 550,450, 600,400, 600,400, 600,450, 550,450, 550,450, 600,400, 600,450, 550,450, 550,450, 550,450, 600,400, 1600,400, 600,400, 600,450, 550,450, 550,450, 600,400, 600,400, 600,450, 550,450, 550,450, 600,400, 600,450, 1550,400, 1600,400, 600,400, 1600,400, 1600,400, 550};
//切タイマー
uint16_t irDataD[85] = {2150,800, 5600,900, 1600,350, 1600,400, 600,400, 600,450, 600,400, 600,400, 600,400, 600,450, 1550,400, 600,450, 550,450, 550,450, 600,400, 600,400, 600,450, 550,450, 550,450, 600,400, 600,400, 1600,400, 600,450, 550,450, 550,450, 600,400, 600,400, 600,450, 550,450, 550,450, 600,400, 600,400, 600,450, 550,450, 550,450, 600,400, 600,450, 550,450, 1550,450, 550,450, 1550,450, 550,450, 550};
//扇風機
//電源
uint16_t irDataE[23] = {1350,400, 1300,400, 450,1250, 1300,400, 1300,400, 500,1200, 450,1250, 450,1250, 1300,400, 450,1250, 450,1250, 450};
//風量
uint16_t irDataF[23] = {1350,400, 1300,400, 450,1200, 1350,400, 1300,400, 450,1200, 500,1200, 500,1200, 500,1200, 500,1200, 500,1200, 1350};
//首振り
uint16_t irDataG[23] = {1350,350, 1350,400, 450,1200, 1350,400, 1300,400, 450,1250, 450,1200, 500,1200, 450,1250, 1300,400, 450,1250, 450};
//タイマー
uint16_t irDataH[23] = {1350,350, 1350,400, 450,1200, 1350,400, 1300,400, 450,1200, 500,1200, 500,1200, 500,1200, 500,1200, 1350,400, 450};
//モード
uint16_t irDataI[23] = {1350,400, 1300,400, 450,1200, 1350,400, 1300,400, 450,1200, 500,1200, 1300,450, 450,1200, 450,1250, 450,1250, 450};
void setup() {
for(i=0; i<rowNum; i++){ //出力ピンをアクティブ
pinMode(rowPin[i],OUTPUT);
}
for(j=0; j<colNum; j++){ //入力ピンをアクティブ
pinMode(colPin[j],INPUT);
}
pinMode(4,INPUT);
}
void loop() {
for(i=0; i<rowNum; i++){
digitalWrite(rowPin[i], HIGH);
if(digitalRead(0)==HIGH){
a=i+1; //行
b=1; //列
result=a*10+b;
}else if(digitalRead(1)==HIGH){
a=i+1; //行
b=2; //列
result=a*10+b;
}else if(digitalRead(2)==HIGH){
a=i+1; //行
b=3; //列
result=a*10+b;
}
if(result>10 && result<=13){ //切り替えスイッチ用
if(result==11){
switching=1;
}else if(result==12){
switching=2;
}else if(result==13){
switching=3;
}
}else if(result>20 && result<=63){ //各スイッチ用
if(result==21){
button21();
delay(delayt);
}else if(result==22){
button22();
delay(delayt);
}else if(result==23){
button23();
delay(delayt);
}else if(result==31){
button31();
delay(delayt);
}else if(result==32){
button32();
delay(delayt);
}else if(result==33){
button33();
delay(delayt);
}else if(result==41){
button41();
delay(delayt);
}else if(result==42){
button42();
delay(delayt);
}else if(result==43){
button43();
delay(delayt);
}else if(result==51){
button51();
delay(delayt);
}else if(result==52){
button52();
delay(delayt);
}else if(result==53){
button53();
delay(delayt);
}else if(result==61){
button61();
delay(delayt);
}else if(result==62){
button62();
delay(delayt);
}else if(result==63){
button63();
delay(delayt);
}
}
digitalWrite(rowPin[i], LOW);
a=b=result=0;
//71キーの入力ピンのif文
if(digitalRead(4)==HIGH){
button71();
delay(delayt);
}
}
}
void button21(){
if(switching==1){
//switch1の21
}else if(switching==2){
//switch2の21
}else if(switching==3){
//switch3の21
}
delay(delayt);
}
void button22(){
if(switching==1){
for(x=0; x<2; x++){
irsend.sendRaw(irDataE, 23, 38); //扇風機電源
delay(40);
}
}else if(switching==2){
//switch2の22
}else if(switching==3){
//switch3の22
}
delay(delayt);
}
void button23(){
if(switching==1){
irsend.sendRaw(irDataA, 85, 38); //ライト電源
}else if(switching==2){
result=200+result;
}else if(switching==3){
result=300+result;
}
delay(delayt);
}
void button31(){
if(switching==1){
irsend.sendRaw(irDataB, 85, 38); //ライト明るく
}else if(switching==2){
result=200+result;
}else if(switching==3){
result=300+result;
}
delay(delayt);
}
void button32(){
if(switching==1){
irsend.sendRaw(irDataC, 85, 38); //ライト暗く
}else if(switching==2){
result=200+result;
}else if(switching==3){
result=300+result;
}
delay(delayt);
}
void button33(){
if(switching==1){
irsend.sendRaw(irDataD, 85, 38); //ライト暗く
}else if(switching==2){
result=200+result;
}else if(switching==3){
result=300+result;
}
delay(delayt);
}
void button41(){
if(switching==1){
for(x=0; x<2; x++){
irsend.sendRaw(irDataF, 23, 38); //扇風機風量
delay(40);
}
}else if(switching==2){
result=200+result;
}else if(switching==3){
result=300+result;
}
delay(delayt);
}
void button42(){
if(switching==1){
for(x=0; x<2; x++){
irsend.sendRaw(irDataG, 23, 38); //首振り
delay(40);
}
}else if(switching==2){
result=200+result;
}else if(switching==3){
result=300+result;
}
delay(delayt);
}
void button43(){
if(switching==1){
for(x=0; x<2; x++){
irsend.sendRaw(irDataH, 23, 38); //扇風機タイマー
delay(40);
}
}else if(switching==2){
result=200+result;
}else if(switching==3){
result=300+result;
}
delay(delayt);
}
void button51(){
if(switching==1){
for(x=0; x<2; x++){
irsend.sendRaw(irDataI, 23, 38); //扇風機モード
delay(40);
}
}else if(switching==2){
result=200+result;
}else if(switching==3){
result=300+result;
}
delay(delayt);
}
void button52(){
if(switching==1){
//switch1の52
}else if(switching==2){
result=200+result;
}else if(switching==3){
result=300+result;
}
delay(delayt);
}
void button53(){
if(switching==1){
//switch1 53
}else if(switching==2){
result=200+result;
}else if(switching==3){
result=300+result;
}
delay(delayt);
}
void button61(){
if(switching==1){
//switch1 61
}else if(switching==2){
result=200+result;
}else if(switching==3){
result=300+result;
}
delay(delayt);
}
void button62(){
if(switching==1){
//switch1 62
}else if(switching==2){
result=200+result;
}else if(switching==3){
result=300+result;
}
delay(delayt);
}
void button63(){
if(switching==1){
//switch1 63
irsend.sendRaw(irDataA, 23, 38); //ライト電源
}else if(switching==2){
result=200+result;
}else if(switching==3){
result=300+result;
}
delay(delayt);
}
void button71(){
if(switching==1){
irsend.sendRaw(irDataA, 85, 38); //ライト電源
}else if(switching==2){
result=200+result;
}else if(switching==3){
result=300+result;
}
delay(delayt);
}
カバー作成
基板むき出しでも使ううえでは問題ないと思って裸で使っていたのですがどこかでひっかけたのか使い方が荒かったのか気が付いたら基板のレジストがはがれてパターンが剥き出しになっていました。
ということでFuision360でいい感じに作りました。


3Dプリンタに出力して基板を装着すると見た目もよくなりました。

まとめ
手配線と比べると圧倒的にきれいなのと何より配線不良による動作不良がなく、一度作っているということもあり完成するまでにあまり時間はかかりませんでした。
どちらかというと3DCAD(Fuision360)をあまり触ったことがなかったのでリモコンのカバーを作る方に圧倒的に時間がかかりました。基板設計時のデータをそのままFuision360に移植したのですが穴の位置がおもいっきりずれて部品と干渉してしまったりと試行錯誤していました。結果的にソフトの使い方の理解が深まったので良かったです。
モチベーションが低空飛行していた影響で構想から完成まで2年近くかかりその月日の中で使用するリモコンがシーリングライトと扇風機のリモコンの2つに減ってしまい、ここまでボタンの多いリモコンを作る必要がなくなってしまいました…。
とはいえリモコンが一つだけでよくなるので探す手間が省けるようになったことは非常に大きいですし今後生活環境が変わって家電製品が増えてもリモコン一つで対応することができるようになったのは喜ばしいです。
参考記事