PICの工作(4)


PICを使った電灯用リモコン送受信機の製作

PICを使った電灯用リモコン送受信機を製作しました。



 ぐうたらな発想から、寝室にある4個の40w白熱電球が同時に点く室内電灯を少し改造して、 4個の電球を60w、40w、20wの白熱電球と2wの100VLEDに切り替えて、リモコンで 一つ一つ点灯できるようにしました。
 こうすれば、布団に入ったまま電灯を操作できるし、身体と電気の省エネにもなりますよね??
 なお、プログラムは、「PICによるホームコントロール工作入門」(中尾 司著)を参考にさせてもらい、 12chのリモコン用に作ったプリント基板をそのまま5ch用に使用しています。



  完成作品


 写真のようにリモコン送信機は、5個のプッシュボタンで左から60w、40w、20w、 2wの点灯用に、右上のボタンは全消灯用に使っています。
 電源は、2個の単4形電池を使用し、電源スイッチは付けていません。
 使用しない時は,TIMER1のオーバーフロー割込みを使ってSleep状態にしてあり、 プッシュボタンを押すことによりRB状態変化割込みで起動しています。それにより1年以上 電池を交換しなくても使えています。

 受信機は、写真のように電灯のスイッチの所に設置しています。このスイッチをONにすると 60Wの電灯が点灯し、OFFにすると電灯が切れるようにしてあります。
 お断りしておきますが、屋内配線は電気工事士の資格が必要ですので考慮してください。




  リモコン送信機の回路図


 下記にリモコン送信機の回路図を表示しておきます。




  リモコン送信機 回路図の概略


1.PIC16F648Aを次のように使用しています。

(1)キー・スイッチを使用した12ch用のリモコン送信機を5chに変更しただけです。

(2)プリント基板も12ch用に作成したプリント基板をそのまま使用しています。




  送信機のプログラムコード


 リモコン送信機のPICプログラムを掲載しておきます。

// remocon12ch //

#include <16F648A.h>
#fuses NOWDT,INTRC_IO,PUT,NOPROTECT,NOBROWNOUT,MCLR,NOLVP,NOCPD
#use delay(clock=4000000)

// レジスタ・アドレス
#byte PORTA	=0x05
#byte PORTB	=0x06
#byte INTCON =0x0B

struct TAG_PORT
{
  unsigned char B0:1;
  unsigned char B1:1;
  unsigned char B2:1;
  unsigned char B3:1;
  unsigned char B4:1;
  unsigned char B5:1;
  unsigned char B6:1;
  unsigned char B7:1;
};

struct TAG_PORT PA;
#byte PA=5

struct TAG_PORT PB;
#byte PB=6

#define BitTest(p,b) (p&(1<<b))

void SendData(int cmd);
boolean GoSleep=false;
void PulseOut(void);
char KeyMtxScan(void);
void KeyPress(void);
BYTE KeyCode[3][4] = {{0,1,2,3},{4,5,6,7},{8,9,10,11}};

#int_RB
RB_isr()
{
  INTCON &= 0xFB;
  disable_interrupts(INT_RB);
}

#int_TIMER1
TIMER1_isr()
{
  GoSleep=true;
}

BYTE BefKey=0;
BYTE KPValue;
BYTE KeyMatch=0;
boolean KeyDown=false;
boolean Repeating=false;
BYTE KeyInterval=0;
#define KEY_REPEAT_ENA true
#define KEY_REPEAT_DIS false

char KeyCheck(BYTE key, BYTE repeat_ena)
{
  if(BefKey==key)
  {
    KeyMatch++;
    if(repeat_ena)
    {
      if(KeyMatch>50)
      {
        KeyMatch=50;
        Repeating=true;
      }
      else
      {
        Repeating=false;
      }
    }
    else
    {
      Repeating=false;
    }
  }
  else
  {
    BefKey=key;
    KeyMatch=0;
    Repeating=false;
  }
  if(KeyMatch>=2)
  {
    if(key==0xFF)
    {
      KeyDown=false;
      Repeating=false;
    }
    else
    {
      if(!Repeating)
      {
        if(!KeyDown)
        {
          KeyDown=true;
          KPValue=key;
          return true;
        }
      }
      else
      {
        if(!KeyDown)
        {
          KeyInterval=(KeyInterval+1) % 10;
          if(KeyInterval==0)
          {
            KeyDown=true;
            KPValue=key;
            return true;
          }
        }
      }
    }
  }
  return false;
}

