;******************************************************
; サーボセンター      << PIC12F675 >> Nakasige-Tosikazu
; Version 1.01
;
; 2007/03/13
;******************************************************
;======================================================
;;発振器を４MHz
;- input -
#DEFINE     P_BATTERY   GPIO,0      ;GP0 = 電圧入力
;- output -
#DEFINE     P_DRIVE     GPIO,4      ;GP4 = サーボドライブ
;                       
    LIST        P=PIC12F675
    INCLUDE     "P12F675.INC"
;
CB = _CPD_OFF               ;データEEPROMもプログラム・メモリも
CB &= _CP_OFF               ;コード・プロテクトしない
CB &= _BODEN_ON             ;ブラウンアウト・リセットを使う
CB &= _MCLRE_OFF            ;MCLRリセットを使わないがＨにしておく
CB &= _PWRTE_ON             ;パワーアップ・タイマを使う
CB &= _WDT_ON               ;ウォッチドッグ・タイマを使う
CB &= _INTRC_OSC_NOCLKOUT   ;内部発振器を使う
    __CONFIG CB             ;3FFF -> 3='11'BANDGAP
    __IDLOCS H'0100'        ;バージョン1.00
;
;----------------------
; Data Define
;----------------------
    CBLOCK          H'20'
            W_TEMP,S_TEMP   ;コンテキストを保存する
            C_T0IF          ;タイマ0オーバーフロー回数を数える
            C_TIM1          ;遅延タイマカウンタ
            C_TIM2          ;遅延タイマカウンタ
            C_ADH           ;バッテリのA/D値 H側
            C_ADL           ;バッテリのA/D値 L側
            C_OUT           ;出力用変数
            C_INTR          ;割込み回数カウンタ
            C_TEMP          ;汎用変数
    ENDC
;======================================================
;  Start program
;======================================================
;START
        ORG     H'0'        ;0番地スタート
        CALL    H'3FF'      ;内部発振器をキャリブレーションする
        BSF     STATUS,RP0
        MOVWF   OSCCAL
        GOTO    MAIN
;
        ORG     H'4'        ;4番地スタート
        GOTO    INTR        ;割り込み処理
;
;======================================================
;  SubRoutines
;======================================================
;----------------------
;  WedgeIn   Subroutine
;----------------------
INTR
        ; ----- レジスタ保存 -----
        MOVWF   W_TEMP      ;Wレジスタ待避
        SWAPF   STATUS,W    ;STATUS取り出し
        MOVWF   S_TEMP      ;STATUS待避 
        ; ----- 割込み設定 -----
        ; (2ms) 2000ｶｳﾝﾄ/8 = 250
        ; TMROはｱｯﾌﾟｶｳﾝﾀなので 255-250=5
        BCF     INTCON,T0IE ;タイマ割込みフラグクリア
        MOVLW   D'5'        ;カウント値ロード
        MOVWF   TMR0        ;TMR0へ出力
        BCF     INTCON,T0IF ;ｵｰﾊﾞｰﾌﾛｰフラグクリア
INTR010
        ; ----- インターバルを14msにする -----
        DECFSZ  C_INTR,F    ;カウントダウン
        GOTO    INTRend     ;まだ14msでない
INTR020
        ; ----- ＰＷＭ出力 -----
        CALL    PWM         ;ＰＷＭ出力
INTR030
        ; ----- カウンタクリア -----
        MOVLW   D'7'        ;7を代入2msX7=14ms
        MOVWF   C_INTR      ;割込み回数カウンタ
INTRend
        ; ----- レジスタ復帰 -----
        SWAPF   S_TEMP,W    ;STATUSを戻す
        MOVWF   STATUS      ;
        SWAPF   W_TEMP,F    ;Wレジスタを戻す
        SWAPF   W_TEMP,W
        BSF     INTCON,T0IE ;タイマ割込み許可
        RETFIE              ;割込み許可リターン
;----------------------
;PWM Subroutine
;----------------------
PWM                         ;901us+(ｶｳﾝﾀ*5us)=PWM幅:901-2175us
        CLRWDT
        MOVF    C_OUT,W     ;A/D変換の値を
        MOVWF   C_TEMP      ;汎用変数に代入
        BSF     P_DRIVE     ;レジスタを１にしてPWMの立上り
        CALL    TIM99       ;996us
PWMLP
        NOP                 ;このループを4usにする
        DECFSZ  C_TEMP,F    ;レジスタの減算をし結果が０ならスキップ
        GOTO    PWMLP       ;C_TEMPが０になるまでループ
        BCF     P_DRIVE     ;レジスタを０にしてPWMの立下がり
        RETLW   0
;----------------------
;996us Timer Subroutine
;----------------------(996us)
TIM99
        MOVLW   D'248'      ;248回
        MOVWF   C_TIM2      ;ここまでで２サイクル
TIM99LP
        NOP
        DECFSZ  C_TIM2,F    ;このループは4サイクル
        GOTO    TIM99LP     ;2+4*248-1=993
        RETLW   0           ;993+2=995*1usec=995usec
