;------------------------------------------------------------------------
; MPPT 充放電コントローラー
; Programmed by GRANADA since 2007/11/7-
;                        v1.2 2009/04/07  MPPT中の満充電電圧チェック追加
;
; 製作記： http://www.asahi-net.or.jp/~SE1M-NITU/html/mppt.htm
;------------------------------------------------------------------------
; PIN アサイン
; GPIO-0 <AI> 太陽電池電圧
; GPIO-1 <AI> 電池電圧
; GPIO-2 <DO> PWM PULSE 出力（充電制御）
; GPIO-3 <DI> 夜間検出（ H = 夜間、L = 昼間 ）
; GPIO-4 <DO> 負荷制御（ H = 負荷接続許可、L = 負荷切り離し ）
; GPIO-5 <DO> 過放電 LED 制御（H = 過放電）
;---------------------------------------------------------------------------

	LIST		P=12F683
	INCLUDE		P12F683.INC
	ERRORLEVEL	-302

CB  = _CP_OFF
CB &= _CPD_OFF
CB &= _WDT_OFF
CB &= _BOD_OFF
CB &= _PWRTE_OFF
CB &= _INTRC_OSC_NOCLKOUT
CB &= _MCLRE_OFF

	__CONFIG	CB
	__IDLOCS	H'0100'

;---------------------------------------------------------------------------
; 変数領域定義
;---------------------------------------------------------------------------

PWM_WIDTH	EQU	H'20'	; テューティー値

MPP_V		EQU	H'21'	; MPP 電圧ストア用
SOLAR_V		EQU	H'22'	; 太陽電池電圧ストア用
BATT_V		EQU	H'23'	; バッテリ電圧ストア用

WAIT1		EQU	H'30'	; 時間待ちカウンタ
WAIT2		EQU	H'31'	; 時間待ちカウンタ
WAIT3		EQU	H'32'	; 時間待ちカウンタ
PWM_COUNT1	EQU	H'33'	; PWM 実行カウンタ
PWM_COUNT2	EQU	H'34'	; PWM 実行カウンタ
DARK_COUNT	EQU	H'35'	; 夜間検出用カウンタ

USER_FLAG	EQU	H'40'	; 各種フラグ領域

A1			EQU	H'50'	; 割られる数
B1			EQU	H'51'	; 割る数
W1			EQU	H'52'	; ワーク１
Na			EQU	H'54'	; Ａのシフト値
Nba			EQU	H'56'	; ＢとＡのシフト値の差

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

SOLAR_IN	EQU	D'0'	; 太陽電池電圧                                           ポート番号
BATTERY_IN	EQU	D'1'	; 電池電圧                                               ポート番号
PWM_OUT		EQU	D'2'	; PWM PULSE 出力 （充電制御）                            ポート番号
DARK_IN		EQU	D'3'	; 夜間検出       （ H = 夜間、L = 昼間 ）                ポート番号
LOAD_OUT	EQU	D'4'	; 負荷制御       （ H = 負荷接続許可、L = 負荷切り離し ）ポート番号
ALARM_OUT	EQU	D'5'	; 過放電 LED 制御（ H = 過放電 ）                        ポート番号


TRACK_COUNT	EQU	D'40'	; MPP 追跡ループ回数（クロック 8MHz時）

						; クロック 8MHz 時 10KHz 設定
;CYCLE		EQU	D'199'	; PE2 レジスタ設定値
;DUTY100		EQU	D'200'	; DUTY 100%（太陽電池開放用）
;DUTY90		EQU	D'180'	; DUTY  90%（トリクル充電用）
;WIDTH_MAX	EQU	D'195'	; DUTY 最大値

						; クロック 8MHz 時 15KHz 設定
CYCLE		EQU	D'149'	; PE2 レジスタ設定値
DUTY100		EQU	D'150'	; DUTY 100%（太陽電池開放用）
DUTY90		EQU	D'135'	; DUTY  90%（トリクル充電用）
WIDTH_MAX	EQU	D'145'	; DUTY 最大値

