;※ 本ソースは固定幅フォント、120桁で見やすくなるようコーディングしています。

;***********************************************************
;
;  間欠ワイパー車速対応コントローラ Ver.3.00A
;
;***********************************************************
;
;【機能概要】
;
; 間欠ワイパーの拭き取り間隔を車速低速時(15Km/h以下)に長くなるよう制御し、車速感応式間欠ワイパー
; とするPIC12F1822用プログラム。
;
;【変更履歴】
;
; 2014. 5. 6 Ver1.00     -00 新規作成
; 2014. 5.17 Ver2.00A    -00 設定機能追加
; 2014. 5.18 Ver2.01A    -00 設定完了処理（SET_L9） が 主処理（MAIN）の中にあった
; 2014. 5.20 Ver2.02A    -00 主処理で割り込みOFFとなっていた。
;                        -01 割合取得アドレス計算ミス "ADDFW   fWA_TBL0" -> "ADDLW   fWA_TBL0"
;                        -02 ワイパーリレー入力と車速パルス入力のピン割り当てを入替
;                        -03 車速パルス判定極性反転（H->L を L->H）
; 2014. 7.18 Ver3.00A    -00 減速抵抗無し対応
;                        -01 割合計算方法変更
;                        -02 減速パターン0を２倍ではなく３倍に変更
;
;【詳細情報】
;
; １．PIC12F1822の各ピンの割り当て
;
;   ピン        機能
;   -------------------------------------------------------------------------------
;   1   P   VDD VDD(+5V電源)
;   2   O   RA5 確認用LED
;   3   I   RA3 車速パルス入力 / VPP（PICプログラマー用）
;   4   I   RA4 ワイパーリレー入力（L:拭き取り中、H:待機中） / タクトスイッチ
;   5   O   RA2 減速リレー制御（L:通常、H:減速）
;   6   I   RA1 ICSPCLK（PICプログラマー用）
;   7   I   RA0 ICSPDAT（PICプログラマー用）
;   8   P   VSS VSS
;
; ２．設定
;
;  機能有効/無効設定 : 無効設定の場合、拭き取り間隔を制御しない。
;  減速パターン設定：  パターン 0  標準の３倍となる設定
;                      パターン 1  INTツマミにかかわらず、約10秒とする。
;                      パターン 2  INTツマミ0...8で25秒...33秒
;
; ３．ラベルの規約
;
;   xxxx_Ln     ループラベル。n...外側のループから昇順の整数（ルーチン内の通番）
;   xxxx_Jn     ジャンプラベル。n...整数（ルーチン内の通番）
;   fxxxx       ファイルレジスタ
;   fxxxx_L     fxxxxの下位８ビット ファイルレジスタ
;   fxxxx_M     fxxxxの中位８ビット ファイルレジスタ
;   fxxxx_H     fxxxxの上位８ビット ファイルレジスタ
;   C_xxxx      定数
;   F_xxxx      フラグビット位置
;   M_xxxx      フラグマスク
;
; ４．仕様
;
;  (1) 起動時
;
;   ・設定スイッチが押されている場合、設定モードとする。
;   ・設定スイッチが押されていない場合、通常モードとする。
;
;  (2) 設定モード
;
;   ・LEDを点灯する。
;   ・設定スイッチを３秒以内にOFFにした場合、(5)通常動作モードとする。
;   ・設定スイッチを５秒以内にOFFにした場合、(3)減速パターン設定モードとする。
;   ・設定スイッチを５秒以上押されていた場合、(4)機能有効/無効設定モードとする。
;
;  (3) 減速パターン設定モード
;
;   ・パターン 0 が設定されている場合、LED 2回点滅を繰り返す。
;   ・パターン 1 が設定されている場合、LED 3回点滅を繰り返す。
;   ・パターン 2 が設定されている場合、LED 1回点滅を繰り返す。
;   ・設定スイッチをクリックすることで、設定を変更。
;   ・設定スイッチを３秒以上長押しでEEPROMへ設定を保存し、通常モードとする。
;
;  (4) 機能有効/無効設定モード
;
;   ・機能有効が設定されている場合、LEDを早い点滅とする。
;   ・機能無効が設定されている場合、LEDを遅い点滅とする。
;   ・設定スイッチをクリックすることで、設定を変更。
;   ・設定スイッチを３秒以上長押しでEEPROMへ設定を保存し、通常モードとする。
;
;  (5) 通常動作モード
;
;   ・機能無効設定の場合、停止する。
;   ・機能有効設定の場合、拭き取り速度をコントロールする。
;　　  1) 時速20Km/h以上で通常の拭き取り速度とする。
;　　  2) 時速15Km/h以下で拭き取り速度を遅くする。（機能A/Bで拭き取り速度は変える）
;

;==================================
; 各種宣言
;==================================

;--------------
; PIC基本定義
;--------------

	LIST	P=12f1822
	#INCLUDE <p12f1822.inc>

    __CONFIG _CONFIG1,  _FOSC_INTOSC & _WDTE_OFF & _PWRTE_ON & _MCLRE_OFF & _CP_OFF & _CPD_OFF & _BOREN_OFF & _CLKOUTEN_OFF & _IESO_OFF & _FCMEN_OFF

                        ; _FOSC_INTOSC      内部クロックとする
                        ; _WDTE_OFF         ウォッチドックタイマを使用しない
                        ; _PWRTE_ON         パワーアップタイマを使用する
                        ; _MCLRE_OFF        MCLR/VPP端子をデジタル入力に使用する
                        ; _CP_OFF           プログラムメモリーの保護を行わない
                        ; _CPD_OFF          データメモリーの保護を行わない
                        ; _BOREN_OFF        ブラウンリセットを使用しない
                        ; _CLKOUTEN_OFF     CLKOUT機能を無効にする
                        ; _IESO_OFF         内部/外部切替を無効にする
                        ; _FCMEN_OFF        Fail-Safeクロックモニターを使用しない

    __CONFIG _CONFIG2, _WRT_OFF & _PLLEN_OFF & _STVREN_OFF & _BORV_19 & _LVP_OFF

                        ; _WRT_OFF          プログラム・メモリを書込み禁止にしない
                        ; _PLLEN_OFF        4倍PLLは動かさない
                        ; _STVREN_OFF       スタックオーバフロー、アンダーフローで
                        ;                   リセットしない
                        ; _BORV_19          ブラウンアウト電圧を1.9Vに設定する
                        ; LVP_OFF           プログラミング時はMCLRに高電圧を使用する

;-------------
; マクロ定義
;-------------

BANK_0	MACRO   ;バンク０に変更
	MOVLB	0
	ENDM
BANK_1	MACRO   ;バンク１に変更
	MOVLB	1
	ENDM
BANK_2	MACRO   ;バンク２に変更
	MOVLB	2
	ENDM
BANK_3	MACRO   ;バンク３に変更
	MOVLB	3
	ENDM
BANK_4	MACRO   ;バンク４に変更
	MOVLB	4
	ENDM
BANK_5	MACRO   ;バンク５に変更
	MOVLB	5
	ENDM
BANK_6	MACRO   ;バンク６に変更
	MOVLB	6
	ENDM
BANK_7	MACRO   ;バンク７に変更
	MOVLB	7
	ENDM


;-----------
; 定数定義
;-----------

C_TMR0init  EQU     6       ; TMR0の割込みサイクルを 250usec とする
                            ;   250usec = 4クロック / 4MHz x (256 - C_TMR0init)
C_RRP       EQU     4       ; タイヤ１回転あたりの車速センサ発生パルス数
                            ;   車により異なる：4,8 (16,20,25は未サポート)
C_LED_TCNT  EQU     D'40'   ; LED ON/OFF判定間隔 10msec = 250usec(TMR0割込み間隔) x C_LED_TCNT

;----- フラグ定義(変数 fFLG用)

