;　　　　　　プログラム名　　　Tra_v2   (mother trans_key
;
;論理信号を使用した鍵システム（鍵＋錠）の鍵側のプログラムである
;
;ＰＩＣ１６Ｆ８４を使用し、
;　（１）１０進数６桁の暗号番号を１０種類登録できる
;　（２）指定したキー番号の暗号番号を出力し、錠側で受信する。
;
;改訂開始　２００１年１２月２８日　　　　　　　　　　金野
;　　　　　２００２年　１月１０日一応改訂完了
;仕様
;１．キー番号　０～９までの１０個の整数値で指定可能
;２．暗号コード　各キー番号毎に、１０進数６桁の数値。（ＥＥＰＲＯＭ　６４バイト故）
;　　　　　　　　００００００～９９９９９９までの整数値。
;　　　　　　　　高位桁がゼロでも、必ず、全６桁の数値を入力しなければならない。
;　　注記　１６Ｆ８Ｘには、アドレス０ｈ～３Ｆｈまでの６４バイトのＥＥＰＲＯＭがある。
;　　　　　先頭番地から６バイトずつに区切って、暗号コードを書き込む。
;
;動作の概要
;１．電源スイッチをオンにしたとき、ＬＥＤが点滅し続けるときには、ロータリースイッチで指定している
;　　キー番号に暗証番号が未だ登録されていない場合である。
;２．希望するキー番号の暗号番号の出力。
;（１）ロータリスイッチを希望するキー番号に設定してから、電源スイッチをオンとすると、約２秒後
;　　そのキー番号の６桁の暗号コードが出力される。
;　　成功すれば、錠が開き、ＬＥＤが黄緑点灯し、失敗すればＬＥＤが赤点灯するだけである。
;（２）放置すれば、スリープモードに入る。再度やりたければ、（１）へ戻る。
;
;３．暗号コードの入力及び更新、変更の仕方
;　留意事項　暗号コードの最下位１桁目を入力した時点で、既成値が書き変わる。
;　　　　　　間違い、失敗、中止をしたい時には、それまでのうちにスタートキーを押せば
;　　　　　　初期状態に復帰する。
;（１）選択スイッチを押しながら、電源スイッチをオンとする。
;　　　モニターＬＥＤが点滅する。
;（２）選択スイッチを離すと、モニターＬＥＤが連続点灯する。
;（３）暗号コードを入力（変更、更新）したいキー番号値をロータリースイッチで指定し、
;　　　選択スイッチを押して離す。
;　　　　　　キー番号値が読み込まれ、モニターＬＥＤが数秒間点滅した後、連続点灯する。
;（５）暗号コードの最上位６桁目の数値をロータリースイッチで指定し、
;　　　選択スイッチを押す。　
;　　　　　　数値が読み込まれ、　　　モニターＬＥＤが数秒間点滅した後、連続点灯する。
;（６）（５）に従って、５桁目を入力する。
;（７）同じ、４桁目を入力する。
;（８）３桁目を入力する。
;（９）２桁目。
;（１０）１桁目を入力する。ＥＥＰＲＯＭに書き込まれ、暗号コードの入力完了。
;
;　更に暗号コードを入力したければ、（１）から繰り返せばよい。
;
;
;************************************************************************************
;
     LIST P=PIC16F84           ;使用するプロセッサの種類を指定する
     #INCLUDE "P16F84.INC"     ;上記のプロセッサ用インクルードファイルを呼び出し、結合する

;PIC本体の初期設定
     __CONFIG  _WDT_OFF & _XT_OSC
                               ;ウオッチドックタイマーはオフ
                               ;発信はクリスタル方式
;*********************************
;使用する変数の定義
   CBLOCK h'000C'
      i           ;任意使用のカウンタ変数
      count       ;任意使用のカウンタ変数
      temp0       ;カウンター用変数
      temp1       ;カウンター用変数
      temp2       ;カウンター用変数
      keycode6    ;暗号コードの入る６バイト（６桁整数値）変数
      keycode5
      keycode4
      keycode3
      keycode2
      keycode1
      keynumber   ;開錠するキー番号の入る変数
      number      ;ロータリースイッチの指定する数値の入る変数
      e_adrs      ;ＥＥＰＲＯＭのアドレスの入る変数
      
   ENDC

;*********************************
;使用端子に名称を定義する
;  #define   RSmonitor  PORTA   ;ＲＡ端子に名称を与える

;*********************************
;使用する定数の定義
codefig     equ     6          ;暗号コードの桁数

timebase0   equ     5    ;3    ;時間幅設定用定数その０　ＬＥＤ点灯（セット表示）用
timebase1   equ    64    ;255  ;時間幅設定用定数その１　ＬＥＤ点滅（送信データ長）用
timebase2   equ   128    ;255  ;時間幅設定用定数その２　ＬＥＤ点滅（送信データ長）用
                               ;timebase1,timebase2 の値は錠側のプログラムのそれと
                               ;　　　　　　　　　　同じとしなければならない

;***********************************************************************************
;
        org      0               ;
start
    ;ポートの初期設定
    ;　ポートＡ　ＲＡ０～ＲＡ３　入力端子。
    ;　　　　　　４ビット１０進数ＲＳのモニター端子。
    ;　ポートＢ　ＲＢ７　出力端子。ＬＥＤの駆動。　
    ;　　　　　　ＲＢ３　入力端子。選択スイッチに接続。　 

        bcf     STATUS,RP1   ;バンク１に移る
        bsf     STATUS,RP0   ;
        movlw   b'11111111'  ;ＲＡ３，２，１，０を入力端子に、
        movwf   TRISA        ;残り（未使用）も入力端子に指定しておく。
        movlw   b'01111111'  ;ＲＢ７を出力端子、ＲＢ３を入力端子に、
        movwf   TRISB        ;残りは入力端子に指定。
        bcf     STATUS,RP0   ;バンク０に戻る。

        bcf     PORTB,7      ;ＬＥＤを消灯。


        call    timewidlong  ;鍵及び錠の両方が安定するまで時間を稼ぐ
        call    timewidlong  ;１秒＋１秒



    ;選択スイッチ（ＲＢ３ポート）の状態を調べ、処理を分岐する。
    ;　　押されていなければ（＝Ｈ）、ロータリースイッチからキー番号を読み込み、
    ;　　　　　　　　　　　　　　　　その番号の暗号コードをコードＬＥＤから出力する。
    ;　　押されていれば（＝Ｌ）、キー番号、暗号コードの入力を行う。
        btfsc   PORTB,3      ;
        goto    codeoutput   ;
        goto    codeinput    ;

;***********************************************************************************
;ロータリスイッチの指示しているキー番号の暗号コードをＥＥＰＲＯＭから読み出した後、出力する
codeoutput
    ;キー番号の読み込み
        call    RS_decode    ;number にロータリスイッチで指定している数値を取り込む。
        movf    number,0     ;number の値を
        movwf   keynumber    ;keynumber に代入。
        bsf     PORTB,7
        call    timewidlong  ;データ送信開始の合図として、ＬＥＤを数秒間点灯させる。
        bcf     PORTB,7      ;ＬＥＤを消し、データの転送に入る。

    ;読み込んだキー番号の６桁の暗号コードをＥＥＰＲＯＭから読み出す。
        movf     keynumber,0     ; keynumber の値をＷレジスタに取り込む。
        addwf    keynumber,0     ;キー番号値を６倍し、対応するＥＥＰＲＯＭアドレスの初期値を算出する。
        addwf    keynumber,0     ;Ｗレジスタの内容＋keynumber をＷレジスタの内容とする。
        addwf    keynumber,0     ;
        addwf    keynumber,0     ;
        addwf    keynumber,0     ;以上で　keynumber を６回加算した。結果はＷレジスタにある。

        movwf    e_adrs          ;e_adrs に代入し、ＥＥＰＲＯＭアドレスの初期値とする。 
        call     eepromread      ;最上位６桁目　
        movwf    keycode6        ;取り込んだデータを代入しておく

        incf     e_adrs,1        ;アドレスを＋１する
        call     eepromread      ;５桁目
        movwf    keycode5        ;   

        incf     e_adrs,1        ;アドレスを＋１する
        call     eepromread      ;４桁目
        movwf    keycode4        ;

        incf     e_adrs,1        ;アドレスを＋１する
        call     eepromread      ;３桁目
        movwf    keycode3        ;

        incf     e_adrs,1        ;アドレスを＋１する
        call     eepromread      ;２桁目     
        movwf    keycode2        ;
  
        incf     e_adrs,1        ;アドレスを＋１する
        call     eepromread      ;１桁目
        movwf    keycode1        ;

     ;６桁のデータを順次出力する。ＬＥＤでモニターできる
        call     dataout

        sleep                    ;暗号コードを１回出力したら、省電力のためスリープモードに入る。
                                 ;スタートキーが押されるとプログラムの先頭からの開始となる。
        return

;**************************
;ＥＥＰＲＯＭからの読み出し
eepromread
        movf     e_adrs,0        ;ＷレジスタにＥＥＰＲＯＭアドレス値を取り込み、
        movwf    EEADR           ;ＥＥＰＲＯＭアドレス指定専用レジスタに代入。
        bsf      STATUS,RP0      ;バンク１に移る
        bsf      EECON1,RD       ;読み出し開始
        bcf      STATUS,RP0      ;バンク０に戻る
        movf     EEDATA,0        ;Ｗレジスタにデータを取り出す。最上位６桁目
        return

;**************************
;timewidshort の時間幅ＬＥＤを点灯し、引き続いて同じ時間幅ＬＥＤを消灯する。
;これを数値の回数だけ繰り返す。最後に、終了を示す同じ時間だけの消灯時間を付加している。 
dataout
        movf     keycode6,0      ;６桁目のデータを取り込み、
        movwf    i               ;
        call     figout          ;出力に入る

        movf     keycode5,0      ;５桁目のデータを取り込み、
        movwf    i               ;
        call     figout          ;出力に入る

        movf     keycode4,0      ;４桁目のデータを取り込み、
        movwf    i               ;
        call     figout          ;出力に入る

        movf     keycode3,0      ;３桁目のデータを取り込み、
        movwf    i               ;
        call     figout          ;出力に入る

        movf     keycode2,0      ;２桁目のデータを取り込み、
        movwf    i               ;
        call     figout          ;出力に入る

        movf     keycode1,0      ;１桁目のデータを取り込み、
        movwf    i               ;
        call     figout          ;出力に入る
        return

;*************************
;１桁だけの出力ルーチン
figout
        incf     i,1             ;数値０の処理の回避方法　ｉを＋１に嵩上げしておく
dataloop
        bcf      PORTB,7         ;この間、ＬＥＤを
        call     timewidshort    ;消灯している
        decfsz   i,1             ;ｉが１になったら、
        goto     bipass          ;ＬＥＤは継続して消灯したまま、送信完了とする
        goto     endled
bipass  bsf      PORTB,7         ;この間、ＬＥＤを
        call     timewidshort    ;点灯している
        goto     dataloop        ;
endled
        call     timewidshort    ;１桁データ転送終了時間間隔
        return

;***********************************************************************************
RS_decode
    ;ロータリースイッチの数値の読み込み
    ;　　　　　　　　　　　　対応表
    ;　　　　　　　０　１　２　３　４　５　６　７　８　９
    ;ＲＡ０（１）　Ｌ　Ｈ　Ｌ　Ｈ　Ｌ　Ｈ　Ｌ　Ｈ　Ｌ　Ｈ
    ;ＲＡ１（２）　Ｌ　Ｌ　Ｈ　Ｈ　Ｌ　Ｌ　Ｈ　Ｈ　Ｌ　Ｌ
    ;ＲＡ２（４）　Ｌ　Ｌ　Ｌ　Ｌ　Ｈ　Ｈ　Ｈ　Ｈ　Ｌ　Ｌ
    ;ＲＡ３（８）　Ｌ　Ｌ　Ｌ　Ｌ　Ｌ　Ｌ　Ｌ　Ｌ　Ｈ　Ｈ
   
        clrf     number          ;
check8
        btfss    PORTA,3         ;
        goto     check4          ;８のビットのチェック
        movlw    8
        addwf    number,1        ;number を＋８  
check4
        btfss    PORTA,2         ;
        goto     check2          ;４のビットのチェック
        movlw    4
        addwf    number,1        ;number を＋４
check2
        btfss    PORTA,1         ;
        goto     check1          ;２のビットのチェック
        movlw    2
        addwf    number,1        ;numner を＋２
check1
        btfss    PORTA,0         ;
        goto     checkend        ;１のビットのチェック
        movlw    1
        addwf    number,1        ;number を＋１
checkend  
        return

;**********************************************************************************
;キー番号を指定して、その番号での暗号コードを入力する
codeinput  
repeat50
        bsf      PORTB,7         ;            
        call     timewidshort    ;モニターＬＥＤを点滅させ、
        bcf      PORTB,7         ;
        call     timewidshort    ;
        btfss    PORTB,3         ;選択スイッチを押すことが、終了した
        goto     repeat50        ;ことを確認した後、次の処理に入る。

        call     catprotect      ;選択スイッチのチャッタリング対策。
        bsf      PORTB,7         ;モニターＬＥＤ連続点灯

   ;ロータリースイッチからキー番号を読みとる。
repeat55
        btfsc    PORTB,3         ;ロータリースイッチで設定された値を読み込むために、
        goto     repeat55        ;選択スイッチが押されるまで待機。
        call     RS_decode       ;キー番号が number に代入される。
        movf     number,0        ;得られた数値を
        movwf    keynumber       ;keynumber に代入
        call     catprotect      ;チャッタリング防止

   ;ロータリースイッチから６桁の暗号コードを読みとる。
   ;　　　モニターＬＥＤ点滅から、連続点灯になった時点で、選択スイッチを押すことで、  
   ;　　　高位桁から、１桁ずつ読み込まれる。
        call     readkeycode     ;ロータリスイッチで指定した数値を読み出す。
        movwf    keycode6        ; keynumber6 に代入
        call     readkeycode     ; 
        movwf    keycode5        ; keynumber5 に代入
        call     readkeycode
        movwf    keycode4        ; keynumber4 に代入
        call     readkeycode
        movwf    keycode3        ; keynumber3 に代入
        call     readkeycode
        movwf    keycode2        ; keynumber2 に代入
        call     readkeycode
        movwf    keycode1        ; keynumber1 に代入
 
        bcf      PORTB,7         ;ＬＥＤ消灯
        call     catprotect      ;チャッタリング防止

;*****************************
;ＥＥＰＲＯＭに、入力したキー番号の暗号コードを書き込む
;　　　　　　　　　　　　　　　　　　　対応表
;　　　キー番号　　　　　　０　１　　２　　３　　４　　５　　６　　７　　８　　９　　
;　EEPROMアドレス初期値　　０　６　１２　１８　２４　３０　３６　４２　４８　５４
;
        movf     keynumber,0     ; keynumber の値をＷレジスタに取り込む。
        addwf    keynumber,0     ;キー番号値を６倍し、対応するＥＥＰＲＯＭアドレスの初期値を算出する。
        addwf    keynumber,0     ;Ｗレジスタの内容＋keynumber をＷレジスタの内容とする。
        addwf    keynumber,0     ;
        addwf    keynumber,0     ;
        addwf    keynumber,0     ;以上で　keynumber を６回加算した。結果はＷレジスタにある。

        movwf    e_adrs          ;e_adrs に代入し、ＥＥＰＲＯＭアドレスの初期値とする。 
        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     ;

        sleep                    ;登録を完了したので、冬眠へ
        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
  
;****************************************************     
;ロータリースイッチで指定した暗号数値を読み出す。６桁分なので６回読み出される。
readkeycode
        movlw    5              ;ＬＥＤを５回点滅し、
        movwf    temp0          ;その後連続点灯し、入力待ちとする
ledloop
        bsf      PORTB,7        ;ＬＥＤの点滅
        call     timewidshort   ;
        bcf      PORTB,7        ;
        call     timewidshort   ;
        decfsz   temp0,1        ;
        goto     ledloop        ;
        bsf      PORTB,7        ;その後、連続点灯
readloop
        btfsc    PORTB,3        ;
        goto     readloop       ;選択スイッチが押されるまで待機。
        call     RS_decode      ;選択スイッチが押されると、ロータリスイッチで指定した数値が読み込まれる。
        movf     number,0       ;その値をＷレジスタに取り込んで、戻る。
        return 
  
;****************************************************
;ＬＥＤの定時間点滅ルーチン　　
ledonoff
      return

;****************************************************
;チャッタリング防止遅延ループ　約０．４秒程度　　　
catprotect
      clrf    temp0        ;２５６×２５６回のループ
      clrf    temp1        ;
catloop
      decfsz  temp0,1      ;
      goto    catloop
      decfsz  temp1,1      ;
      goto    catloop
      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

;************************************************************************************
;終了
jobend
      bcf     PORTB,7      ;コードＬＥＤを消灯する。
      return

;****************************************************
;
      end