;						; クロック 8MHz 時 20KHz 設定
;CYCLE		EQU	D'99'	; PE2 レジスタ設定値
;DUTY100		EQU	D'100'	; DUTY 100%（太陽電池開放用）
;DUTY90		EQU	D'90'	; DUTY  90%（トリクル充電用）
;WIDTH_MAX	EQU	D'95'	; DUTY 最大値

WIDTH_MIN	EQU	D'1'	; DUTY 最小値

FULL_V		EQU	D'186'	; 満充電時     14.5V の 8bit A/D 変換値 = 14.5/4 * 256/5
RECHARGE_V	EQU	D'177'	; 再充電許可時 13.8V の 8bit A/D 変換値 = 13.8/4 * 256/5
EMPTY_V		EQU	D'143'	; 過放電時     11.2V の 8bit A/D 変換値 = 11.2/4 * 256/5

DARK_CHECK	EQU	D'3'	; 夜間処理までの暗黒検出回数（MPP周期xこの回数秒でクロックダウン）

DARK		EQU	D'0'	; 夜間フラグビット
BAT_FULL	EQU	D'1'	; 満充電フラグビット
BAT_EMPTY	EQU	D'2'	; 過放電フラグビット

;---------------------------------------------------------------------------
; 電源投入時ベクタ
;---------------------------------------------------------------------------

	ORG		0x00
	GOTO	INITIALIZE

;---------------------------------------------------------------------------
; 割込みベクタ（未使用）
;---------------------------------------------------------------------------

	ORG		0x04
	RETFIE	; 何もしないで戻る

;---------------------------------------------------------------------------
; 初期化
;---------------------------------------------------------------------------
INITIALIZE:

	BANKSEL	GPIO			; Bank 0

	CLRF	GPIO			; とりあえず全ポートをクリア

	MOVLW	B'00000111'
	MOVWF	CMCON0 			; CMCON = CM0/CM1/CM2 ON (コンパレータを使用しない)

	BANKSEL	TRISIO			; Bank 1

	MOVLW	B'00001011'		; 0 = OUT, 1 = IN
	MOVWF	TRISIO			; 各ポート入出力設定

	MOVLW	B'10000000'
	MOVWF	OPTION_REG		; GPIO プルアップを使用しない
	CLRF	WPU				; Weak pull up 未使用

	CLRF	OSCTUNE			; クロック微調整無し

	BANKSEL	GPIO			; Bank 0

	CLRF	USER_FLAG		; ユーザーフラグを全クリア

	CALL	SET_DAY			; 昼間の状態にフラグを初期化

	CALL	INIT_PWM		; PWM & A/D 変換関連初期化

	BSF		GPIO, ALARM_OUT	; 警告 LED 点灯（正常起動確認）
	CALL	WAIT_1s			; 3 秒間自己点滅
	CALL	WAIT_1s
	CALL	WAIT_1s
	BCF		GPIO, ALARM_OUT	; 警告 LED 消灯

	CALL	LOAD_CONNECT	; 負荷接続

;---------------------------------------------------------------------------
; メインループ
;---------------------------------------------------------------------------

MAIN_LOOP:

;---------------------------------------------------------------------------
; 電池電圧チェック
;---------------------------------------------------------------------------

	CALL 	READ_BATT_V		; バッテリ電圧測定

;---------------------------------------------------------------------------
; 過放電処理
;---------------------------------------------------------------------------

	MOVF	BATT_V,W		; 測定電圧値を読み出す
	SUBLW	EMPTY_V			; 過放電チェック EMPTY_V - VOLTAGE -> W
	BTFSC	STATUS,C		; 正常電圧ならキャリーが発生し C=0 となり次の命令をスキップ
	CALL	LOAD_DISCONNECT	; 負荷切り離し処理

;---------------------------------------------------------------------------
; 夜間検出処理
;---------------------------------------------------------------------------
DETECT_DARKNESS:

	CALL	CLOCK_DOWN_CHK	; 夜間検出チェック、所定回数に達するとフラグを立て、PWM 停止後クロックダウン
	BTFSC	USER_FLAG,DARK	; 夜間フラグをチェック、フラグが立っていなければ次の行をスキップ
	GOTO	MAIN_LOOP		; 夜間は充電関連処理は行わない