F_SPOF      EQU     7       ; 前回計測車速（0…約5.5km/h以上、1…約5.5km/h以下）
F_SPFLG     EQU     6       ; 車速状態（0…低速、1…高速）20Km/h以上の場合1、15Km/h以下の場合0にする
F_WSET      EQU     5       ; ワイパー間隔の測定終了（0…測定中、1…測定終了）
F_WPOW      EQU     4       ; ワイパーレバー判定（０…OFF、１…OFF以外（INT等））
F_WSAV      EQU     3       ; 拭き取り状態（0…前回待機、1…前回拭き取り）
F_WEGD      EQU     2       ; 拭き取り開始（0…拭き取りまたは待機中、1…拭き取り開始直後）
F_WSTP      EQU     1       ; 拭き取り終了（0…拭き取りまたは待機中、1…拭き取り終了直後）
F_SET       EQU     0       ; 動作モード（0…通常動作モード、1…設定モード）

;------ 機能設定関連

C_EEADR_SET EQU     0x40    ; 設定値格納 EEPROM アドレス
C_EEADR_FNC EQU     0x41    ; パターン番号格納 EEPROM アドレス
C_EEADR_FPT EQU     0x50    ; 機能データ格納 EEPROM 開始アドレス

F_SET_DISF  EQU     7       ; 機能無効フラグ（0…有効、1…無効）
M_SET_DISF  EQU     0x80    ; F_SET_DISFのマスク


;----------
; 変数定義
;----------

    ;----- 全BANK共通変数

    CBLOCK 070h

        fSAVE_W         ; 割り込みルーチン W レジスタの保存用
        fSAVE_S         ; 割り込みルーチン STATUS レジスタの保存用

    ENDC


    ;----- BANK0変数

    CBLOCK 020h

        fFLG            ; 各種フラグ

        fSPTC_L         ; 車速パルス間隔カウンタの下位８ビット
        fSPTC_H         ; 車速パルス間隔カウンタの上位８ビット

        fRRPIDX         ; 車速パルス間隔カウンタ配列のインデックス

        fSPTCT_L        ; 車速パルス間隔カウンタ合計の下位８ビット
        fSPTCT_H        ; 車速パルス間隔カウンタ合計の上位８ビット

        fWA             ; ワイパー低速・高速割合
        fWINT           ; ワイパー間隔の測定結果

        fWCNT           ; 拭き取り動作チェックカウンタ

        fTMP_L          ; １６ビット計算用一時領域（下位８ビット）
        fTMP_H          ; １６ビット計算用一時領域（上位８ビット）

        ; 車速パルス間隔カウンタ配列 下位、上位の順で８個
        ;   C_RRP 個をサイクリックに使用する。

        fSPTCA0_L
        fSPTCA0_H

        fSPTCA1_L
        fSPTCA1_H

        fSPTCA2_L
        fSPTCA2_H

        fSPTCA3_L
        fSPTCA3_H

        fSPTCA4_L
        fSPTCA4_H

        fSPTCA5_L
        fSPTCA5_H

        fSPTCA6_L
        fSPTCA6_H

        fSPTCA7_L
        fSPTCA7_H

        ; ワイパー間隔関連変数

        fWINTT_L        ; ワイパー間隔の測定用カウンタ（下位８ビット）
        fWINTT_M        ; ワイパー間隔の測定用カウンタ（中位８ビット）
        fWINTT_H        ; ワイパー間隔の測定用カウンタ（上位８ビット）

        ; 四則演算用変数

        fA7             ; ┬── 演算変数 A' (32ビット)
        fA6             ; │
        fA5             ; │
        fA4             ; ┘

        fA3             ; ┬── 演算変数 A (32 ビット)
        fA2             ; │
        fA1             ; │┬─ 演算変数 A (16 ビット)
        fA0             ; ┘┘─ 演算変数 A ( 8 ビット)

        fB3             ; ┬── 演算変数 B（32 ビット）
        fB2             ; │
        fB1             ; │┬─ 演算変数 B (16 ビット)
        fB0             ; ┘┘─ 演算変数 B ( 8 ビット)

        fC3             ; ┬── 演算変数 C（32 ビット)
        fC2             ; │
        fC1             ; │┬─ 演算変数 C (16 ビット)
        fC0             ; ┘┘

        fD3             ; ┬── 演算変数 D（32 ビット）
        fD2             ; │
        fD1             ; │
        fD0             ; ┘

        ; 設定モード用変数

        fCHK_LCNT       ; ループカウンタ
        fSET            ; 設定
        fFNC            ; 減速パターン番号
        fLED_ADR        ; LED発光パターン読み出しアドレス
        fLED_ADR0       ; LED発光パターン読み出し先頭アドレス
        fLED_TCNT       ; TMR0割込みカウンタ
        fLED_SCNT       ; LED状態保持カウンタ

        ; 汎用カウンタ

        fCNT            ; 8ビットカウンタ
        fCNT_L          ; 16ビットカウンタ（下位）
        fCNT_H          ; 16ビットカウンタ（上位）

        ; 汎用インデックス

        fIDX_L          ; 16ビットインデックス（下位）
        fIDX_H          ; 16ビットインデックス（上位）

        ; デバッグ用変数

        fDEB_W          ; デバッグ開始時 W レジスタ保存用
        fDEB_CNT        ; デバッグ内カウンタ

    ENDC


;==================================
; リセットベクター
;==================================

	ORG     0x0000

    GOTO    INIT            ; goto INIT             // 初期化処理へジャンプ


