;　　　　　　プログラム名　　　Rec_v2   (mother  reciev_key)
;
;論理信号を使用した鍵システムの錠側のプログラムである
;キー側のプログラムと一対で役割を果たせる。
;
;ＰＩＣ１６Ｆ８４を使用し、
;　（１）暗号コードをキー側から入力し、記憶させておく。
;　（２）キーから送られてくる論理パルス列と暗号コードを比較し、
;　　　　合致していれば、開錠し、モニター黄緑ＬＥＤを点灯させる。
;　　　　不一致ならば、モニター赤ＬＥＤを点灯させる
;
;改訂開始　２００１年１２月２５日　　　　　　　　　　金野
;　　　　　２００２年　１月１０日一応改訂完了
;仕様
;１．６桁の暗号番号を登録することができる。（不揮発データ）
;２．鍵から送信される光パルスを受信し、登録番号と比較する。
;　　一致していれば開錠。
;
;動作の概要
;１．暗号コードの登録方法
;（１）選択スイッチを暗号登録側とし、電池をセットする。
;（２）鍵側から、この錠の暗号番号として登録したい暗号番号を送信する。
;　　　数秒～数十秒で登録が完了する。時間は暗証番号の数値の大小に依存する。
;　　　登録完了は鍵のＬＥＤの点滅が終了した時点で認識できる。
;２．開錠（暗号番号の比較）
;（１）選択スイッチを待機側とし、電池をセットする。
;（２）鍵側から暗号番号を送信する。
;（３）登録されている番号と　一致すれば、緑ＬＥＤを数秒間点灯し、リレーを駆動
;　　　　　　　　　　　　　不一致ならば、赤ＬＥＤを数秒間点灯する。
;（４）その後待機モードに入り、冬眠する。
;（５）繰り返したければ、（１）からやり直す。
;
;
;************************************************************************************
;
     LIST P=PIC16F84A           ;使用するプロセッサの種類を指定する
     #INCLUDE "P16F84A.INC"     ;上記のプロセッサ用インクルードファイルを呼び出し、結合する

;PIC本体の初期設定
     __CONFIG  _WDT_OFF & _XT_OSC
                               ;ウオッチドックタイマーはオフ
                               ;発信はクリスタル方式
;*********************************
;使用する変数の定義
   CBLOCK h'000C'
      i           ;任意使用のカウンタ変数
      count       ;任意使用のカウンタ変数
      temp0       ;カウンター用変数
      temp1       ;カウンター用変数
      temp2       ;カウンター用変数
      halftime    ;時間幅設定用変数

      memcode6    ;ＥＥＰＲＯＭに記憶させている暗号コードの入る６バイト（６桁整数値）変数
      memcode5
      memcode4
      memcode3
      memcode2
      memcode1

      keycode6    ;受信した暗号コードの入る６バイト（６桁整数値）変数
      keycode5
      keycode4
      keycode3
      keycode2
      keycode1

      e_adrs      ;ＥＥＰＲＯＭアドレス設定用変数
      
   ENDC

;*********************************
;使用端子に名称を定義する
;  #define   RSmonitor  PORTA   ;ＲＡ端子に名称を与える

;*********************************
;使用する定数の定義
codefig     equ     6          ;暗号コードの桁数

timebase0   equ     5    ;3    ;時間幅設定用定数その０　

timebase1   equ    64    ;255  ;時間幅設定用定数その１　
timebase2   equ   128    ;128  ;時間幅設定用定数その２　

;***********************************************************************************
;
        org      0               ;
start
    ;ポートの初期設定
    ;　ポートＡ　ＲＡ０～ＲＡ３　入力端子。
    ;　　　　　　光パルス列の受信端子。
    ;　ポートＢ　ＲＢ７　出力端子。緑ＬＥＤの駆動。　
    ;           ＲＢ６　出力端子。リレーの駆動。
    ;　　　　　　ＲＢ５　出力端子。赤ＬＥＤの駆動。
    ;　　　　　　ＲＢ３　入力端子。選択スイッチに接続。　 

        bcf     STATUS,RP1   ;バンク１に移る
        bsf     STATUS,RP0   ;
        movlw   b'11111111'  ;ＲＡ３，２，１，０を入力端子に、
        movwf   TRISA        ;残り（未使用）も入力端子に指定しておく。
        movlw   b'00011111'  ;ＲＢ７、６，５を出力端子、ＲＢ３を入力端子に、
        movwf   TRISB        ;残りは入力端子に指定。
        bcf     STATUS,RP0   ;バンク０に戻る。

        bcf     PORTB,7      ;緑ＬＥＤを消灯。
        bcf     PORTB,5      ;赤ＬＥＤを消灯。
        bsf     PORTB,7      ;
        call    timewidlong  ;ウオーミングアップ時間。緑ＬＥＤを点灯し、安定状態に入ったかを視認させる。
        bcf     PORTB,7      ;

    ;入力した光パルス列から数値を読み出す。
        call    lightread    ;光信号列を読む。

    ;処理の分岐　ＲＢ３の論理レベルで決定　分岐の種類　「暗証番号登録」、「暗証番号比較」
        btfsc   PORTB,3      ; 
        goto    coderecord   ;
        goto    codecheck    ;