;	BTFSC	GPIO,DARK_IN	; 
;	GOTO	MAIN_LOOP		; 夜ならPWM制御なし

;--------------------------------------------------------------------------------
;	電圧比較、満充電か ?
;--------------------------------------------------------------------------------
CHECK_FULL_CHARGE:

	MOVF	BATT_V,W			; 測定電圧値を読み出す
	SUBLW	FULL_V				; FULL_V - VOLTAGE -> W
	BTFSC	STATUS,C			; 満充電時は借り入れが発生するので C=0 となり、次の命令がスキップされる
	GOTO	CHECK_RECHARGE		; 満充電ではない

;--------------------------------------------------------------------------------
;	満充電
;--------------------------------------------------------------------------------

	CALL	DISCON_SOLAR		; 太陽電池を切り離す
	BSF		USER_FLAG,BAT_FULL	; 満充電フラグセット
	GOTO	MAIN_LOOP			; メイン処理再開

;--------------------------------------------------------------------------------
;	再充電許可電圧か ?
;--------------------------------------------------------------------------------

CHECK_RECHARGE:

	MOVF	BATT_V,W			; 測定電圧値を読み出す
	SUBLW	RECHARGE_V			; RECHARGE_V - VOLTAGE -> W
	BTFSC	STATUS,C			; 再充電許可電圧より電圧が高ければキャリーが発生して C=0 となり次の命令がスキップされる
	GOTO	MPPT				; 正常電圧範囲内なので MPPT 制御

;--------------------------------------------------------------------------------
;	再充電許可電圧以上の場合
;--------------------------------------------------------------------------------

	BTFSC	USER_FLAG,BAT_FULL	; 満充電フラグチェック
	GOTO	MAIN_LOOP			; 満充電フラグが立っていたら何もしない

	CALL	DUTY_90				; デューティー比 90% で充電
	CALL	WAIT_1s				; 1 秒充電

	GOTO	MAIN_LOOP

;---------------------------------------------------------------------------
;	電池電圧正常、PWM 制御開始
;---------------------------------------------------------------------------
MPPT:

	BCF		USER_FLAG,BAT_FULL	; 満充電フラグをクリアする

	CALL	CALC_MPP			; 太陽電池（開放）電圧測定 → MPP 電圧決定
	CALL	TRACK_MPP			; 一定回数 MPP 追従

	GOTO	MAIN_LOOP

;---------------------------------------------------------------------------
; ここからサブルーチン群
;---------------------------------------------------------------------------
; MPP（最大出力点）電圧計算
; 事前の夜間検出により、低電圧時はこの処理には飛んでこない
;---------------------------------------------------------------------------
CALC_MPP:

	CALL	DISCON_SOLAR	; 太陽電池を負荷から切り離し

	CALL	READ_SOLAR_V	; 開放時の太陽電池電圧を取得
							; MPP_V = 開放電圧 * 0.8、すなわち開放電圧から 1/5 を引けば求まる
	MOVF	SOLAR_V,W		; 割られる数（測定値）
	MOVWF	A1
	MOVLW	D'5';			; 割る数
	MOVWF	B1

	CALL	DIV8			; 8bit 割り算、答え A1, 余り B1 で戻ってくる

	MOVF	A1,W			; 答えを得る
	SUBWF	SOLAR_V,W		; レジスタ SOLAR_V 内の値 - W  = 0.8 * SOLAR_V
	BTFSS	STATUS,C		; 借り入れが発生しなければ（正常） C=1 となり、次の命令がスキップされる
	GOTO	ILLEGULAR_MPP	; 値が異常なので強制補正

	BTFSS	STATUS,Z		; 万が一ゼロの場合は Z=1 となり、次の命令がスキップされる
	GOTO	SET_MPP			; 計算値は正常

ILLEGULAR_MPP:

	MOVF	SOLAR_V,W		; MPP 値が異常なので MPP を開放時電圧に強制設定

SET_MPP:

	MOVWF	MPP_V			; MPP 電圧ストア

	RETURN