;==================================
; 割込みベクター
;==================================

    ORG     0x0004

    ;---- 割り込み前処理

    MOVWF   fSAVE_W         ; fSAVE_W = W;          // W レジスタの保存
    SWAPF   STATUS,W        ; fSAVE_S = STATUS;     // STATUS レジスタの保存
    MOVWF   fSAVE_S

    ;------------------------
    ; タイマー０割込み処理
    ;------------------------


    ;---- TMR0割込み時処理

    BANK_0

    BTFSS   INTCON,TMR0IF   ; if ( INTCON.TMR0IF == 1 ) {
    GOTO    TMR0_END
                            ;   // TMR0の割込みがあった場合

    BCF     INTCON,TMR0IF   ;   INTCON[ TMR0IF ] = 0;               // TMR0割込みフラグクリア
    MOVLW   C_TMR0init      ;   TMR0 = C_TMR0init;                  // TMR0初期化
    MOVWF   TMR0


    ;---- 設定関連処理

    BTFSS   fFLG,F_SET      ;   if ( fFLG.F_SET == 1 ) {
    GOTO    WIPCHK
                            ;     // 設定モードの場合

    DECFSZ  fLED_TCNT,f     ;     fLED_TCNT--;
                            ;     if ( fLED_TCNT == 0 ) {
    GOTO    TMR0_END
                            ;       // TMR0割込みが C_LED_TCNT 回発生した場合（10msec間隔）

    MOVLW   C_LED_TCNT      ;       fLED_TCNT = C_LED_TCNT          // TMR0割込みカウンタ初期化
    MOVWF   fLED_TCNT

    MOVF    fLED_ADR,w      ;       if ( ((fLED_ADR xor fLED_ADR0) and B'00111000') != 0 ) {
    XORWF   fLED_ADR0,w
    ANDLW   B'00111000'     ;         // bit5-bit3 がLEDパターン番号
    BTFSC   STATUS,Z
    GOTO    LED_J8
                            ;         // パターンに変更があった場合

    MOVF    fLED_ADR,w      ;         fLED_ADR0 = fLED_ADR;          // 変更後のパターンを保存
    MOVWF   fLED_ADR0       ;
    MOVLW   1               ;         fLED_SCNT = 1;                 // すぐに変更が反映されるよう 1 にする
    MOVWF   fLED_SCNT
                            ;       }

LED_J8

    DECFSZ  fLED_SCNT,f     ;       fLED_SCNT--;                     // LED点灯/消灯時間カウンタデクリメント
    GOTO    TMR0_END        ;       if ( fLED_SCNT == 0 ) {

                            ;         // LED点灯/消灯時間終了の場合

LED_J3                      ;         do {
                            ;           while(1) {
    MOVF    fLED_ADR,w

LED_J1
    BANK_3
    MOVWF   EEADRL          ;             W = EEPROM[ fLED_ADR ];    // EEPROM よりLED発光パターン取得
    CALL    READ_EE

    INCFSZ  WREG,f          ;             if  ( W != 255 ) break;    // LED発光パターン終了(255)でない場合、ループを出る
    GOTO    LED_J2
                            ;             // LED点灯データ終了
    MOVF    fLED_ADR0,w     ;             fLED_ADR = fLED_ADR0;      // LED発光パターンの先頭に戻し、ループする
    MOVWF   fLED_ADR
    GOTO    LED_J1          ;           }

LED_J2
    INCF    fLED_ADR,f      ;           fLED_ADR++;                  // LED発光パターン取得アドレスを１つ進める
    DECFSZ  WREG,f          ;         } while ( W == 0 );            // LED発光パターンが 0 以外となるまで繰り返す
    GOTO    LED_J4
    GOTO    LED_J3

LED_J4
    MOVWF   fLED_SCNT       ;         fLED_SCNT = W;                 // LED点灯/消灯時間カウンタ初期化

    BTFSC   fLED_ADR,0      ;         if ( fLED_ADRのbit0 == 0 ) {   // LED発光パターン取得アドレスより消灯/点灯判定
    GOTO    LED_J5
                            ;           // 次のアドレスが偶数の場合
    BANK_2
    BCF     LATA,LATA5      ;           LATA5 = 0;                   // ＬＥＤ消灯

    GOTO    LED_J6          ;         } else {

LED_J5                      ;           // 次のアドレスが奇数の場合
    BANK_2
    BSF     LATA,LATA5      ;           LATA5 = 1;                   // ＬＥＤ点灯

LED_J6
    BANK_0                  ;         }
                            ;       }
                            ;     }
    GOTO    TMR0_END
                            ;   } else {

                            ;     // 通常モードの場合

    ;---- ワイパー間隔測定

WIPCHK

    BTFSS   fFLG,F_WPOW     ;     if ( fFLG.F_WPOW == 1 ) {       // ワイパーON/OFF判定
    GOTO    WIP_J1
                            ;       // ワイパーONの場合

    INCFSZ  fWINTT_L,f      ;       fWINNT++;                     // ワイパー間隔測定用カウント
    GOTO    WIP_J1
    INCFSZ  fWINTT_M,f
    GOTO    WIP_J1
    INCF    fWINTT_H,f

    MOVLW   2               ;       if ( fWINNT >= 0x20000 ) {
    SUBWF   fWINTT_H,w      
    BTFSS   STATUS,C
    GOTO    WIP_J1
                            ;         // 約32.7秒(0x20000×250usec)経過した場合

    BCF     fFLG,F_WPOW     ;         fFLG.F_WPOW = 0;            // ワイパーOFFとする

WIP_J1                      ;       }
                            ;     }

    ;---- 拭き取り動作チェック

    BTFSC   PORTA,RA4       ;     if ( RA4 == 0 ) {
    GOTO    WCHK_J1
                            ;       // 拭き取り中の検出


    BTFSC   fFLG,F_WSAV     ;         if ( fFLG.F_WSAV == 0 ) {
    GOTO    WCHK_J2
                            ;           // 拭き取り待機中だった場合

    BSF     fFLG,F_WSAV     ;           fFLG.F_WSAV = 1;          // 拭き取り中とする
    BSF     fFLG,F_WEGD     ;           fFLG.F_WEGD = 1;          // 拭き取り開始直後とする

    GOTO    WCHK_J2
                            ;         }
                            ;     } else {
WCHK_J1
                            ;       // 拭き取り待機中の検出

    BTFSS   fFLG,F_WSAV     ;         if ( fFLG.F_WSAV == 1 ) {
    GOTO    WCHK_J2
                            ;           // 拭き取り中だった場合

    BCF     fFLG,F_WSAV     ;           fFLG.F_WSAV = 0;          // 拭き取り待機中とする
    BSF     fFLG,F_WSTP     ;           fFLG.F_WSTP = 1;          // 拭き取り終了

                            ;         }
                            ;     }
WCHK_J2

    ;---- 車速用カウンタ処理

    INCFSZ  fSPTC_L,f       ;     fSPTC++;                         // 車速カウンタインクリメント
    GOTO    TMR0_END
    INCF    fSPTC_H,f

    MOVLW   C_RRP           ;     if ( fSPTC >= C_RRP*0x100 ) {
    SUBWF   fSPTC_H,w
    BTFSS   STATUS,C
    GOTO    TMR0_END
                            ;       // 車速が約5.5Km/hより低速の場合

    BSF     fFLG,F_SPOF     ;       fFLG.F_SPOF = 1;

    GOTO    PLS_J1

                            ;     }
                            ;   }
                            ; }
TMR0_END


    ;------------------------
    ; PORTA変化割り込み処理
    ;------------------------


    ;---- 設定判定

    BTFSC   fFLG,F_SET      ; if ( fFLG.F_SET == 0 ) {
    GOTO    INIT_END

                            ;   // 通常モードの場合

    ;---- PORTA割込み判定

    BANK_0
    BTFSS   INTCON,IOCIF    ;   if ( INTCON.IOCIF == 1 ) {
    GOTO    PLS_END
                            ;     // PORTAの変化で割り込みがあった場合

    BANK_7
    BTFSS   IOCAF,IOCAF3    ;     if ( IOCAF.IOCAF3 == 1 ) {
    GOTO    PLS_END2
                            ;       // RA3の変化で割り込みがあった場合

    BANK_0
    BTFSS   fFLG,F_SPOF     ;       if ( fFLG.F_SPOF == 1 ) {
    GOTO    PLS_J1

                            ;         // 前回の車速が約5.5Km/h以下だった場合

    BCF     fFLG,F_SPOF     ;         fFLG.F_SPOF = 0;
    GOTO    PLS_J3
                            ;       }
PLS_J1

    BANK_0
    DECF    fRRPIDX,f       ;       fRRPIDX--;                      // 車速パルス配列インデックスを進める
    LSLF    fRRPIDX,w       ;

    CLRF    FSR0H           ;                                       //  FSR0 = fSPTCA配列アドレス + fRRPIDX * 2;
    ADDLW   fSPTCA0_L
    MOVWF   FSR0L

    MOVF    INDF0,w         ;       fSPTCT = fSPTCT - fSPTCA[ fRRPIDX ];    // 車速パルス合計から古い値を引く
    SUBWF   fSPTCT_L,f

    MOVF    fSPTC_L,w       ;       fSPTCA[ fRRPIDX ] = fSPTC;      // 古い値の代わりに最新の値を入れる
    MOVWF   INDF0

    INCF    FSR0L,f
    MOVF    INDF0,w
    SUBWFB  fSPTCT_H,f

    MOVF    fSPTC_H,w
    MOVWF   INDF0

    MOVF    fSPTC_L,w       ;       fSPTCT = fSPTCT + fSPTC;        // 車速パルス合計に最新の値を加える
    ADDWF   fSPTCT_L,f
    MOVF    fSPTC_H,w
    ADDWFC  fSPTCT_H,f

    MOVF    fRRPIDX,f       ;       if ( fRRPIDX == 0 ) {
    BTFSS   STATUS,Z
    GOTO    PLS_J3
                            ;         // インデックスが 0 の場合

    MOVLW   C_RRP           ;         fRRPIDX = C_RRP;              // インデックスを初期化する
    MOVWF   fRRPIDX

                            ;       }
PLS_J3

    CLRF    fSPTC_L         ;       fSPTC = 0;                      // 車速パルスカンタを初期化する
    CLRF    fSPTC_H         ;


                            ;     }
PLS_END2


    ;---- PORTAで変化のあったビットのみクリアする

    BANK_7
    MOVLW   0xFF
    XORWF   IOCAF,W
    ANDWF   IOCAF,F

                            ;   }
PLS_END


    ;------------------------
    ; 拭き取り開始チェック
    ;------------------------

    BANK_0

    BTFSS   fFLG,F_WEGD     ;   if ( fFLG,F_WEGD == 1 ) {
    GOTO    PLS_END4
                            ;     // 拭き取り開始した場合

    BCF     fFLG,F_WEGD     ;     fFLG.F_WEGD = 0;
    BTFSC   fFLG,F_WPOW     ;     if ( fFLG.F_WPOW == 0 ) {
    GOTO    PLS_J4
                             ;      // ワイパー停止の場合

    BSF     fFLG,F_WPOW     ;       fFLG.F_WPOW = 1;                // ワイパー動作中に変更

    GOTO    PLS_END3        ;     } else {

PLS_J4

    LSRF    fWINTT_H,f      ;       fWINT = fWINTT / 0x200;         // 測定結果を算出
    RRF     fWINTT_M,f
    MOVF    fWINTT_M,w
    MOVWF   fWINT

    BSF     fFLG,F_WSET     ;       fFLG.F_WSET = 1;                // 測定結果設定フラグON

PLS_END3                    ;     }

    CLRF    fWINTT_L        ;     fWINTT = 0;                       // 測定カウンタの初期化
    CLRF    fWINTT_M
    CLRF    fWINTT_H

    BANK_5
    CLRF    CCP1CON         ;     CCP1CON = 0;                      // ＰＷＭをOFFにする
    BANK_2                  ;
    BCF     LATA,LATA2      ;     LATA.LATA2 = 0;                   // フォトモスリレーOFF

    BANK_2
    BCF     LATA,LATA5      ;     LATA.LATA5 = 0;                   // LED消灯
    BANK_0

PLS_END4                    ;   }


    ;------------------------
    ; 割り込み後処理
    ;------------------------

INIT_END                    ; }

    SWAPF   fSAVE_S,W       ; STATUS = fSAVE_S;                     // 保存した STATUS を復元する
    MOVWF   STATUS
    SWAPF   fSAVE_W,F       ; W = fSAVE_W;                          // 保存した W を復元する
    SWAPF   fSAVE_W,W

    RETFIE                  ; return;                               // 割り込み可として復帰