void main()
{
  port_b_pullups(TRUE);
  setup_timer_0(RTCC_INTERNAL|RTCC_DIV_64);
  setup_timer_1(T1_INTERNAL|T1_DIV_BY_8);
  setup_comparator(NC_NC_NC_NC);
  setup_vref(FALSE);
  setup_oscillator(OSC_4MHZ);

  set_tris_a(0);
  et_tris_b(0xF0);
  PORTA=0xFF;
  set_timer1(0);

  enable_interrupts(INT_TIMER1);
  enable_interrupts(GLOBAL);

  while(1)
  {
    if(GoSleep)
    {
      setup_timer_1(T1_DISABLED);
      set_timer0(0);
      PORTB &=0xF1;
      enable_interrupts(INT_RB);
#asm
  SLEEP
  NOP
#endasm
      GoSleep=false;
    }
    if((INTCON & 0x04) !=0 )
    {
      INTCON &= 0xFB;
      if(KeyMtxScan())
      {
        KeyPress();
      }
    }
  }
}

void KeyPress(void)
{
  set_timer1(0);
  SendData(KPValue);
}

BYTE lc;
void SendData(int cmd)
{
  signed char i;
  BYTE data;
  cmd &= 0x0F;
  data =~cmd <<4;
  data |=cmd;
  disable_interrupts(GLOBAL);
  lc=56;
  PulseOut();
  delay_us(480);

  for(i=7;i>=0;i--)
  {
    if(BitTest(data,i))
    {
      lc=37;
      PulseOut();
      delay_us(480);
    }
    else
    {
      lc=19;
      PulseOut();
      delay_us(480);
    }
  }
  enable_interrupts(GLOBAL);
#asm
  NOP
#endasm
}

void PulseOut(void)
{
#asm
LOOP:
  MOVLW 0
  MOVWF PORTA
  NOP
  NOP
  NOP
  NOP
  NOP
  NOP
  NOP
  NOP
  NOP
  NOP
  NOP
  MOVLW 0xFF
  MOVWF PORTA
  NOP
  NOP
  NOP
  NOP
  NOP
  NOP
  NOP
  NOP
  DECFSZ lc
  GOTO LOOP
#endasm
}

char KeyMtxScan(void)
{
  BYTE col,row,coldat,key=0xFF;
  for(row=0;row<3;row++)
  {
    PORTB|=0b1110;
    switch(row)
    {
      case 0:
        PB.B1=0;
        break;
      case 1:
        PB.B2=0;
        break;
      default:
        PB.B3=0;
        break;
    }
    delay_us(5);
    coldat=PORTB>>4;
    for(col=0;col<4;col++)
    {
      if(!(coldat & 1))
      {
        key=KeyCode[row][col];
        goto next;
      }
      coldat>>=1;
    }
  }
next:
  return KeyCheck(key,KEY_REPEAT_ENA);
}
						



  送信機の参考写真


 参考として送信機ケース内の写真を掲載しておきます。


 実にシンプルですね!!




  受信機の回路図


 下記にリモコン受信機の回路図を表示しておきます。




  受信機のプログラムコード


 リモコン受診機のPICプログラムを掲載しておきます。(12ch用の受信機のプログラムです。)

#include <16F648A.h>

#fuses NOWDT,INTRC_IO,PUT,NOPROTECT,BROWNOUT,NOMCLR,NOLVP,NOCPD

#use delay(clock=4000000)

#byte PORTA =0x05
#byte PORTB =0x06

#define TST_IrIN   (!PB.B3)	
#define P0_ON	(PA.B0=1)
#define P0_OFF	(PA.B0=0)
#define P1_ON	(PA.B1=1)
#define P1_OFF	(PA.B1=0)
#define P2_ON	(PA.B2=1)
#define P2_OFF	(PA.B2=0)
#define P3_ON	(PA.B3=1)
#define P3_OFF	(PA.B3=0)
#define P4_ON	(PA.B4=1)
#define P4_OFF	(PA.B4=0)
#define P5_ON	(PB.B0=1)
#define P5_OFF	(PB.B0=0)
#define P6_ON	(PB.B1=1)
#define P6_OFF	(PB.B1=0)
#define P7_ON	(PB.B2=1)
#define P7_OFF	(PB.B2=0)
#define P8_ON	(PB.B4=1)
#define P8_OFF	(PB.B4=0)
#define P9_ON	(PB.B5=1)
#define P9_OFF	(PB.B5=0)
#define P10_ON	(PB.B6=1)
#define P10_OFF	(PB.B6=0)
#define P11_ON	(PB.B7=1)
#define P11_OFF	(PB.B7=0)