;----------------------
;BATTERY     Subroutine
;----------------------(59us)
BATT
       ;----- A/Dコンバータを電源オン -----
        MOVLW   B'00000001' ;結果データは左詰にする
                            ;リファレンス電圧はVddを使う
                            ;GP0/AN0ピンから入力する
        MOVWF   ADCON0      ;A/Dコンバータを電源オンする
BATT010
        ;----- 蓄積時間の待ち -----
        MOVLW   D'7'        ;7回
        MOVWF   C_TIM1      ;ここまでで2サイクル
BATT015
        DECFSZ  C_TIM1,F    ;このループは3サイクル
        GOTO    BATT015     ;2+3*7-1=22us
BATT020
        ;----- A/D変換開始 -----
        BSF     ADCON0,GO   ;A/D変換開始する
BATT030
        ;----- A/D変換時間待ち -----
        MOVLW   D'7'        ;7回
        MOVWF   C_TIM1      ;ここまでで2サイクル
BATT035
        DECFSZ  C_TIM1,F    ;このループは3サイクル
        GOTO    BATT035     ;2+3*7-1=22us
BATT040
        ;----- A/D変換終了確認 -----
        BTFSC   ADCON0,GO   ;ADCON0,GOが０になるとA/D変換終了
        GOTO    BATT040     ;A/D変換終了待ち
BATT050
        ;----- A/D変換結果の代入 -----
        MOVF    ADRESH,W    ;A/D変換結果をWに代入
        MOVWF   C_ADH       ;WからC_ADHに代入 左詰めで、こちらだけで２５６分解能
        BSF     STATUS,RP0  ;STATUSレジスタのRP0ビットを１にBank1(Page1)に
        MOVF    ADRESL,W    ;A/D変換結果をWに代入
        BCF     STATUS,RP0  ;Bank0(Page0)に戻る
        MOVWF   C_ADL       ;WからC_ADLに代入
BATT060
        RETLW   0           ;サブルーチンの終了リターン
;
;======================================================
;  Main Routine
;======================================================
MAIN
;----------------------
; Initialize Routine
;----------------------
INIT
        ; ----- 初期設定 -----
        BSF     STATUS,RP0  ;STATUSレジスタのRP0ビットを１に
                            ;してBank1(Page1)に切替える     【BSF】 ｆ レジスタの指定ビットを１にする
        MOVLW   B'11010010' ;タイマ0に命令クロックを1:8して入力する
        MOVWF   OPTION_REG  ;WDTのTimeOutは??18ms*8=0.144秒??
        MOVLW   B'00001001' ;GP0入力にする
        MOVWF   TRISIO      ;GP1,2,4,5ピンを出力にする
        BCF     STATUS,RP0  ;Bank0(Page0)に戻る             【BCF】 ｆ レジスタの指定ビットを０にする 
        MOVLW   B'00000111' ;GP2/1/0 をデジタルI/Oに設定
        MOVWF   CMCON       ;CMCON = CM0/CM1/CM2 ON (COMPARATOR OFF)
        ;----- A/Dコンバータピンをアナログ設定 -----
        BSF     STATUS,RP0  ;STATUSレジスタのRP0ビットを１にBank1(Page1)に
        MOVLW   B'00110001' ;GP0/AN0ピンをアナログ入力モードにする
        MOVWF   ANSEL       ;A/D変換クロックはFrc(内部RC発振)
        BCF     STATUS,RP0  ;Bank0(Page0)に戻る
       ; ----- 初期クリア -----
        CLRF    TMR0        ;タイマ0の内容を0にする
        CLRF    C_T0IF      ;T0IFの内容を0にする
        CLRF    C_TIM1      ;遅延タイマカウンタ
        CLRF    C_TIM2      ;遅延タイマカウンタ
        CLRF    C_ADH       ;バッテリのA/D値 H側
        CLRF    C_ADL       ;バッテリのA/D値 L側
        CLRF    C_OUT       ;出力用変数
        MOVLW   D'7'        ;7を代入2msX7=14ms
        MOVWF   C_INTR      ;割込み回数カウンタ
        CLRF    C_TEMP      ;汎用変数
;----------------------
; Procedure Routine
;----------------------
PROC
        BCF     P_DRIVE     ;とりあえず０にしておく
        ; ----- 割込み設定 -----
        ; (2ms) 2000ｶｳﾝﾄ/8 = 250
        ; TMROはｱｯﾌﾟｶｳﾝﾀなので 255-250=5
        MOVLW   D'5'        ;カウント値ロード
        MOVWF   TMR0        ;TMR0へ出力
        BCF     INTCON,T0IF ;ｵｰﾊﾞｰﾌﾛｰフラグクリア
        BSF     INTCON,T0IE ;タイマ割込み許可
        BSF     INTCON,GIE  ;全体割込み許可;
;----------------------
; Loop Routine
;----------------------
MAIN_LOOP
        CLRWDT
        CALL    BATT        ;A/D変換
        MOVF    C_ADH,W     ;A/D変換結果
        MOVWF   C_OUT       ;出力用の変数に代入
        ;-- 2ms割込を７回でPWM出力 --
        GOTO    MAIN_LOOP
;----------------------
        END