;==================================
; 初期化処理
;==================================

INIT

    ;-------------------
    ; PICレジスタ初期化
    ;-------------------

    ;---- 動作クロック設定

    BANK_1
    MOVLW   B'01101000'     ; OSCCON = B'01101000';
    MOVWF   OSCCON
                            ;       // bit7   = 0       4倍PLL無効
                            ;       // bit6-3 = 1101    内部クロック 4MHz
                            ;       // bit2   = 0       （未使用）
                            ;       // bit1-0 = 00      クロックはFOSCに従う


    ;---- 入出力設定

    BANK_2
    CLRF   LATA             ; LATA = 0;                             // PORTAをクリア

    BANK_1
    MOVLW   B'00011011'     ; TRISA = B'00011011';
    MOVWF   TRISA
                            ;       // bit7-6 = 00      （未使用）
                            ;       // bit5   = 0       RA5 出力（LED）
                            ;       // bit4   = 1       RA4 入力（INT検出/スイッチ)
                            ;       // bit3   = 1       RA3 入力（車速パルス）ICSP
                            ;       // bit2   = 0       RA2 出力（速度ダウンスイッチ）
                            ;       // bit1   = 1       RA1 入力（未使用）ICSP_CLK
                            ;       // bit0   = 1       RA0 入力（未使用）ICSP_DAT


    ;---- ピン機能選択

    BANK_2
    CLRF   APFCON           ; APFCON = 0;

                            ;       // bit7 = 0        RA1をRX/DTにする
                            ;       // bit6 = 0        SDOをRA0とする
                            ;       // bit5 = 0        ~SSをRA3とする
                            ;       // bit4 = 0        （未使用）
                            ;       // bit3 = 0        T1GをRA4とする
                            ;       // bit2 = 0        TX/CKをRA0とする
                            ;       // bit1 = 0        P1BをRA0とする
                            ;       // bit0 = 0        CCP1/PA1をRA2とする


    ;---- アナログ入力設定

    BANK_3
    MOVLW   B'00000000'     ; ANSELA = 0;
    MOVWF   ANSELA
                            ;       // bit7-5 = 000     （未使用）
                            ;       // bit4   = 0       RA4のアナログ入力を無効
                            ;       // bit3   = 0       （未使用）
                            ;       // bit2-0 = 000     RA2-RA0のアナログ入力を無効


    ;---- ＰＷＭの設定

    BANK_0
	MOVLW	D'255'          ; PR2 = 255;                            // PWM周期
	MOVWF	PR2

    MOVLW   B'00000111'     ; T2CON = B'00000111';
    MOVWF   T2CON
                            ;       // bit7   = 0       （未使用）
                            ;       // bit6-3 = 0000    ポストスケーラ(T2OUTPS 1:1)
                            ;       // bit2   = 1       タイマー2をON
                            ;       // bit1-0 = 11      プリスケーラ(T2CKPS 1:64)


	;---- タイマー２初期化

    BANK_5
	CLRF	CCPR1L          ; CCPR1 = 0;
	CLRF	CCPR1H

    MOVLW   B'00000000'     ; CCP1CON = B'00000000';
    MOVWF   CCP1CON
                            ;       // bit7-6 = 00      P1A(5ピン)をPWMとして使用
                            ;       // bit5-4 = 00      DC1B デューティーサイクルの下位2ビット
                            ;       // bit3-0 = 0000    PWM off

	CLRF	TMR2            ; TMR2 = 0;


    ;---- タイマー０初期化

    BANK_1
    
    BCF     OPTION_REG,TMR0CS
                            ; OPTION_REG.TMR0CS = 0             // タイマー０を内部命令サイクルクロックを元にする

    BANK_0
    MOVLW   C_TMR0init      ; TMR0 = C_TMR0init;                // タイマー０カウンタ初期化
    MOVWF   TMR0


    ;------------
    ; 変数初期化
    ;------------

    ;---- 車速関連

    BANK_0

    MOVLW   C_RRP           ; for( i=0; i < C_RRP;++ ) {            // 車速パルス配列のインデックスを初期化
    MOVWF   fRRPIDX

    CLRF    FSR0H           ;                                       // 間接データアドレスを車速パルス配列の先頭へ
    MOVLW   fSPTCA0_L
    MOVWF   FSR0L

VINIT_LOOP

    MOVLW   D'0'            ;   fSPTC[ i ] = 0x800;                 // 車速パルス配列(16bit)を初期化
    MOVWI   FSR0++
    MOVLW   D'8'
    MOVWI   FSR0++
    DECFSZ  fRRPIDX
    GOTO    VINIT_LOOP      ; }


    CLRF    fSPTC_L         ; SPTC = 0;                             // 車速パルスカウンタを初期化
    CLRF    fSPTC_H
    CLRF    fSPTCT_L
    MOVLW   C_RRP           ; fRRPIDX = C_RRP                       // 車速パルス配列のインデックスを初期化
    MOVWF   fRRPIDX
    MOVWF   fSPTCT_H        ; SPTCT = C_RRP * 0x800;                // 車速パルス合計を初期化
    LSLF    fSPTCT_H
    LSLF    fSPTCT_H
    LSLF    fSPTCT_H

    BCF     fFLG,F_SPOF     ; fFLG.F_SPOF = 0;                      // 前回計測車速を5.5Km/h以上に初期化
    BSF     fFLG,F_SPFLG    ; fFLG.F_SPFLG = 1;                     // 車速状態を 高速 に初期化

    ;---- ワイパー関連

    BCF     fFLG,F_WSET     ; fFLG.F_WSET = 0;                      // ワイパー間隔測定中に初期化
    BCF     fFLG,F_WEGD     ; fFLG.F_WEGD = 0;                      // 拭き取り開始フラグを停止中に初期化
    BCF     fFLG,F_WSTP     ; fFLG.F_WSTP = 0;                      // 拭き取り終了フラグを停止中に初期化
    BCF     fFLG,F_WSAV     ; fFLG.F_WSAV = 0;                      // 前回拭き取り状態を待機に初期化
    BCF     fFLG,F_WPOW     ; fFLG.F_WPOW = 0;                      // ワイパーレバー位置をOFFに初期化

    CLRF    fWA             ; fWA = 0;                              // ワイパー低速・高速割合変数を 0% とする
    CLRF    fWINT           ; fWINT = 0;                            // ワイパー間隔を 0 とする
    CLRF    fWCNT           ; fWCNT = 0;                            // 拭き取り動作チェックカウンタを初期化


    ;---- 設定関連

    BSF     fFLG,F_SET      ; fFLG.F_SET = 1;                       // 設定中に初期化

    CLRF    fLED_ADR        ; fLED_ADR = 0;                         // LEDを消灯パターンとする
    MOVLW   0x38            ; fLED_ADR0 = 0x38;                     // LED予備パターン先頭アドレス
    MOVWF   fLED_ADR0       ;                                       //    （パターン0以外としておく）
    MOVLW   0x1
    MOVWF   fLED_TCNT       ; fLED_TCNT = 1;                        // LED点灯用TMR0カウンタを1に初期化
    MOVWF   fLED_SCNT       ; fLED_SCNT = 1;                        // LED点灯用カウンタを1に初期化


    ;--------------
    ; 割り込み設定
    ;--------------

    BANK_7
    BSF     IOCAN,IOCAN3    ; IOCAP.IOCAP3 = 1;                     // RA3のみ立ち下がり割り込み ON
                            ;                                       // (車速パルス立ち上がり）

    BANK_0
    BSF     INTCON,TMR0IE   ; INTCON.TMR0IE = 1;                    // タイマー０割込み ON
    BSF     INTCON,GIE      ; INTCON.GIE = 1;                       // グローバル割込み ON


