文書の過去の版を表示しています。
1キーリモコン
概要
実家の古い台所についていた天吊り照明が古くなったので、余っていた新品の照明器具に交換することになりました。
ただし台所と廊下に段差があるうえ、昔ながらの引っ張り式の照明で、部屋の入口にスイッチのようなものはありません。
今後のことを考えると、不便で危ないと思っています。
なので、新しいものは町の電器屋で購入した下記の装置を間に挟んでリモコン式にしました。
リモコンスイッチ 天井照明器具専用 [品番]04-9447|株式会社オーム電機
リモコンは小さいカードサイズなのですが、わざわざホルダーからリモコンを取り出してON/OFFするのは、普段使いとしては大変です。
なので、部屋の入り口に専用のリモコンを作成することにしました。
設計仕様
小さなスイッチを高齢者が暗くなったら見分けられないので、ユーザビリティを考慮して大きめのボタン1つで操作するようにして、
ONの信号とOFFの信号を押下するたびに切り替えて送信するようにします。
また、どこに取り付けてもよいように、リモコンのLEDは最大3つを別角度て取り付けます。
木製の柱に付けるので、サイズとしては同様にカードリモコンサイズ、マイコン含めてコイン電池の3Vで動かします。
小さくする必要があるので、目標として秋月電子のFRISK基板を参考に、FRISKの容器にはいるようにします。
回路図