struct sPort {
  unsigned char B0:1;
  unsigned char B1:1;
  unsigned char B2:1;
  unsigned char B3:1;
  unsigned char B4:1;
  unsigned char B5:1;
  unsigned char B6:1;
  unsigned char B7:1;
};

struct sPort PA;
#byte PA=5

struct sPort PB;
#byte PB=6

BYTE IrRcvData2(void);

boolean OnSts0 = false;
boolean OnSts1 = false;
boolean OnSts2 = false;
boolean OnSts3 = false;
boolean OnSts4 = false;
boolean OnSts5 = false;
boolean OnSts6 = false;
boolean OnSts7 = false;
boolean OnSts8 = false;
boolean OnSts9 = false;
boolean OnSts10 = false;
boolean OnSts11 = false;

void main() {
  BYTE cmd;

  setup_comparator(NC_NC_NC_NC);
  setup_vref(FALSE);
  setup_oscillator(OSC_4MHZ);

  PA=0;
  PB=0;
  set_tris_a(0);
  set_tris_b(0x08);

  while(1) {        // リモコン受信処理
    cmd = IrRcvData2();
    switch(cmd) {
      case 0:
        if(!OnSts0) {
          P0_ON;
        } else {
          P0_OFF;
        }
        OnSts0 = !OnSts0;
        break;
      case 1:
        if(!OnSts1) {
          P1_ON;
        } else {
          P1_OFF;
        }
        OnSts1 = !OnSts1;
        break;
      case 2:
        if(!OnSts2) {
          P2_ON;
        } else {
          P2_OFF;
        }
        OnSts2 = !OnSts2;
        break;
      case 3:
        if(!OnSts3) {
          P3_ON;
        } else {
          P3_OFF;
        }
        OnSts3 = !OnSts3;
        break;
      case 4:
        if(!OnSts4) {
          P4_ON;
        } else {
          P4_OFF;
        }
        OnSts4 = !OnSts4;
        break;
      case 5:
        if(!OnSts5) {
          P5_ON;
        } else {
          P5_OFF;
        }
        OnSts5 = !OnSts5;
        break;
      case 6:
        if(!OnSts6) {
          P6_ON;
        } else {
          P6_OFF;
        }
        OnSts6 = !OnSts6;
        break;
      case 7:
        if(!OnSts7) {
          P7_ON;
        } else {
          P7_OFF;
        }
        OnSts7 = !OnSts7;
        break;
      case 8:
        if(!OnSts8) {
          P8_ON;
        } else {
          P8_OFF;
        }
        OnSts8 = !OnSts8;
        break;
      case 9:
        if(!OnSts9) {
          P9_ON;
        } else {
          P9_OFF;
        }
        OnSts9 = !OnSts9;
        break;
      case 10:
        if(!OnSts10) {
          P10_ON;
        } else {
          P10_OFF;
        }
        OnSts10 = !OnSts10;
        break;
      case 11:
        if(!OnSts11) {
          P11_ON;
        } else {
          P11_OFF;
        }
        OnSts11 = !OnSts11;
        break;
    }
  }

}

BYTE IrRcvData2(void) {
  BYTE data, data2;
  BYTE i, j;

  for(i = 0; i < 12; i++) {
    if(TST_IrIN) {			
      delay_us(100);
    } else {
      return 0xFF;
    }
  }
  for(i = 0; i < 30; i++) {
    if(!TST_IrIN) {
      goto next0;
    }
    delay_cycles(20);
  }
  return 0xFF;

next0:
  data = 0;
  for(j = 0; j < 8; j++) {
    data <<= 1;
    for(i = 0; i < 60; i++) {
      if(TST_IrIN) {
        goto next;
      }
      delay_cycles(10);
    }
    return 0xFF;

next:
    delay_us(700);
    if(TST_IrIN) {
      data |= 1;
      for(i = 0; i < 30; i++) {
        if(!TST_IrIN) {
          goto next2;
        }
        delay_cycles(20);
      }
      return 0xFF;
    }

next2:
#asm
  NOP
#endasm
  }
  data2 = ~data >> 4;
  data &= 0x0F;
  if(data == data2) {
    return data;
  }
  return 0xFF;
}