;==================================
; 設定処理
;==================================

    ;---- 設定読み込み

    MOVLW   C_EEADR_SET
    BCF     INTCON,GIE      ; INTCON.GIE = 0;                       // グローバル割込み OFF

    BANK_3
    MOVWF   EEADRL          ; fSET = EEPROM[ C_EEADR_SET ];         // 設定を読み込む
    CALL    READ_EE
    BANK_0
    MOVWF   fSET

    MOVLW   C_EEADR_FNC     ; fFNC = EEPROM[ C_EEADR_FNC ];         // 減速パターン番号を読み込む
    BANK_3
    MOVWF   EEADRL
    CALL    READ_EE

    BSF     INTCON,GIE      ; INTCON.GIE = 1;                       // グローバル割込み ON

    BANK_0
    MOVWF   fFNC


    ;---- 設定変更処理

    CALL    CHK_SW          ; if ( CHK_SW() == 1 ) {
    BTFSS   STATUS,C
    GOTO    MAIN
                            ;   // スイッチが押されている場合

    MOVLW   0x08            ;   fLED_ADR = 0x08;                    // LEDを点灯パターンにする
    MOVWF   fLED_ADR

    MOVLW   0xA7            ;   for( fCHK_LCNT = 0xA7; fCHK_LCNT > 0; fCHK_LCNT-- ) {
    MOVWF   fCHK_LCNT

SET_L1
    CALL    CHK_SW          ;     if ( CHK_SW() == 0 ) break;       // スイッチが離された場合ループを出る
    BTFSS   STATUS,C
    GOTO    SET_J9

    DECFSZ  fCHK_LCNT
    GOTO    SET_L1          ;   }


                            ;   if ( fCHK_LCNT == 0 ) {

                            ;     // 5秒以上押されていた場合

    ;----- 機能有効無効変更

    MOVLW   0x00            ;     fLED_ADR = 0x00;                  // LED消灯パターンにする
    MOVWF   fLED_ADR

SET_L2
    CALL    CHK_SW          ;     while ( CHK_SW() == 1 );          // スイッチが離されるのを待つ
    BTFSC   STATUS,C
    GOTO    SET_L2

SET_L3                      ;     while(1) {
    BTFSC   fSET,F_SET_DISF ;       if ( fSET.F_SET_DISF == 0 ) {
    GOTO    SET_J1
                            ;         // 機能有効の場合

    MOVLW   0x10            ;         fLED_ADR = 0x10;              // LEDを早い点滅パターンにする
    GOTO    SET_J2
                            ;       } else {

SET_J1                      ;         // 機能無効の場合

    MOVLW   0x18            ;         fLED_ADR = 0x18;              // LEDを遅い点滅パターンにする

SET_J2                      ;       }
    MOVWF   fLED_ADR

SET_L4
    CALL    CHK_SW          ;       while ( CHK_SW() == 0 );        // スイッチが押されるのを待つ
    BTFSS   STATUS,C
    GOTO    SET_L4

    MOVLW   0x63            ;       for( fCHK_LCNT = 0x63; fCHK_LCNT > 0; fCHK_LCNT-- ) {
    MOVWF   fCHK_LCNT

SET_L5
    CALL    CHK_SW          ;         if ( CHK_SW() == 0 ) break;   // スイッチが離された場合ループを出る
    BTFSS   STATUS,C
    GOTO    SET_J3

    DECFSZ  fCHK_LCNT
    GOTO    SET_L5          ;       }

                            ;       if ( fCHK_LCNT > 0 ) {
    GOTO    SET_J7

SET_J3                      ;           // スイッチが離された場合

    MOVLW   M_SET_DISF      ;           fSET = fSET xor M_SET_DISF;   // 機能有無反転
    XORWF   fSET,f
                            ;         }
    GOTO    SET_L3          ;     }

SET_J9

    MOVLW   0x43            ;   } else if ( fCHK_LCNT >= 0x43 )  {
    SUBWF   fCHK_LCNT,w     ;
    BTFSC   STATUS,C
    GOTO    MAIN

                            ;     // 3秒以上、5秒未満で離された場合
    ;----- 機能変更
SET_L6

                            ;     while(1) {

                            ;       do {
    MOVF   fFNC,w           ;         w = C_EEADR_FPT + fFNC;       // 機能データ EEPROM アドレス算出
    ADDLW  C_EEADR_FPT

    BCF     INTCON,GIE      ;         INTCON.GIE = 0;               // グローバル割込み OFF
    BANK_3
    MOVWF   EEADRL          ;         w = EEPROM[ w ];              // LED発光パターンアドレス読み込み
    CALL    READ_EE
    BANK_3
    MOVWF   EEADRL
    BSF     INTCON,GIE      ;         INTCON.GIE = 1;               // グローバル割込み ON
    BANK_0
    INCFSZ  WREG,w          ;         if ( w != 255 ) break;
    GOTO    SET_J8
    CLRF    fFNC            ;         fFNC = 0;
                            ;       }
    GOTO    SET_L6

SET_J8
    DECF    WREG,w          ;       fLED_ADR = w;
    MOVWF   fLED_ADR

SET_L7
    CALL    CHK_SW          ;       while ( CHK_SW() == 0 );        // スイッチが押されるのを待つ
    BTFSS   STATUS,C
    GOTO    SET_L7

    MOVLW   0x63            ;       for( fCHK_LCNT = 0x63; fCHK_LCNT > 0; fCHK_LCNT-- ) {
    MOVWF   fCHK_LCNT

SET_L8
    CALL    CHK_SW          ;         if ( CHK_SW() == 0 ) break;   // スイッチが離された場合ループを出る
    BTFSS   STATUS,C
    GOTO    SET_J6

    DECFSZ  fCHK_LCNT
    GOTO    SET_L8          ;       }

                            ;       if ( fCHK_LCNT == 0 ) break;
    GOTO    SET_J7

SET_J6                      ;       // スイッチが離された場合

    INCF    fFNC,f          ;       fFNC++;                         // 減速パターン番号インクリメント

    GOTO    SET_L6          ;     }

                            ;   }

                            ;   if ( fCHK_LCNT >= 0x43 ) {

                            ;     // 3秒以上でスイッチが離された場合
    ;----- EEPROM書込み

SET_J7

    MOVLW   C_EEADR_SET
    BCF     INTCON,GIE      ;     INTCON.GIE = 0;                   // グローバル割込み OFF
    BANK_3
    MOVWF   EEADRL          ;     EEPROM[ C_EEADR_SET ] = fSET;     // 設定をEEPROMへ保存
    BANK_0
    MOVF    fSET,w
    CALL    WRITE_EE

    MOVLW   C_EEADR_FNC
    BANK_3
    MOVWF   EEADRL          ;     EEPROM[ C_EEADR_FNC ] = fFNC;     // をEEPROMへ保存
    BANK_0
    MOVF    fFNC,w
    CALL    WRITE_EE

    BANK_2
    BSF     LATA,LATA5      ;     LATA5 = 1;                        // LED点灯

    ;---- 設定完了

SET_L9
    CALL    CHK_SW          ;     if ( CHK_SW() == 0 ) break;       // スイッチが離された場合ループを出る
    BTFSC   STATUS,C
    GOTO    SET_L9

    BSF     INTCON,GIE      ;     INTCON.GIE = 1;                   // グローバル割込み ON


                            ;   }
                            ; }