赤外線リモコンなので、いかにLEDの出力を上げられるかが重要です。
というのも、コイン電池3Vで動作させているので、出力が大きいとLED点灯時に電圧が落ちてマイコンの動作電圧を下回ってBORになってしまいます。
とりあえず3216サイズ(海外だと1206サイズ)の100uFのチップコンデンサをLED毎につけられるようにして電圧降下を防ぎ、制限抵抗R5,R6,R7はパルスなので、1608サイズや最悪無しでも動作するとは思いますが、マイコン暴走で点灯しっぱなしになってもいいように、1/4W定格をつけられるように3216サイズ(海外だと1206サイズ)を実装できるようにしてあります。
リモコンスイッチは、秋月で購入できるうちから、いくつか選べるようにしました。
自己照光スイッチが一番シンプルですが、DIPの12mm幅のスイッチなら凡そどのメーカーのでも使えます。LEDを別途点灯させる場合は、D1に5mmのLEDを実装してください。自己照光スイッチ、もしくはLED点灯不要の場合は未実装です。
部品表
上記リストにない部品は以下の通りです。
- 1608サイズ(海外0603サイズ)の0.1uFコンデンサ C1 1個
- 1608サイズ(海外0603サイズ)の10k抵抗 R1,R3,R4 3個 ※AVRマイコンを使う場合はR1未実装
- 1608サイズ(海外0603サイズ)の4.7k抵抗 R2 1個 ※AVRマイコンを使う場合のみ
毎度のことながら、秋月ではチップ抵抗の入手が壊滅的なので、別途手配が必要です。せんごく電商の3216サイズを載せていますが5%品なので、リモコンはともかく、常備するようなものではありません。常備するものは、やはりAliExpressで買ってくるのが安いです。チップ抵抗はいつもこの店で買っています。ご参考まで。
CHANZON Official Store - Amazing prodcuts with exclusive discounts on AliExpress
ソースコード
スイッチは1つなので、初期値はライトONの信号を出力、もう1度押したときはライトOFFの信号を出力しています。
またコイン電池でずっと動かすの為、待機状態の消費電流をいかに小さくするかが重要になります。
昔の参考書だと、OSCCON(マイコンのクロックスピード)を未使用時にはLC(32.768kHz)にして、使用する時にHS(4~16MHz)に一時的に変更して処理するという方法です。
ただネットで探していると、アセンブラのsleepとnopを使って、OSCCONはそのままで、アセンブラのsleepとnopを入れて省電力化されている方法をとっておられたので、こちらを参考にさせていただきました。
PICを使った小型赤外線学習リモコン - Qiita
開発環境
MPLAB X v5.50
XC8 V2.31
MPLAB Code Configurator 4
- device_config.c
// CONFIG1 #pragma config FOSC = INTOSC // Oscillator Selection->INTOSC oscillator: I/O function on CLKIN pin #pragma config WDTE = OFF // Watchdog Timer Enable->WDT disabled #pragma config PWRTE = ON // Power-up Timer Enable->PWRT enabled #pragma config MCLRE = OFF // MCLR Pin Function Select->MCLR/VPP pin function is digital input #pragma config CP = OFF // Flash Program Memory Code Protection->Program memory code protection is disabled #pragma config CPD = OFF // Data Memory Code Protection->Data memory code protection is disabled #pragma config BOREN = ON // Brown-out Reset Enable->Brown-out Reset enabled #pragma config CLKOUTEN = OFF // Clock Out Enable->CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin #pragma config IESO = OFF // Internal/External Switchover->Internal/External Switchover mode is disabled #pragma config FCMEN = ON // Fail-Safe Clock Monitor Enable->Fail-Safe Clock Monitor is enabled // CONFIG2 #pragma config WRT = OFF // Flash Memory Self-Write Protection->Write protection off #pragma config PLLEN = OFF // PLL Enable->4x PLL disabled #pragma config STVREN = ON // Stack Overflow/Underflow Reset Enable->Stack Overflow or Underflow will cause a Reset #pragma config BORV = LO // Brown-out Reset Voltage Selection->Brown-out Reset Voltage (Vbor), low trip point selected. #pragma config LVP = OFF
- pin_manager.c
LATA = 0x00; TRISA = 0x3F; ANSELA = 0x17; WPUA = 0x00; OPTION_REGbits.nWPUEN = 1; APFCON = 0x01;
- mcc.c
WDTCON = 0x16;
- main.c
#include "mcc_generated_files/mcc.h" char IR_ON[1] = {0x87}; char IR_OFF[1] = {0x4B}; unsigned int arnum; //IR信号送信処理 void SendIR (char *s, int snum) { //一時処理のデータ箱 int i,j; char w; //動作確認用LED RA2 = 1; TMR2 = 0; //リーダーコードを送信する TMR2ON = 1; __delay_us(2560); TMR2ON = 0; __delay_us(2640); //カスタマーコードとデータ送信 for (i=0;i<1;i++) { w = s[i]; //1バイトずつ取り出す //取り出したデータを1ビットずつ処理する for (j=0;j<8;j++) { TMR2ON = 1; __delay_us(840); TMR2ON = 0; //データ0と1とはOFF時間の長さが異なるので分ける if (w & (0b00000001 << j)) { __delay_us(840); //ビット1のとき } else { __delay_us(1840); //ビット0のとき } } } //ストップビットの送信 TMR2ON = 1; __delay_us(840); TMR2ON = 0; __delay_ms(36); //タイムアウト //動作確認用LED RA2 = 0; } void main(void) { unsigned short mode = 1; //スイッチが押されたら送信するコードを選択 // initialize the device SYSTEM_Initialize(); OSCCON = 0b01101010; //内部オシレーター 4MHz APFCON = 0b00000001; //CCP1=RA5 TRISA = 0b00001000; //RA3のみ入力 ANSELA = 0; //アナログを使用しない WPUA = 0b00001000; //RA3のみプルアップ //割り込み設定 INTCON = 0; //割り込み無効 IOCAN = 0b00001000; //RA3の立下り検出 //PWMキャリアの設定 PR2 = 0b00011001; //38khz T2CON = 0b00001000; //ポストスケーラー1:2 Timer2 = OFF プリスケーラー1 CCP1CON = 0b00111100; //デューティサイクル0b11、PWM CCPR1L = 0x08; //デューティーサイクル35% while (1) { //ボタンが押下されたら実行 if (RA3 == 0) { //配列をポインタに置き換えると、正しい要素数が計算できなくなる。 //https://www.sejuku.net/blog/24793 //「関数に配列を渡すときの注意点」を参照。 //対策として、arnumで計算した値を一緒に渡す。 if (mode == 0) { arnum = sizeof(IR_OFF); SendIR(&IR_OFF,arnum); __delay_ms(60); SendIR(&IR_OFF,arnum); mode = 1; } else { arnum = sizeof(IR_ON); SendIR(&IR_ON,arnum); __delay_ms(60); SendIR(&IR_ON,arnum); mode = 0; } //チャタリング対策 __delay_ms(100); //ちょっと待つ while (RA3 == 0) { __delay_ms(100); //押下されなくなるまで待つ } } //ボタン押下されるまで停止 IOCAF = 0; //各ピンの状態変化割り込みクリア IOCIE = 1; //状態変化割り込みを有効 SLEEP(); NOP(); IOCIE = 0; IOCAF = 0; } }
信号解析とデバックについて
赤外線リモコンといえば、NEC方式とか家電協方式とかあるのですが、最近の家電はそんな常識にとらわれない信号を出力するものがあると聞きます。
知識では知っていたものの、まさかこのリモコンもそれに該当するものとはおもってもみませんでした。
昔から愛用しているこの解析装置の値で設計すると、まったく動作しません。
PICマルチメーカー対応赤外線リモコンコード解析器 PIC16F648A版
なので最近はONとOFF時間をusで計測して、そのまま信号を送ったりするのがトレンドのようです。
数ある方法のうち、M5Atomと赤外線ユニットを使った方法で解析とデバックを行いました。
M5StickC(ESP32)で赤外線リモコンを作ろう
(作成中)