coderecord
        call    datawrite    ;ＥＥＰＲＯＭに書き込む。
        goto    jobend       ;
codecheck
        call    memoryout    ;ＥＥＰＲＯＭに記憶させている暗号コードを読み出す。
    ;入力した暗証番号数値は　　　keycode6,keycode5,keycode4,keycode3,keycode2,keycode1 に入っている
    ;登録している暗証番号数値は　memcode6,memcode5,memcode4,memcode3,memcode2,memcode1 に入っている
    ;これらの２つを比較する。

       movf     memcode6,0   ;
       subwf    keycode6,0   ;keycode6-memcode6 の計算
       btfss    STATUS,Z     ;結果が０ならば、Ｚ＝１　
       goto     disagree     ;
       movf     memcode5,0   ;
       subwf    keycode5,0   ;keycode5-memcode5 の計算
       btfss    STATUS,Z     ;結果が０ならば、Ｚ＝１　
       goto     disagree
       movf     memcode4,0   ;
       subwf    keycode4,0   ;keycode4-memcode4 の計算
       btfss    STATUS,Z     ;結果が０ならば、Ｚ＝１　
       goto     disagree     ;
       movf     memcode3,0   ;
       subwf    keycode3,0   ;keycode3-memcode3 の計算
       btfss    STATUS,Z     ;結果が０ならば、Ｚ＝１　
       goto     disagree
       movf     memcode2,0   ;
       subwf    keycode2,0   ;keycode2-memcode2 の計算
       btfss    STATUS,Z     ;結果が０ならば、Ｚ＝１　
       goto     disagree     ;
       movf     memcode1,0   ;
       subwf    keycode1,0   ;keycode1-memcode1 の計算
       btfss    STATUS,Z     ;結果が０ならば、Ｚ＝１　
       goto     disagree

     ;６桁全てが一致した
agree
       bsf     PORTB,6      ;リレーを駆動。
       bsf     PORTB,7      ;
       call    timewidlong  ;緑ＬＥＤを数秒間点灯し、
       call    timewidlong
       call    timewidlong
       call    timewidlong
       bcf     PORTB,6      ;リレーを停止。
       bcf     PORTB,7      ;冬眠に入る

       sleep

     ;登録番号と入力暗号番号が一致しなかった　
disagree
       bsf     PORTB,5      ;
       call    timewidlong  ;赤ＬＥＤを数秒間点灯し、
       call    timewidlong
       call    timewidlong
       call    timewidlong
       bcf     PORTB,5     
 
       sleep                ;冬眠に入る。


;***********************************************************************************
;フォトトランジスタからパルス光信号を読み込み、６桁の数値を組み上げる。
;キー（送信部）からはスタート信号として眺めの光パルスが最初に送られてくる。
;　　その後、６つに分割され、暗号コードの数値が光りパルス数として、６桁分順々に
;　　送られてくる。　
;　　これらのタイミング、パルス長についてはキー側のプログラムを参照すること。
lightread
     ;ＲＡ０＝Ｈから、ＲＡ０＝Ｌになった時点で、光パルス列のカウントを行う。
loop10 
        btfss   PORTA,0      ;ＰＴに光が入射する（ＲＡ０＝Ｈ）まで待機する。
        goto    loop10       ;
        call    timewidshort ;
loop11 
        btfss   PORTA,0      ;チャッタリング防止のため、時間を開けて繰り返す
        goto    loop11       ;
        call    timewidshort ;