;==================================
; 主処理
;==================================


MAIN

    BANK_0
    BCF     fFLG,F_SET      ; fFLG.F_SET = 0;                       // 通常動作に設定
    BANK_2
    BCF     LATA,LATA5      ; LATA5 = 0;                            // LED消灯

    ;---- 機能停止判定

    BANK_0
    BTFSS   fSET,F_SET_DISF ; if ( fSET.F_SET_DISF == 1) { 
    GOTO    MAIN_J1
                            ;   // 機能停止の場合

    BCF     INTCON,GIE      ;   INTCON.GIE = 0;                     // グローバル割込み OFF

MAIN_L1

    SLEEP                   ;   while(1) sleep;                     // 停止
    GOTO    MAIN_L1

                            ; }

    ;---- 割込み設定

MAIN_J1


    CLRF    IOCAF
    BSF     INTCON,IOCIE    ; ITCON.IOCIE = 1;                      // 状態変化割り込みを ON
    BSF     INTCON,GIE      ; INTCON.GIE = 1;                       // グローバル割込み ON

    BCF     LATA,LATA5      ; LATA5 = 0;                            // LED消灯

    ;---- 主処理ループ

MLOOP
                            ; while(1) {
    BANK_0

    BTFSS   fFLG,F_WSTP     ;   if ( fFLG.F_WSTP == 1 ) {
    GOTO    M_J1
                            ;     // ワイパー拭き取り終了の場合

    BCF     fFLG,F_WSTP     ;     fFLG.F_WSTP = 0;                    // 拭き取り終了フラグ初期化
    BTFSC   fFLG,F_SPFLG    ;     if ( fFLG.F_SPFLG == 0 ) {
    GOTO    M_J1
                            ;       // 車速が低速の場合
   BANK_5
    MOVLW   0x0C            ;       CCP1CN = 0x0C;                    // PWMをONにする
    MOVWF   CCP1CON         ;                                         // CCP1M PWMモード: P1A,P1B active-high

    BANK_2
    BSF     LATA,LATA5      ;       LATA.LATA5 = 1;                   // LEDを点灯する（減速処理中点灯とする）
    BANK_0

                            ;     }
                            ;   }
M_J1

    ;---- スピード判定

    ; fFLG.F_SPFLG=0、かつ、車速が20Km/hより早い場合、fFLG.F_SPFLG=1（ワイパー速度通常）
    ; fFLG.F_SPFLG=1、かつ、車速が15Km/h以下の場合、fFLG.F_SPFLG=0（ワイパー速度半分）

    BANK_0

    BTFSS   fFLG,F_SPFLG    ;   if( fFLG.F_SPFLG == 1 ) {
    GOTO    M_J4
                            ;     // 車速が高速の場合

    MOVF    fSPTCT_H,w      ;     if( fSPTCT_H == 5 ) {
    SUBLW   0x05
    BTFSS   STATUS,Z
    GOTO    M_J2

    MOVLW   0xE2            ;       if( fSPTCT_L < 0xE2 ) continue;
    SUBWF   fSPTCT_L,w
    BTFSS   STATUS,C
    GOTO    MLOOP
    GOTO    M_J3

M_J2                        ;     } else {
    BTFSC   STATUS,C        ;       if( fSPTCT_H < 5 ) continue;
    GOTO    MLOOP
                            ;     }

M_J3                        ;     // 車速が低速になった場合

    BCF     fFLG,F_SPFLG    ;     fFLG.F_SPFLG = 0;                 // 車速状態を 低速 にする

    CLRF    fWA             ;     fWA = 0x00;                       // 減速割合を 0% にする
    BANK_5                  ;     CCPR1L = 0x00;
    CLRF    CCPR1L

    GOTO    MLOOP           ;     continue;

                            ;   }
M_J4
                            ;   // 車速が低速の場合

    MOVF    fSPTCT_H,w      ;   if( fSPTCT <= 0x46A ) {
    SUBLW   0x04
    BTFSC   STATUS,Z
    GOTO    M_J5

    BTFSS   STATUS,C
    GOTO    M_J6

M_J5
    MOVF    fSPTCT_L,w
    SUBLW   0x6A
    BTFSS   STATUS,C
    GOTO    M_J6

                            ;     // 車速が高速になった場合

    BSF     fFLG,F_SPFLG    ;     fFLG.F_SPFLG = 1              // 車速状態を 高速 にする

    BANK_5
    CLRF    CCP1CON         ;     CCP1CON = 0;                  // ＰＷＭをOFFにする
    BANK_2
    BCF     LATA,LATA2      ;     LATA.LATA2 = 0;               // フォトモスリレーOFF

    BANK_2
    BCF     LATA,LATA5      ;     LATA.LAT5 = 0;                // LEDを消灯する
    BANK_0

    GOTO    MLOOP           ;     continue;

                            ;   }
M_J6

    BTFSS   fFLG,F_WSET     ;   if( fFLG.F_WSET == 1 ) {
    GOTO    MLOOP
                            ;     // ワイパー間隔測定終了

    BCF     fFLG,F_WSET     ;     fFLG.F_WSET = 0;              // ワイパー間隔測定中に変更

    CALL    CAL_WA2         ;     fWA = CAL_WA ( fWA, fWINT,fFNC );  // 減速割合を算出

    MOVF    fWA,w           ;     CCPR1L = fWA;                 // 算出値をPWMのON時間割合に設定
    BANK_5
    MOVWF    CCPR1L
                            ;   }
                            ; }
    GOTO    MLOOP


;==================================
; サブルーチン
;==================================

;----------------------------------
; SWが押されているか判定（30msec）
;----------------------------------
; 返却値： C=0...押されていない、C=1...押されている
; 破壊：   W,STATUS

CHK_SW

    BANK_0

    CLRF    fCNT_H          ; fCNT = 0;
    CLRF    fCNT_L

    MOVLW   0x04            ; for( fIDX = 1200; fIDX > 0; fIDX-- ) {
    MOVWF   fIDX_H
    MOVLW   0xB0
    MOVWF   fIDX_L

SW_L1

    BTFSC   PORTA,RA4       ;   if( RA4 == 0 ) {
    GOTO    SW_J0
                            ;     // SWがONになっている場合
    INCFSZ  fCNT_L,f        ;     fCNT++;
    GOTO SW_J1

    INCF    fCNT_H,f
    GOTO SW_J2

SW_J0
    GOTO    SW_J1           ;     // 2サイクル消費

SW_J1
    GOTO    SW_J2           ;     // 2サイクル消費

SW_J2
                            ;   }

    MOVLW   0x03            ;   // 13サイクル消費
    MOVWF   fCNT

SW_L2
    DECFSZ  fCNT,f
    GOTO    SW_L2

    DECFSZ  fIDX_L,f        ; }
    GOTO    SW_J3

    DECFSZ  fIDX_H,f
    GOTO    SW_L1

    GOTO    SW_END

SW_J3
    GOTO    SW_L1

SW_END
    MOVLW   0x03            ; return ( fCNT >= 768 );
    SUBWF   fCNT_H,w
    RETURN


;----------------------------------
; EEPROM読み出し
;----------------------------------
; パラメータ： EEADRLレジスタにアドレス
; 返却値：     Wレジスタに読みこみデータ
; 注意事項:    CALL処理の前にグローバル割込みを OFF としておくこと

READ_EE

    BANK_3
    BCF     EECON1,CFGS     ; EECON1.CFGS = 0;                      // EEPROMアクセスとする
    BCF     EECON1,EEPGD    ; EECON1.EEPGD = 0;
    BSF     EECON1,RD       ; EECON1.RD = 1;                        // EEPROM読み出し開始
    MOVF    EEDATL,w        ; w = EEDATL;                           // wレジスタへEEPROMデータ読み出し

    BANK_0
    RETURN                  ; return;


;----------------------------------
; EEPROM書込み
;----------------------------------
; パラメータ： EEADRLレジスタにアドレス
;              Wレジスタに書込みデータ
; 注意事項:    CALL処理の前にグローバル割込みを OFF としておくこと