;---------------------------------------------------------------------------
; MPP 追従（約 2 秒）
;---------------------------------------------------------------------------
TRACK_MPP:

	MOVLW	TRACK_COUNT		; 8MHz 時
	MOVWF	PWM_COUNT1		; PWM 制御カウンタ 1

PWM_LOOP1:

	MOVLW	D'255'
	MOVWF	PWM_COUNT2		; PWM 制御カウンタ 2

PWM_LOOP2:

	CALL	SET_DUTY		; デューティー比適宜設定

	DECFSZ	PWM_COUNT2,F
	GOTO	PWM_LOOP2

	CALL	READ_BATT_V		; 鉛電池電圧をチェック
	MOVF	BATT_V,W
	SUBLW	FULL_V			; FULL_V - VOLTAGE -> W
	BTFSS	STATUS,C		; FULL_V > VOLTAGE なら借り入れが発生せず C=1 となり、次の命令がスキップされる
	GOTO	COOL_DOWN		; 満充電電圧に達したので充電強制停止

	DECFSZ	PWM_COUNT1,F
	GOTO	PWM_LOOP1

	RETURN

;---------------------------------------------------------------------------
; 強制 Cool down
;---------------------------------------------------------------------------

COOL_DOWN:

	CALL	DISCON_SOLAR		; 太陽電池を切り離す

	CALL	WAIT_1s				; 2秒間充電強制停止
	CALL	WAIT_1s

	RETURN

;---------------------------------------------------------------------------
; MPP 電圧を参照してデューティー比を調整する
;---------------------------------------------------------------------------
SET_DUTY:

	CALL	READ_SOLAR_V
	MOVF	SOLAR_V,W	; 太陽電池電圧を読み出す

	SUBWF	MPP_V,W		; MPP_V - SOLOAR_V -> W
	BTFSC	STATUS,C	; MPP より太陽電池電圧が高いと借り入れが発生するので C=0 となり、次の命令がスキップされる
	GOTO	SOLAR_UP	; MPP より電圧が低いから太陽電池電圧を上げる方向へ

;---------------------------------------------------------------------------
; 太陽電池電圧 DOWN 方向　→　DUTY DOWN 方向
;---------------------------------------------------------------------------
SOLAR_DOWN:

	DECF	PWM_WIDTH,F	; デューティー比 DOWN
	MOVF	PWM_WIDTH,W

	SUBLW	WIDTH_MIN	; WIDTH_MIN - PWM_WIDTH -> W
	BTFSS	STATUS,C	; WIDTH_MIN よりデューティー比が低いと借り入れが発生せず C=1 となり、次の命令がスキップ
	GOTO	CHANGE_DUTY	; 正常範囲内なのでそのままデューティー設定
;
;	最小デューティー比クリッピング
;
	MOVLW	WIDTH_MIN	; Duty 0% の値（定数）に再設定
	MOVWF	PWM_WIDTH

	GOTO	CHANGE_DUTY	; デューティー比設定

;---------------------------------------------------------------------------
; 太陽電池電圧 UP 方向　→　DUTY UP 方向
;---------------------------------------------------------------------------
SOLAR_UP:

	INCF	PWM_WIDTH,F	; デューティー比 UP
	MOVF	PWM_WIDTH,W

	SUBLW	WIDTH_MAX	; WIDTH_MAX - PWM_WIDTH -> W
	BTFSC	STATUS,C	; WIDTH_MAX よりデューティー比が高いと借り入れが発生して C=0 となり、次の命令がスキップ
	GOTO	CHANGE_DUTY	; 正常範囲内なのでそのままデューティー設定
;
;	最大デューティー比クリッピング
;
	MOVLW	WIDTH_MAX	; Duty 100% の値（定数）に再設定
	MOVWF	PWM_WIDTH

CHANGE_DUTY:			; ディーティー比変更

	MOVF	PWM_WIDTH,W	; 
	MOVWF	CCPR1L		; Duty 比変更

	RETURN