loop20
        btfsc   PORTA,0      ;その後、光が消灯するまで待つ。
        goto    loop20       ;この間の時間長は timewidlong で設定されている。

     ;入射してくる光パルスの数をカウントする
     ;消灯時間幅 timewidshort、　点灯時間幅 timwwidshort で設定されている。
     ;”消灯＋点灯”＋”消灯＋点灯”＋．．．＋消灯”＋消灯　の連続
     ;消灯が連続した時が１つの桁のデータの完了を示している。  
     ;受信した６組のデータは、以下の順に変数に代入しておく。
     ;  keycode6,keycode5,keycode4,keycode3,keycode2,keycode1

        movlw   codefig          ;桁定数を
        movwf   count            ;count に代入
     
     ;６桁目の光りパルス数を受信し、数値化する
        call    timewidshort     ;タイミング調整のため、Wt の時間待機する。
        call    timewidhalf      ;タイミング調整のため、Wt の半分の時間待機する。
        call    numerize
        movf    i,0
        movwf   keycode6
     ;５桁目
        call    timewidshort     ;
        call    timewidshort      ;
        call    numerize         ;
        movf    i,0
        movwf   keycode5         ;
     ;４桁目
        call    timewidshort     ;
        call    timewidshort      ;
        call    numerize
        movf    i,0
        movwf   keycode4
     ;３桁目
        call    timewidshort     ;
        call    timewidshort     ;
        call    numerize         ;
        movf    i,0
        movwf   keycode3         ;
     ;２桁目
        call    timewidshort     ;
        call    timewidshort      ;
        call    numerize
        movf    i,0
        movwf   keycode2
     ;１桁目
        call    timewidshort     ;
        call    timewidshort      ;
        call    numerize         ;
        movf    i,0
        movwf   keycode1         ;
        return

;*****************************
;光パルスのカウント
numerize
        clrf    i
figure
        btfss   PORTA,0          ;
        goto    endfig           ;
        incf    i,1
    ;    bsf     PORTB,5          ;受信光パルスのモニターに
        call    timewidshort     ;
    ;    bcf     PORTB,5          ;使用できる。正常時、不必要。
        call    timewidshort     ;
        goto    figure
endfig
        return

;************************************************************************************
;ＥＥＰＲＯＭに、受信したキー暗号コード（１０新６桁の整数値）を書き込む
datawrite
        clrf     e_adrs          ;e_adrs=0 とし、
        movf     e_adrs,0        ;Ｗレジスタに取り込み、 
        movwf    EEADR           ;ＥＥＰＲＯＭアドレスの初期値とする。
        movf     keycode6,0      ;書き込むデータの６桁目をＥＥＰＲＯＭ
        movwf    EEDATA          ;専用レジスタに代入。
        call     eepromwrite     ;

        incf     e_adrs,1        ;アドレスを＋１する。
        movf     e_adrs,0        ;e_adrs をＷレジスタに取り込み、
        movwf    EEADR           ;EEADR に代入する
        movf     keycode5,0      ;５桁目
        movwf    EEDATA          ;
        call     eepromwrite     ;
     
        incf     e_adrs,1        ;アドレスを＋１する。
        movf     e_adrs,0        ;
        movwf    EEADR           ;
        movf     keycode4,0      ;４桁目
        movwf    EEDATA          ;
        call     eepromwrite     ;

        incf     e_adrs,1        ;アドレスを＋１する。
        movf     e_adrs,0        ;
        movwf    EEADR           ;
        movf     keycode3,0      ;３桁目
        movwf    EEDATA          ;
        call     eepromwrite     ;
     
        incf     e_adrs,1        ;アドレスを＋１する。
        movf     e_adrs,0        ;
        movwf    EEADR           ;
        movf     keycode2,0      ;２桁目
        movwf    EEDATA          ;
        call     eepromwrite     ;

        incf     e_adrs,1        ;アドレスを＋１する。
        movf     e_adrs,0        ;
        movwf    EEADR           ;
        movf     keycode1,0      ;１桁目
        movwf    EEDATA          ;
        call     eepromwrite     ;
        return

;*****************************
;ＥＥＰＲＯＭへの書き込み手順ルーチン
eepromwrite
        bsf      STATUS,RP0      ;バンク１に移動
        bsf      EECON1,WREN     ;書き込みを許可する
        movlw    55h             ;書き込み回数をセットして、
        movwf    EECON2          ;おまじない
        movlw    0aah            ;
        movwf    EECON2          ;
        bsf      EECON1,WR       ;書き込み開始
writeloop
        btfsc    EECON1,WR       ;書き込み完了まで待機
        goto     writeloop       ;

        bcf      STATUS,RP0      ;バンク０に戻る
        return 