WRITE_EE

    BANK_3
    MOVWF   EEDATL          ; EEDATL = w;                           // EEPROM書き出しデータを設定
    BCF     EECON1,CFGS     ; EECON1.CFGS = 0;                      // EEPROMアクセスとする
    BCF     EECON1,EEPGD    ; EECON1.EEPGD = 0;
    BSF     EECON1,WREN     ; EECON1.WREN = 1;                      // EEPROM書込み許可

    MOVLW   0x55            ; EECON2 = 0x55;                        // EEPROM書込み解除
    MOVWF   EECON2
    MOVLW   0xAA            ; EECON2 = 0xAA;
    MOVWF   EECON2
    BSF     EECON1,WR       ; EECON1.WR = 1;                        // EEPROM書込み開始
    BCF     EECON1,WREN     ; EECON1.WREN = 0;                      // EEPROM書込み禁止
    BTFSC   EECON1,WR       ; while ( EECON1.WR == 1 );             // EEPROM書込み完了待ち
    GOTO    $-2

    BANK_0
    RETURN


;----------------------------------
; 掛け算 8bit x 8bit -> 16bit
;----------------------------------
; A(8ビット)×B(8ビット) -> C(16ビット)
; パラメータ: fA0 に A の値
;             fB0 に B の値
; 返却値:     fC0 と fC1 に C の値

CAL_MUL

    BANK_0

    CLRF    fC1             ; C = 0:
    CLRF    fC0

    MOVLW   0x8             ; for( fCNT = 8 ; fCNT<0 ;fCNT--) {
    MOVWF   fCNT

MUL_L1

    LSLF    fC0,f           ;   C = C << 1;
    RLF     fC1,f

    LSLF    fA0,f           ;   A = A << 1;
    BTFSS   STATUS,C        ;   if ( A 桁あふれ ) {
    GOTO    MUL_J1

    MOVF    fB0,w           ;     C = C + B;
    ADDWF   fC0,f
    MOVLW   0x0
    ADDWFC  fC1,f
                            ;   }
MUL_J1

    DECFSZ  fCNT,f          ; }
    GOTO    MUL_L1

    RETURN                  ; return C;


;----------------------------------
; 掛け算 16bit x 16bit -> 32bit
;----------------------------------
; A(16ビット)×B(16ビット) -> C(32ビット)
; パラメータ: fA1 と fA0 に A の値
;             fB1 と fB0 に B の値
; 返却値:     fC3 ... fC0 に C の値

CAL_MUL16

    BANK_0

    CLRF    fC3             ; C = 0;
    CLRF    fC2
    CLRF    fC1
    CLRF    fC0

    MOVLW   0x10            ; for( fCNT = 16 ; fCNT<0 ;fCNT--) {
    MOVWF   fCNT

MUL16_L1

    LSLF    fC0,f           ;   C = C << 1;
    RLF     fC1,f
    RLF     fC2,f
    RLF     fC3,f

    LSLF    fA0,f           ;   A = A << 1;
    RLF     fA1,f
    BTFSS   STATUS,C        ;   if ( A 桁あふれ ) {
    GOTO    MUL16_J1

    MOVF    fB0,w           ;     C = C + B;
    ADDWF   fC0,f
    MOVF    fB1,w
    ADDWFC  fC1,f
    MOVLW   0x00
    ADDWFC  fC2,f
    ADDWFC  fC3,f

MUL16_J1                    ;  }

    DECFSZ  fCNT,f          ; }
    GOTO    MUL16_L1

    RETURN                  ; return C;


;------------------------------
; 割り算 32bit / 32bit -> 32bit
;------------------------------
; A(16ビット)×B(16ビット) -> C(32ビット)
; パラメータ: fA3 ... fA0 に A の値
;             fB3 ... fB0 に B の値
; 返却値:     fC3 ... fC0 に C の値

    BANK_0

CAL_DIV

    CLRF    fA7             ; A' = 0;
    CLRF    fA6
    CLRF    fA5
    CLRF    fA4

    MOVLW   0x20            ; for( fCNT = 32; fCNT>0; i-- ) {
    MOVWF   fCNT

DIV_L1

    RLF     fA0,f           ;   A = A << 1;
    RLF     fA1,f
    RLF     fA2,f
    RLF     fA3,f
    RLF     fA4,f           ;   A' = A' << 1 + CY;
    RLF     fA5,f
    RLF     fA6,f
    RLF     fA7,f

    MOVF    fB0,w           ;   A' = A' - B;
    SUBWF   fA4,f
    MOVF    fB1,w
    SUBWFB  fA5,f
    MOVF    fB2,w
    SUBWFB  fA6,f
    MOVF    fB3,w
    SUBWFB  fA7,f

    BTFSC   STATUS,C        ;   if ( A' >= 0 ) {
                            ;     CY = 1;
    GOTO    DIV_J1          ;   } else {

    MOVF    fB0,w           ;     A' = A' + fB;
    ADDWF   fA4,f
    MOVF    fB1,w
    ADDWFC  fA5,f
    MOVF    fB2,w
    ADDWFC  fA6,f
    MOVF    fB3,w
    ADDWFC  fA7,f

    BCF     STATUS,C        ;     CY = 0;

DIV_J1                      ;   }

    RLF     fC0,f           ;   fC = fC << 1 + CY
    RLF     fC1,f
    RLF     fC2,f
    RLF     fC3,f

    DECFSZ  fCNT,f          ; }
    GOTO    DIV_L1

    RETURN                  ; return C;



;------------------------------
; 減速割合算出
;------------------------------
; パラメータ: fWA       現在の減速割合(β = fWA / 256)
;             fWINT     実測拭き取り間隔(t = fWINT * 128msec)
;             fFNC      拭き取り間隔選択番号
; 返却値:     fWA       新減速割合

CAL_WA2

    BANK_0
                            ; // D = t - 611
	CLRF	fA0             ; A = fWINT * 128;
	MOVF	fWINT,w
	MOVWF	fA1
	LSRF	fA1,f
	RRF		fA0

    MOVLW   0x63            ; D = A - 611;
    SUBWF   fA0,w
    MOVWF   fD0
    MOVLW   0x02
    SUBWFB  fA1,w

    BTFSC   STATUS,C        ; if( D < 0 ){
    GOTO    WA2_J1

    CLRF    fWA             ;   fWA = 0;
    RETURN                  ;   return;
                            ; }