;---------------------------------------------------------------------------
; 太陽電池負荷フル状態 (DUTY 0%)
;---------------------------------------------------------------------------
CONNECT_SOLAR:

	CLRF	PWM_WIDTH
	CLRF	CCPR1L		; Duty 0% 設定
	CALL	WAIT_1ms	; 少し待つ

	RETURN

;---------------------------------------------------------------------------
; 太陽電池開放 (DUTY 100%)
;---------------------------------------------------------------------------
DISCON_SOLAR:

	MOVLW	DUTY100		; Duty 100% の値（定数）を読み出す
	MOVWF	PWM_WIDTH
	MOVWF	CCPR1L		; Duty 100% 設定
	CALL	WAIT_100ms	; 太陽電池電圧回復待ち

	RETURN

;---------------------------------------------------------------------------
; 満充電時のトリクル充電 (DUTY 90%)
;---------------------------------------------------------------------------
DUTY_90:

	MOVLW	DUTY90		; Duty 90%
	MOVWF	PWM_WIDTH
	MOVWF	CCPR1L		; Duty 90% 設定

	RETURN

;---------------------------------------------------------------------------
; 電圧取得
;---------------------------------------------------------------------------
READ_SOLAR_V:			; 太陽電池電圧測定

	BANKSEL	ADCON0

	MOVLW	B'00000000'	; AN0, 左詰め
	MOVWF	ADCON0
	CALL	EXEC_ADC
	MOVF	ADRESH,W	; A/D 変換値を得て
	MOVWF	SOLAR_V		; ワークエリアにストアしておく
	RETURN

READ_BATT_V:			; バッテリ電圧測定

	BANKSEL	ADCON0

	MOVLW	B'00000100'	; AN1, 左詰め
	MOVWF	ADCON0
	CALL	EXEC_ADC
	MOVF	ADRESH,W	; A/D 変換値を得て
	MOVWF	BATT_V		; ワークエリアにストアしておく
	RETURN

;---------------------------------------------------------------------------
; A/D 変換実行
;---------------------------------------------------------------------------
EXEC_ADC:

	BSF		ADCON0,ADON	; A/D 変換 Enable
	CALL	PRECHARGE	; プリチャージ待ち
	BSF		ADCON0,GO	; A/D 変換開始

ADC_WAIT:

	BTFSC	ADCON0,GO	; A/D 変換終了 ?
	GOTO	ADC_WAIT

	BCF		ADCON0,ADON	; A/D 変換 Disable

	RETURN

;---------------------------------------------------------------------------
; 夜間検出、PWM 停止〜クロックダウン処理
;---------------------------------------------------------------------------
CLOCK_DOWN_CHK:

	BTFSS	GPIO,DARK_IN	; H = 夜間状態なので次の行をスキップ
	GOTO	DAY				; 昼間処理へ

	BTFSC	USER_FLAG,DARK	; 夜間フラグをチェック、フラグが立っていなければ次の行をスキップ
	RETURN					; 既に夜間状態なので何もしないで戻る

	DECFSZ	DARK_COUNT,F	; 夜間検出カウンタを減らす
	RETURN					; まだ許容範囲内なのでそのまま戻る

NIGHT:						; 夜間状態

	BANKSEL OSCCON			; Bank 1

	MOVLW	B'00000000'		; 内部クロック 31KHz にクロックダウン
	MOVWF	OSCCON			; 周波数設定

	CALL	STOP_PWM		; PWM 停止

	BANKSEL	GPIO			; Bank 0

	BSF		USER_FLAG,DARK	; 夜間フラグを立てる

	RETURN

DAY:						; 昼間状態

	BTFSC	USER_FLAG,DARK	; 夜間フラグをチェック、フラグが立っていなければ次の行をスキップ
	GOTO	CLOCK_UP		; 夜間からの復帰処理

	CALL	SET_DAY			; 昼間なのでフラグ類だけ初期化

	RETURN

CLOCK_UP:

	CALL	SET_DAY			; フラグ類初期化
	CALL	INIT_PWM		; PWM 初期化, PWM 再開

	RETURN

SET_DAY:

	MOVLW	DARK_CHECK
	MOVWF	DARK_COUNT		; 夜間カウンタを初期値に
	BCF		USER_FLAG,DARK	; 夜間フラグをクリア

	RETURN