;***********************************************************************************
;記憶している６桁の暗号コードをＥＥＰＲＯＭから読み出す。
memoryout
        clrf     e_adrs          ;ＥＥＰＲＯＭアドレスの初期値は０としている。 
        call     eepromread      ;最上位６桁目をＥＥＰＲＯＭから読み出し、
        movwf    memcode6        ;memcode6 に代入しておく

        incf     e_adrs,1        ;アドレスを＋１する
        call     eepromread      ;５桁目
        movwf    memcode5        ;  

        incf     e_adrs,1        ;アドレスを＋１する
        call     eepromread      ;４桁目
        movwf    memcode4        ;

        incf     e_adrs,1        ;アドレスを＋１する
        call     eepromread      ;３桁目
        movwf    memcode3        ;

        incf     e_adrs,1        ;アドレスを＋１する
        call     eepromread      ;２桁目     
        movwf    memcode2        ;
  
        incf     e_adrs,1        ;アドレスを＋１する
        call     eepromread      ;１桁目
        movwf    memcode1        ;
        return

;**************************
;ＥＥＰＲＯＭからの読み出し
eepromread
        movf     e_adrs,0        ;ＷレジスタにＥＥＰＲＯＭアドレス値を取り込み、
        movwf    EEADR           ;ＥＥＰＲＯＭアドレス指定専用レジスタに代入。
        bsf      STATUS,RP0      ;バンク１に移る
        bsf      EECON1,RD       ;読み出し開始
        bcf      STATUS,RP0      ;バンク０に戻る
        movf     EEDATA,0        ;Ｗレジスタにデータを取り出す。最上位６桁目
        return

;**********************************************************************************
;プログラムの試験のため、ＥＥＰＲＯＭに登録した数値をＬＥＤから光りパルス列として出力する
;　　やり方は、キーのプログラムをそのまま簡単にコピーすればよいはず
;timewidshort の時間幅ＬＥＤを点灯し、引き続いて同じ時間幅ＬＥＤを消灯する。
;これを数値の回数だけ繰り返す。最後に、終了を示す同じ時間だけの消灯時間を付加している。 
ledout
        movwf    i               ;
        incf     i,1             ;数値０の処理の回避方法　ｉを＋１に嵩上げしておく
ledloop
        bcf      PORTB,7         ;この間、ＬＥＤを
        call     timewidshort    ;消灯している
        decfsz   i,1             ;ｉが１になったら、
        goto     bipass          ;ＬＥＤは継続して消灯したまま、送信完了とする
        goto     endled
bipass  bsf      PORTB,7         ;この間、ＬＥＤを
        call     timewidshort    ;点灯している
        goto     ledloop         ;
endled
        call     timewidshort    ;１桁データ転送終了時間間隔
        return

;***********************************************************************************
;一定時間幅設定ルーチン　その０　長時間幅用　約１秒
;timebase0 の値で変更可能　
timewidlong
      movlw   timebase0    ;＝５　　　約１．０秒
      movwf   temp0        ;
twloop3
      clrf    temp1        ;
      clrf    temp2        ;
twloop0
      decfsz  temp1,1      ;
      goto    twloop0
      decfsz  temp2,1      ;
      goto    twloop0
      decfsz  temp0,1      ;
      goto    twloop3 
      return

;************************************************************************************
;一定時間幅設定ルーチン　その１　短時間幅用
;timebase1 timebase2 の値で設定自在　
timewidshort
      movlw   timebase1    ;２５６×２５６　約０．４秒
      movwf   temp1        ;１２８×１２８　約０．１秒
      movlw   timebase2    ;
      movwf   temp2        ;　
twloop1
      decfsz  temp1,1      ;
      goto    twloop1
      movlw   timebase1    ;
      movwf   temp1        ;
      decfsz  temp2,1      ;
      goto    twloop1
      return

;************************************************************************************
;一定時間幅設定ルーチン　その２　短時間幅の半分に設定
timewidhalf
      movlw   timebase1    ;
      movwf   temp1        ;
      bcf     STATUS,C
      movlw   timebase2    ;timebase2 の半値を、
      movwf   count
      rrf     count,0      ; 
      movwf   temp2        ;temp2 に代入　
twloop2
      decfsz  temp1,1      ;
      goto    twloop2
      movlw   timebase1    ;
      movwf   temp1        ;
      decfsz  temp2,1      ;
      goto    twloop2
      return

;************************************************************************************
;動作の試験のため、ＬＥＤを点滅させる
checker
      bsf     PORTB,7
      call    timewidshort
      bcf     PORTB,7
      call    timewidshort
      return

;************************************************************************************
;終了
jobend
      bcf     PORTB,7      ;コードＬＥＤを消灯する。
      return

;************************************************************************************

      end