WA2_J1

    MOVWF   fD1
                            ; // A = (1.042725 - β)*256*16
    SWAPF   fWA,w           ; B = fWA * 16;
    ANDLW   0xF0
    MOVWF   fB0
    SWAPF   fWA,w
    ANDLW   0x0F
    MOVWF   fB1

    MOVLW   0xAF            ; A = 4271;
    MOVWF   fA0
    MOVLW   0x10
    MOVWF   fA1

    MOVF    fB0,w           ; A = A - B;
    SUBWF   fA0,f
    MOVF    fB1,w
    SUBWFB  fA1,f
                            ; // C = (t - 611) * (1.042725 - β)*256*16
    MOVF    fD0,w           ; B = D;
    MOVWF   fB0
    MOVF    fD1,w
    MOVWF   fB1

    CALL    CAL_MUL16       ; C = A * B;

                            ; // D = C
    MOVF    fC0,w           ; D = C;
    MOVWF   fD0
    MOVF    fC1,w
    MOVWF   fD1
    MOVF    fC2,w
    MOVWF   fD2
    MOVF    fC3,w
    MOVWF   fD3

                            ; // 機能別に目標時間設定

    MOVF    fFNC,w          ; switch(fFNC) {

    BTFSS   STATUS,Z        ;   case 0:        // ３倍の拭き取り間隔
    GOTO    WA2_J2

                            ;     // 通常の拭き取り間隔時間を算出
                            ;     // C = (t - 611) * (1.042725 - β) + 611
    LSRF    fC3             ;     C = C / 256 / 16 + 611;
    RRF     fC2
    RRF     fC1
    LSRF    fC3
    RRF     fC2
    RRF     fC1
    LSRF    fC3
    RRF     fC2
    RRF     fC1
    LSRF    fC3
    RRF     fC2
    RRF     fC1

    MOVLW   0x63
    ADDWFC  fC1,w
    MOVWF   fC0
    MOVLW   0x02
    ADDWFC  fC2,w
    MOVWF   fC1
    CLRF    fC2

                            ;     // ３倍の拭き取り間隔時間を算出
                            ;     // B = C * 3
    LSLF    fC0,w           ;     B = C * 3
    MOVWF   fB0
    RLF     fC1,w
    MOVWF   fB1
    RLF     fC2,w
    MOVWF   fB2

    MOVF    fC0,w
    ADDWF   fB0,f
    MOVF    fC1,w
    ADDWFC  fB1,f
    MOVF    fC2,w
    ADDWFC  fB2,f

    GOTO    WA2_J3          ;     break;

WA2_J2                      ;   case 1:        // 30秒の拭き取り間隔

    DECF    WREG,w
    BTFSS   STATUS,Z
    GOTO    WA2_J4

    MOVLW   0x30            ;     B = 30 * 10000;
    MOVWF   fB0
    MOVLW   0x75
    MOVWF   fB1

    GOTO    WA2_J5          ;     break;

WA2_J4                      ;   case 2;        // 10秒の拭き取り間隔

    MOVLW   0x10            ;     B = 10 * 10000;
    MOVWF   fB0
    MOVLW   0x27
    MOVWF   fB1
                            ;    break;
WA2_J5

    CLRF    fB2

WA2_J3

    CLRF    fB3
                            ; }

                            ; // 目標停止時間の算出
    MOVLW   0x63            ; B = B - 611;
    SUBWF   fB0,f
    MOVLW   0x02
    SUBWFB  fB1,f
    BTFSS   STATUS,C        ; if ( B <= 0 ) {
    GOTO    WA2_J7

    BTFSS   STATUS,Z
    GOTO    WA2_J6

    MOVF    fB0,f
    BTFSS   STATUS,Z
    GOTO    WA2_J6

WA2_J7                      ;   // 目標停止時間がマイナスになる場合

    CLRF    fWA             ;   fWA = 0;
    RETURN                  ;   return;
                            ; }
WA2_J6

                            ; // A = 4271 - (t - 611) * (1.042725 - β)*256*16 / (t' - 611)
    MOVF    fD0,w           ; A = D;
    MOVWF   fA0
    MOVF    fD1,w
    MOVWF   fA1
    MOVF    fD2,w
    MOVWF   fA2
    MOVF    fD3,w
    MOVWF   fA3

    CALL    CAL_DIV         ; C = A / B
                            ; A = 10AFh - C
    MOVF    fC3,f           ; if ( A < 0 ) {
    BTFSS   STATUS,Z        ;   // 新割合がマイナスになる場合
    GOTO    WA2_J9

    MOVF    fC2,f
    BTFSS   STATUS,Z
    GOTO    WA2_J9

    MOVF    fC0,w
    SUBLW   0xAF
    MOVWF   fA0

    MOVLW   0x10
    MOVWF   fA1
    MOVF    fC1,w
    SUBWFB  fA1,f
    BTFSC   STATUS,C
    GOTO    WA2_J10

WA2_J9

    CLRF    fWA             ;   fWA = 0;
    RETURN                  ;   return;
                            ; }
WA2_J10

    LSRF    fA1             ; A = A / 16;
    RRF     fA0
    LSRF    fA1
    RRF     fA0
    LSRF    fA1
    RRF     fA0
    LSRF    fA1
    RRF     fA0

    MOVLW   0x00
    ADDWFC  fA0,f
    ADDWFC  fA1,f

    BTFSC   STATUS,Z        ;if ( A > 255 ) {
    GOTO    WA2_J11         ;   // 新割合が 1 以上の場合

    MOVLW   0xFF            ;   fWA = 0xFF;
    MOVWF   fWA             ;   return;
    RETURN
                            ;}
WA2_J11

    MOVF    fA0,w           ; fWA = A;
    MOVWF   fWA
    RETURN                  ; return;


;--------------------------------
; デバッグ
;--------------------------------
;Wレジスタの内容をRA5に出力する
;パラメータ: Wレジスタ

DEBUG_W


    BANK_0

    MOVWF   fDEB_W

    MOVLW   0x8
    MOVWF   fDEB_CNT

    BANK_2
                            ; // 短いパルス

    BCF     LATA,LATA5      ; LATA.LATA5 = 0;
    BSF     LATA,LATA5      ; LATA.LATA5 = 1;
    BCF     LATA,LATA5      ; LATA.LATA5 = 0;

DEBUG_L1
                            ; for( fDEB_CNT = 7; fDEB_CNT >= 0; fDEB_CNT--) {
    BANK_0

    RLF     fDEB_W,f        ;   if( fDEB_W の fDEV_CNTビット == 1 )  {

    BANK_2

    BTFSS   STATUS,C
    GOTO    DEBUG_J1

    BSF     LATA,LATA5      ;     LATA.LATA5 = 1;
    BSF     LATA,LATA5      ;     // 長い High
    BSF     LATA,LATA5
    BSF     LATA,LATA5
    BSF     LATA,LATA5
    BSF     LATA,LATA5

    GOTO    DEBUG_J2
                            ;   } else {
DEBUG_J1

    BCF     LATA,LATA5      ;     LATA.LATA5 = 0;
    BCF     LATA,LATA5      ;     // 長い Low
    BCF     LATA,LATA5
    BCF     LATA,LATA5
    BCF     LATA,LATA5
    BCF     LATA,LATA5
                            ;   }

DEBUG_J2                    ;   // 短い LOW

    BCF     LATA,LATA5      ;   LATA.LATA5 = 0;
    BSF     LATA,LATA5
    BCF     LATA,LATA5

    BANK_0

    DECFSZ  fDEB_CNT,f      ; }
    GOTO    DEBUG_L1

    RETURN                  ; return;


;========================
; EEPROM
;========================

    ;----- LED発光パターン

    ORG     0xF000

    ;       データ終了は0xFF、単位:10msec
    ;       1-------------2-------------3-------------4-------------
    ;       ON     OFF    ON     OFF    ON     OFF    ON     OFF
    DE      D'0'  ,D'254',0xFF  ,D'0'  ,D'0'  ,D'0'  ,D'0'  ,D'0'   ; 00  パターン0 消灯
    DE      D'254',0xFF  ,D'0'  ,D'0'  ,D'0'  ,D'0'  ,D'0'  ,D'0'   ; 08  パターン1 点灯
    DE      D'20' ,D'20' ,0xFF  ,D'0'  ,D'0'  ,D'0'  ,D'0'  ,D'0'   ; 10  パターン2 早い点滅
    DE      D'40' ,D'40' ,0xFF  ,D'0'  ,D'0'  ,D'0'  ,D'0'  ,D'0'   ; 18  パターン3 遅い点滅
    DE      D'0'  ,D'120',D'5'  ,D'40' ,D'5'  ,0xFF  ,D'0'  ,D'0'   ; 20  パターン4 2回点滅繰り返し
    DE      D'0'  ,D'120',D'5'  ,D'40' ,D'5'  ,D'40' ,D'5'  ,0xFF   ; 28  パターン5 3回点滅繰り返し
    DE      D'0'  ,D'120',D'5'  ,0xFF  ,D'0'  ,D'0'  ,D'0'  ,D'0'   ; 30  パターン4 1回点滅繰り返し
    DE      D'0'  ,D'254',0xFF  ,D'0'  ,D'0'  ,D'0'  ,D'0'  ,D'0'   ; 38  パターン7 （予備）


    ;----- 各種設定

    ORG     0xF040

    DE      D'00'                                                   ; bit7 … 機能無効フラグ（0...有効、1...無効）
    DE      D'00'                                                   ; 減速パターン番号


    ;----- 機能別LED発光パターン番号

    ORG     0xF050

    ;       LED   
    ;       発光  
    ;       ----- 
    DE      0x20    ; パンターン0 通常の３倍の拭き取り間隔
    DE      0x28    ; パンターン1 約10秒間隔
    DE      0x30    ; パンターン2 最長間隔の拭き取り間隔（約25秒?33秒）
    DE      0xFF    ; データ終了


;========================

    END