;---------------------------------------------------------------------------
; PWM 初期化、内部クロック設定
;---------------------------------------------------------------------------
INIT_PWM:

	BANKSEL	ANSEL			; Bank 1

	MOVLW	B'01100011'		; FOSC/64, Port AN0 & AN1 使用
	MOVWF	ANSEL

	MOVLW	B'01110000'		; 内部クロック 8MHz
	MOVWF	OSCCON			; 周波数設定

	MOVLW	CYCLE			; PWM 周波数読み込み
	MOVWF	PR2				; PWM 周期セット

	CALL	DISCON_SOLAR	; 太陽電池開放 DUTY 設定 (100%)

	BANKSEL	CCPR1L			; Bank 0

	MOVLW	B'00001100'		; PWM モード に設定
	MOVWF	CCP1CON

	CALL	TIMER_START		; タイマースタート

	RETURN

;---------------------------------------------------------------------------
; タイマ 2 START
;---------------------------------------------------------------------------
TIMER_START:

	BANKSEL	T2CON			; Bank 0
	MOVLW	B'0000100'		; TIMER2 ON, Prescale = 1:1
	MOVWF	T2CON			; TIMER2 START

	RETURN

;---------------------------------------------------------------------------
; タイマ 2 STOP
;---------------------------------------------------------------------------
TIMER_STOP:

	BANKSEL	T2CON			; Bank 0
	BCF		T2CON,TMR2ON	; タイマ 2 を止める

	RETURN

;---------------------------------------------------------------------------
; PWM 停止
;---------------------------------------------------------------------------
STOP_PWM:

	BANKSEL	ANSEL			; Bank 1
	MOVLW	B'00110011'		; Frc, Port AN0 & AN1 使用
	MOVWF	ANSEL

	CALL	CONNECT_SOLAR	; 太陽電池を接続（= PWM PORT L で確定）

	CALL	TIMER_STOP		; タイマー停止

	BCF		GPIO,PWM_OUT	; 太陽電池フル接続 (L) で省電力化

	RETURN

;---------------------------------------------------------------------------
; A/D コンバータのプリチャージ待ち
;---------------------------------------------------------------------------
PRECHARGE:

	MOVLW	D'10'			; 8MHz -> 50us, 32KHz -> 12.5ms 待つ
	MOVWF	WAIT1
	GOTO	WAIT_LOOP1

;---------------------------------------------------------------------------
; WAIT 1us (CLOCK 8MHZ -> 1 cycle = 0.5us) 
; CALL を含めて 10 Step で 5us（正確）
;---------------------------------------------------------------------------
WAIT_5us:			; ( CALL 2 cycle )

	GOTO	$+1		; 2 cycle
	GOTO	$+1		; 2 cycle
	GOTO	$+1		; 2 cycle

	RETURN			; 1 cycle

;---------------------------------------------------------------------------
; WAIT 1ms（だいたい 1ms）
;---------------------------------------------------------------------------

WAIT_1ms:

	MOVLW	D'200'
	MOVWF	WAIT1
	GOTO	WAIT_LOOP1

;---------------------------------------------------------------------------
; 時間稼ぎ本体（1msまで)
;---------------------------------------------------------------------------

WAIT_LOOP1:

	CALL	WAIT_5us

	DECFSZ	WAIT1,F
	GOTO	WAIT_LOOP1

	RETURN

;---------------------------------------------------------------------------
; WAIT 100ms (だいたい 100ms)
;---------------------------------------------------------------------------

WAIT_100ms:

	MOVLW	D'100'
	MOVWF	WAIT2

WAIT_100ms_LOOP:

	CALL	WAIT_1ms
	DECFSZ	WAIT2,F
	GOTO	WAIT_100ms_LOOP

	RETURN

;---------------------------------------------------------------------------
; WAIT 1sec （だいたい 1sec）
;---------------------------------------------------------------------------

WAIT_1s:

	MOVLW	D'10'
	MOVWF	WAIT3

WAIT_1s_LOOP:

	CALL	WAIT_100ms
	DECFSZ	WAIT3,F
	GOTO	WAIT_1s_LOOP

	RETURN

;--------------------------------------------------------------------------------
;	過放電処理（負荷切り離し）
;--------------------------------------------------------------------------------
LOAD_DISCONNECT:

	BSF		USER_FLAG, BAT_EMPTY	; 過放電フラグを立てる
	BSF		GPIO, ALARM_OUT			; LED 警告開始
	BCF		GPIO, LOAD_OUT			; 負荷切り離し

	BCF		USER_FLAG, BAT_FULL		; 満充電ではないから念のためクリアしておく

	RETURN

;--------------------------------------------------------------------------------
;	負荷接続
;--------------------------------------------------------------------------------
LOAD_CONNECT:

	BCF		USER_FLAG, BAT_EMPTY	; 過放電フラグをクリア
	BCF		GPIO, ALARM_OUT			; LED 警告停止
	BSF		GPIO, LOAD_OUT			; 負荷接続

	RETURN

;*********************************************************************
;	8bit除算ルーチン	Ａ÷Ｂ＝Ａ･･･Ｂ
;   Orignal By http://orange.zero.jp/electronics/pic/pic.html
;	0エラーのときは、A,B ともに 0 クリア
;	A1	割られる数	／	答え
;	B1	割る数		／	余り
;*********************************************************************

;----------------------------
DIV8:	;	8 bit 割り算ルーチン
;----------------------------
		clrf		Na			;初期値をセット
		clrf		Nba
		clrf		W1
;-----------------------------
LOOP8A:
		btfsc		A1,7		;最上位bitまでループ
		goto		LOOP8B		;最上位まできたら、次へ
		bcf			STATUS,C
		rlf			A1,f
		incf		Na,f		;カウント加算
		movlw		8h
		subwf		Na,w
		btfss		STATUS,Z	;カウントが 8 か？
		goto		LOOP8A		;ループ
		goto		ANSERR8		;カウント値が 8 ならばエラー処理
;-----------------------------
LOOP8B:
		btfsc		B1,7		;最上位bitまでループ
		goto		NCHK8		;最上位まできたら、次へ
		bcf			STATUS,C
		rlf			B1,f
		incf		Nba,f		;カウント加算
		movlw		8h
		subwf		Na,w
		btfss		STATUS,Z	;カウントが 8 か？
		goto		LOOP8B		;ループ
		goto		ANSERR8		;カウント値が 8 ならばエラー処理
;---------------------------
NCHK8:
		movf		Na,w		;Nbaを計算
		subwf		Nba,f
		incf		Nba,f
		btfss		STATUS,C	;Nbaが負なら
		goto		ANS8		;ANSZへジャンプ
		movf		Nba,w
		addwf		Na,f
;---------------------------
HOS8:
		movf		B1,w
		subwf		A1,f
		btfss		STATUS,C
		goto		ADDH8
LOOP8H:
		rlf			W1,1
		rlf			A1,1
		decf		Nba,f
		btfsc		STATUS,Z
		goto		ANS8
		btfsc		A1,7		;最上位までループ
		goto		HOS8		;最上位まできたらHOS8へ
		goto		LOOP8H
;---------------------------
ADDH8:
		movf		B1,w
		addwf		A1,f
		bcf			STATUS,C
ADDHLOOP:
		rlf			W1,1
		rlf			A1,1
		decf		Nba,f
		btfsc		STATUS,Z
		goto		ANS8
		movf		B1,w
		subwf		A1,f
		bsf			STATUS,C
		btfsc		A1,7
		goto		ADDHLOOP
		goto		LOOP8H
;---------------------------
ANS8:
		bcf			STATUS,C
		rrf			A1,f
		decfsz		Na,f
		goto		ANS8
ANSS8:							;解答をセットし終了
		movf		A1,w
		movwf		B1			;余りをＢにコピー
		movf		W1,w
		movwf		A1			;答えをＡにコピー

		return
;---------------------------
ANSERR8:						;エラー処理
		clrf		A1			;数値クリア
		goto		ANSS8

;----------------------------------------------------------------

;
;
;
	END
