;
;	RS-232C の命令を受け取って入出力を行う
;                                    薮 哲郎
;	v0.0  2009.10.31   開発開始
;	 1.0       11. 4   ほぼ完成
;
;	入出力ポート
;     デジタル出力 6ch   PORTC bit 0-5
;     アナログ入力 4ch   PORTA bit 0-3
;     デジタル入力 4ch   PORTA bit 0-3
;
;　　   PORTB はインジケーター用
;		bit 0-6 は RS-232C から受信したコード
;		bit 7   はコマンド処理中のとき点灯
;
;  ＜コマンド＞
;
;	コマンドは # で始まり $ で終わる。0x0a, 0x0d などは不要
;
;		コマンドの応答はデータを返すときは #データ$
;		OK のときは #OK$
;		エラー発生のときは #E02$    02 はエラーコード
;		
;		PIC のバッファは 2 byte しかなく、バッファがあふれたときはデータが失われる。
;		本プログラムではバッファオーバーランが起きたとき、バッファの中をクリアして
;		動作を続ける。
;
;		命令を送信した後は、必ず PIC から応答を読み込んでから、
;		次のコマンドを送信すること。
;
;	アナログ入力 ch.は 0-3
;		a2  ch.2 の入力を問い合わせる
;			応答は #3ff$ のように 10 bit で返る
;
;   入力モードチェンジ
;		デフォルトはアナログモード
;		Ma	アナログモードに移行
;		Md	デジタルモードに移行
;
;	デジタル入力 ch.は 0-3
;		d1	ch.1 の入力を問い合わせる
;			応答は "#0$" のように 0 か 1 を返す
;		da  ch.0-3 の入力を問い合わせる
;			応答は "#0f$" のように 4 bit ずつ 16 進数で表示する
;			ch.4-7 は将来の拡張用　今は 0 が入る。
;		
;	デジタル出力 ch.は 0-5
;		D20   ch.2 の出力を 0 に設定
;		D01   ch.0 の出力を 1 に設定
;		Da2f  ch.0-5 の出力のビットパターンを 2f に設定する
;
;　＜注意＞
;
;  PIC の USART はバッファが 2 文字分しかない。
;  ディレイ処理の最中に PC から 3 文字以上送ると、
;  1 文字目を読み取り、2 文字目の読み取りのときに
;  buf が永遠に empty のままになり、ハングアップする。
;
;  従って、PC は自分が何らかのコマンドを送った後、かならず #?$ という文字列を
;  読み取った後、次のコマンドを送る必要がある。
;
;  ＜エラーコード(16進)＞
;
;	1   命令が長すぎる
;	2   該当コマンドがない
;   3   D コマンドのチャンネルが 6 以上
;	4   d コマンドのチャンネルが 4 以上
;   5   a コマンドのチャンネルが 4 以上
;   6   M コマンドの引数が a,d 以外である
;   7   d,a コマンドが来たが、現在のモードと異なる
;   8   D コマンドの引数が 0, 1 以外の数である
;　 10   数値が来るべきところに 0-9, A-F, a-f 以外の文字がある
;

	LIST	P=PIC16F873A
	INCLUDE	P16F873A.INC

conf  = _CP_OFF & _DEBUG_OFF
conf &= _WRT_OFF
conf &= _CPD_OFF & _LVP_OFF & _BODEN_ON
conf &= _PWRTE_ON & _WDT_OFF & _HS_OSC

	__CONFIG conf

; CP          コードプロテクト
; DEBUG       In-Circuit Debugger を有効にするか否か
;             ON にすると RB6, RB7 がデバッグ用ピンになる
; WRT         プログラムメモリのライトプロテクト 
; CPD         データ EE メモリの読み出しプロテクト
; LVP         低電圧( 5V, 通常は 12.5V ) で PIC に書き込む機能
;            　有効／無効   LVP 対応のプログラマが必要で RB4 が
;             使用不可になる。
; BODEN       ブラウンアウト検出 ON 有効 ／ OFF 無効
;        　    電源電圧が下がったときにリセットするか否か
; PWRTE       パワーアップタイマ　
;             電源が入ってから実行を開始するまで 72 ms 待つか否か
;             外部の信号を取り込むとき ON にした方がよい
; WDG         ウォッチドッグタイマ　使用した場合、
;             17 ms 以内に定期的に CLRWDT を実行しないと、
;             暴走したと見なしリセットがかかる
; HS_OSC      セラロック使用

;	0x20 から受信用バッファ
;	0x30 から送信用バッファ
;	どちらも 16 byte 確保してあるが、使うのは最初の 8 バイト

INPUT_BUF_TOP	EQU		0x20
INPUT_BUF_2nd	EQU		0x21
INPUT_BUF_3rd	EQU		0x22
INPUT_BUF_4th	EQU		0x23
INPUT_BUF_END	EQU		0x27
OUTPUT_BUF_TOP	EQU		0x30
OUTPUT_BUF_2nd	EQU		0x31
OUTPUT_BUF_3rd	EQU		0x32
OUTPUT_BUF_4th	EQU		0x33
OUTPUT_BUF_5th	EQU		0x34
OUTPUT_BUF_END	EQU		0x37

	cblock 0x40
	T1, T2, T3			; ディレイループ用
	BUF, MASK, FLAG
	DATA_L, DATA_H, DATA_HH
	CONV_DAT, CONV_ERR
	C1,C2,C3			; カウンタ用
	ERR_CODE
	INPUT_CH
	SEND_BUF, RECV_BUF
	ANALOG_MODE
	endc

	banksel	INTCON	
	clrf	INTCON		; 割り込み禁止
						; これを怠ると途中でハングアップする
	bsf		INTCON,6

;----- 入出力ポートの設定 ------

	banksel	TRISA
	movlw	B'00011111'	; 全て入力
	movwf	TRISA
	movlw	B'00000000'	; 全て出力
	movwf	TRISB
	movlw	B'10000000'	; RC7 入力  RC6 出力（USART）
	movwf	TRISC		; それ以外は出力

;------- AD コンバータの設定 -------
;
;	注意 ： 20 MHz の場合、可能な設定値は Fosc/32 (1.6μs) あるいは
;         Fosc/64 (3.2μs) である。
;		  Fosc/32 のとき ADCON1:6 = 0   ADCON0:76 = 10 である。
;         後藤氏の PIC16F 活用ガイドブック p.238 を参照すること

	banksel	ADCON0
;			  76543210
	movlw	B'10000001'	; 76: クロック
						; 5-3: チャンネルセレクトビット
						; 2 : 1 で変換スタート  0 になったら終了
						; 1 : -
						; 0 : ADコンバータ 0=off  1=on
	movwf	ADCON0

;	デフォルトはアナログモード

	banksel	ADCON1
;			  76543210
	movlw	B'10000000'	; 7 : 1=右寄せ  0=左寄せ
						; 6 : クロック
						; 54: -
						; 3-0 : 0000 = 全てアナログ入力
						;     : 011x = 全てデジタル入力
	movwf	ADCON1

	banksel	ANALOG_MODE
	movlw	D'1'
	movwf	ANALOG_MODE

;----- RS-232C の設定 --------

	banksel	TXSTA
;			  76543210
	movlw	B'00100100'		; 7:-
							; 6:0=8-bit mode
							; 5:1=transmit enable
							; 4:0=Asynchronous mode
							; 3:-
							; 2:0=Low Speed  1=High speed
							; 1:Read only
							; 0:-
	movwf	TXSTA			; バンク 1

	movlw	D'129'			; p.114 の表参照   9600 baud
	movwf	SPBRG			; バンク 1

	banksel	RCSTA
;			  76543210
	movlw	B'10010000'		; 7:serial port enabled
							; 6:0=8-bit mode
							; 5:-
							; 4:1=enable continuous receive
							;   0=disable continuous receive
							;   bit 4 を 0 にすると、PIC は全く反応しなかった
							; 3:-
							; 2-0:Read only
	movwf	RCSTA			; バンク 0

;------ スタート時は PORTB, PORTC の出力は 0 -----

	clrf	PORTB
	clrf	PORTC

;----- メインループ ----------

MAIN
	clrf	PORTB		; インジケータをクリア
MAIN2
	call	Recv_1byte
	movf	RECV_BUF,W
	sublw	A'#'
	btfss	STATUS,Z	; コマンドの先頭文字 # を見つける
	goto	MAIN2

;	　　　---- コマンドの読み込み ----

	bsf		PORTB,7		; コマンド処理中のサイン		
	movlw	INPUT_BUF_TOP	; インデックスレジスタに 0x20 をセット
	movwf	FSR

Recv_top
	call	Recv_1byte	; 1 バイト読んで格納する
	movf	RECV_BUF,W
	movwf	INDF
	incf	FSR,F
	sublw	A'$'		; コマンドの末尾文字 $ を見つけたら Syori へ行く
	btfsc	STATUS,Z	
	goto	Syori
	movf	FSR,W
	sublw	INPUT_BUF_END	; 命令が 8 文字以上あるときエラー処理
	btfsc	STATUS,C
	goto	Recv_top

;   エラー処理
	movlw	D'1'
	movwf	ERR_CODE
	call	Disp_error
	goto	MAIN

;----------- 受け取ったコマンドの処理 --------

Syori
	movf	INPUT_BUF_TOP,W
	sublw	A'a'
	btfsc	STATUS,Z
	goto	Analog_input

	movf	INPUT_BUF_TOP,W
	sublw	A'd'
	btfsc	STATUS,Z
	goto	Digital_input

	movf	INPUT_BUF_TOP,W
	sublw	A'D'
	btfsc	STATUS,Z
	goto	Digital_output

	movf	INPUT_BUF_TOP,W
	sublw	A'M'
	btfsc	STATUS,Z
	goto	Input_mode_change

;	どのコマンドにも該当しないのでエラー

	movlw	D'2'
	movwf	ERR_CODE
	call	Disp_error
	goto	MAIN

;--------- 入力モードの変換 ---------

Input_mode_change
	movf	INPUT_BUF_2nd,W
	sublw	A'd'
	btfsc	STATUS,Z
	goto	To_digital_mode
	movf	INPUT_BUF_2nd,W
	sublw	A'a'
	btfsc	STATUS,Z
	goto	To_analog_mode

	movlw	D'6'
	movwf	ERR_CODE
	call	Disp_error
	goto	MAIN

To_digital_mode
	movlw	D'0'
	movwf	ANALOG_MODE
	movlw	B'00000110'
	movwf	MASK
	goto	Change_mode

To_analog_mode
	movlw	D'1'
	movwf	ANALOG_MODE
	movlw	B'00000000'
	movwf	MASK
	goto	Change_mode	; 無意味な goto だが将来コマンドが増えた場合に備える

Change_mode
	banksel	ADCON1		; bank 1
	movf	ADCON1,W
	andlw	B'11110000'	; Wreg <-- Wreg && 11110000
	banksel	MASK		; bank 0
	iorwf	MASK,W		; Wreg <-- Wreg || MASK
	banksel	ADCON1		; bank 1
	movwf	ADCON1
	banksel	00h			; bank 0
	call	Send_ACK
	goto	MAIN

;------------ アナログ入力処理 --------

Analog_input
	movf	ANALOG_MODE,W
	sublw	D'1'
	btfss	STATUS,Z
	goto	Mode_mismatch_error

	movf	INPUT_BUF_2nd,W		; 操作するビットを指定 '0'-'3'
	movwf	CONV_DAT
	call	Conv_ascii2binary
	movf	CONV_ERR,F
	btfss	STATUS,Z
	goto	Input_cha_error		; 指定ビットが数値でないときエラー
	movf	CONV_DAT,W

	movwf	INPUT_CH

	sublw	D'3'
	btfss	STATUS,C
	goto	A_IN_CH_ERROR	; INPUT_CH が 3 以下のとき処理を続ける

	movf	ADCON0,W	; Wreg <--- ADCON0
	andlw	B'11000111'
	movwf	BUF			; ADCON0 の bit 3-5 を除く部分を BUF に格納

	rlf		INPUT_CH,F	; 左へ 3 bit シフト
	rlf		INPUT_CH,F
	rlf		INPUT_CH,W	; 3 回目は Wreg に書く
	andlw	B'00111000'	; 念のため and をとっておく

	iorwf	BUF,W		; Wreg ← Wreg || BUF
	movwf	ADCON0		; ADチャンネル設定

;	チャンネル切り替え後 20μs 以上のディレイが必要

	call	DELAY20
	bsf		ADCON0,2	; AD 変換開始
AD_LOOP
	btfsc	ADCON0,2
	goto	AD_LOOP

;	結果を取り出す
;	上位 2 bit

	movf	ADRESH,W
	movwf	CONV_DAT
	call	Conv_binary2ascii
	movf	CONV_DAT,W
	movwf	DATA_HH

;	下位 8 bit

	banksel	ADRESL		; bank 1
	movf	ADRESL,W

	banksel	DATA_L		; bank 0
	movwf	DATA_L
	movwf	DATA_H
	swapf	DATA_H,F	; 上位　4 bit と下位 4 bit の入れ替え

	movlw	B'00001111'
	andwf	DATA_L,F
	andwf	DATA_H,F

	movf	DATA_H,W
	movwf	CONV_DAT
	call	Conv_binary2ascii
	movf	CONV_DAT,W
	movwf	DATA_H

	movf	DATA_L,W
	movwf	CONV_DAT
	call	Conv_binary2ascii
	movf	CONV_DAT,W
	movwf	DATA_L

	movlw	A'#'
	movwf	OUTPUT_BUF_TOP
	movf	DATA_HH,W
	movwf	OUTPUT_BUF_2nd
	movf	DATA_H,W
	movwf	OUTPUT_BUF_3rd
	movf	DATA_L,W
	movwf	OUTPUT_BUF_4th
	movlw	A'$'
	movwf	OUTPUT_BUF_5th

	call	Send_command

	goto	MAIN

A_IN_CH_ERROR
	movlw	D'5'
	movwf	ERR_CODE
	call	Disp_error
	goto	MAIN

Mode_mismatch_error
	movlw	D'7'
	movwf	ERR_CODE
	call	Disp_error
	goto	MAIN

;----------- デジタル入力処理 ------

Digital_input
	movf	ANALOG_MODE,W
	sublw	D'0'
	btfss	STATUS,Z
	goto	Mode_mismatch_error

	movf	INPUT_BUF_2nd,W
	sublw	A'a'				; 'a' のとき ch.0-3 を bitpattern
	btfsc	STATUS,Z			; で返す
	goto	Bitpattern_input

	movf	INPUT_BUF_2nd,W		; ch を指定 '0'-'3'
	movwf	CONV_DAT
	call	Conv_ascii2binary
	movf	CONV_ERR,F
	btfss	STATUS,Z
	goto	Input_cha_error		; ch が数値でないときエラー
	movf	CONV_DAT,W

	movwf	C1
	incf	C1,F

	sublw	D'3'
	btfss	STATUS,C
	goto	D_IN_CH_ERROR	; ch が 3 以下のとき処理を続ける

	movf	PORTA,W		; Wreg <--- PORTA
	movwf	BUF			; Wreg ---> BUF
D_IN
	rrf		BUF,F
	decfsz	C1,F
	goto	D_IN		; 目的のビットが carry に入るようシフト

	btfsc	STATUS,C
	goto	INPUT_IS_ONE
; Input = 0
	movlw	D'0'
	movwf	CONV_DAT
	goto	D_IN_2

INPUT_IS_ONE
	movlw	D'1'
	movwf	CONV_DAT

D_IN_2
	call	Conv_binary2ascii

	movlw	A'#'
	movwf	OUTPUT_BUF_TOP
	movf	CONV_DAT,W
	movwf	OUTPUT_BUF_2nd
	movlw	A'$'
	movwf	OUTPUT_BUF_3rd

	call	Send_command
	goto	MAIN

; 入力ポートのビットパターンを返す
; 入力は PORTA の下位 4 bit しか使ってないが、将来に備えて
; 8 bit 分を PC に送出する

Bitpattern_input
	banksel	PORTA
	movf	PORTA,W
	movwf	DATA_L	
	movwf	DATA_H
	swapf	DATA_H,F
	movlw	B'00001111'

	andwf	DATA_H,F
	andwf	DATA_L,F

	movf	DATA_H,W
	movwf	CONV_DAT
	call	Conv_binary2ascii
	movf	CONV_DAT,W
	movwf	DATA_H
	
	movf	DATA_L,W
	movwf	CONV_DAT
	call	Conv_binary2ascii
	movf	CONV_DAT,W
	movwf	DATA_L

	movlw	A'#'
	movwf	OUTPUT_BUF_TOP
	movf	DATA_H,W
	movwf	OUTPUT_BUF_2nd
	movf	DATA_L,W
	movwf	OUTPUT_BUF_3rd
	movlw	A'$'
	movwf	OUTPUT_BUF_4th

	call	Send_command
	goto	MAIN

D_IN_CH_ERROR
	movlw	D'4'
	movwf	ERR_CODE
	call	Disp_error
	goto	MAIN

;------------ デジタル出力 PORTC  bit 0～5 --------

Digital_output
	movf	INPUT_BUF_2nd,W
	sublw	A'a'				; 'a' は次の 2 文字でビットパターンを指定
	btfsc	STATUS,Z
	goto	Bitpattern_out

;   ---- 操作するビットと値が指定された場合 ---
	
	movf	INPUT_BUF_2nd,W		; 操作するビットを指定 '0'-'5'
	movwf	CONV_DAT
	call	Conv_ascii2binary
	movf	CONV_ERR,F
	btfss	STATUS,Z
	goto	Input_cha_error		; ビットが数値でないときエラー
	movf	CONV_DAT,W

	movwf	C1
	movwf	C2
	incf	C1,F
	incf	C2,F

	sublw	D'5'		; 5 - Wreg
	btfss	STATUS,C	; 0 または 正のとき C フラグが 1 になる
	goto	D_OUT_ERROR ; 6 以上のときエラー

;	入力された数値が 0, 1 であることをチェックする

	bsf		FLAG,0		; FLAG の 0 ビット目を 1 にする

	movlw	A'0'			; '0' かどうかチェックする
	subwf	INPUT_BUF_3rd,W
	btfsc	STATUS,Z
	bcf		FLAG,0

	movlw	A'1'			; '1' かどうかチェックする
	subwf	INPUT_BUF_3rd,W
	btfsc	STATUS,Z
	bcf		FLAG,0

	btfsc	FLAG,0			; '0' or '1' のとき bit 0 は 0
	goto	D_OUT_ERROR2

;	指定されたビットを指定された値に設定する

	movf	PORTC,W
	movwf	BUF			; PORTC --> BUF
D_OUT_1
	rrf		BUF,F
	decfsz	C1,F
	goto	D_OUT_1		; 目的のビットが carry に入るようシフト

	movlw	A'1'
	subwf	INPUT_BUF_3rd,W	; Wreg <--- 3rd - '1'
							; 0 か 正　で C=1
D_OUT_2
	rlf		BUF,F
	decfsz	C2,F
	goto	D_OUT_2		; 元に戻す

	movf	BUF,W
	movwf	PORTC
	call	Send_ACK
	goto	MAIN

D_OUT_ERROR
	movlw	D'3'
	movwf	ERR_CODE
	call	Disp_error
	goto	MAIN

D_OUT_ERROR2
	movlw	D'8'
	movwf	ERR_CODE
	call	Disp_error
	goto	MAIN

; ------　ビットパターンが指定された場合 ------

Bitpattern_out
	movf	INPUT_BUF_3rd,W		; 1 バイト目は bit 4-5
	movwf	CONV_DAT
	call	Conv_ascii2binary
	movf	CONV_ERR,F
	btfss	STATUS,Z
	goto	Input_cha_error
	movf	CONV_DAT,W
	andlw	B'00000011'			; 1 文字目は bit 4-5
	movwf	BUF
	rlf		BUF,F
	rlf		BUF,F
	rlf		BUF,F
	rlf		BUF,F				; 結果を BUF の bit 4,5 に格納
	movf	INPUT_BUF_4th,W		; 2 バイト目は bit 0-3
	movwf	CONV_DAT
	call	Conv_ascii2binary
	movf	CONV_ERR,F
	btfss	STATUS,Z
	goto	Input_cha_error
	movf	CONV_DAT,W
	andlw	B'00001111'			; 結果を Wreg の bit 0-3 に格納
	iorwf	BUF,W				; BUF との or をとり結果を Wreg に格納
	movwf	PORTC
	call	Send_ACK
	goto	MAIN

;----- 数値が来るべきとき (0-9,a-f) に数値でなかった場合のエラー処理

Input_cha_error
	movlw	10h
	movwf	ERR_CODE
	call	Disp_error
	goto	MAIN

;------- ACK を送る --------

Send_ACK
	movlw	OUTPUT_BUF_TOP
	movwf	FSR
	movlw	A'#'
	movwf	INDF
	incf	FSR,F
	movlw	A'O'
	movwf	INDF
	incf	FSR,F
	movlw	A'K'
	movwf	INDF
	incf	FSR,F
	movlw	A'$'
	movwf	INDF
	call	Send_command
	return

;------ CONV_DAT に入った文字をバイナリに変換する -----
;
;  0～9, A～F, a～f 以外の入力は CONV_ERR に　1 を入れてリターン

Conv_ascii2binary

	banksel	CONV_DAT
	movlw	D'0'
	movwf	CONV_ERR
	movlw	A'0'
	subwf	CONV_DAT,F		; まず '0' を引く
	btfss	STATUS,C
	goto	Conv_a2b_error	; 0 未満のときエラー

; この時点で 0～9, 17～22(A～F), 49～54(a～f) が入っている
; 10 未満のとき変換終了。それ以外のとき 17 を引く

	movlw	D'10'
	subwf	CONV_DAT,W
	btfss	STATUS,C
	goto	Conv_a2b_completed

	movlw	D'17'
	subwf	CONV_DAT,F
	btfss	STATUS,C
	goto	Conv_a2b_error	; 0 未満のときエラー

; この時点で 6 未満のとき 10 を足して変換終了

	movlw	D'6'
	subwf	CONV_DAT,W
	btfss	STATUS,C
	goto	Conv_a2b_plus10

; それ以外のとき小文字なので、さらに 32 を引く

	movlw	D'32'
	subwf	CONV_DAT,F
	btfss	STATUS,C
	goto	Conv_a2b_error	; 0 未満のときエラー

; この時点で 6 未満のとき 10 を足して変換終了

	movlw	D'6'
	subwf	CONV_DAT,W
	btfss	STATUS,C
	goto	Conv_a2b_plus10

Conv_a2b_error
	movlw	D'1'
	movwf	CONV_ERR
	goto	Conv_a2b_completed
Conv_a2b_plus10
	movlw	D'10'
	addwf	CONV_DAT,F		; CONV_DAT <-- Wreg + CONV_DAT
Conv_a2b_completed
	return

;------ CONV_DAT に入った数値を　ascii に変換する -----
;
;  入力として 0～f 以外の値が来たときは CONV_DAT = 'x' とし、
;  CONV_ERR を　1 にする
;
;  本プログラム中で CONV_ERR のチェックはしていない（さぼっている）。
;  パソコン側でエラーチェックするか？

Conv_binary2ascii
	banksel	CONV_DAT

	movlw	D'0'
	movwf	CONV_ERR

	movlw	D'16'
	subwf	CONV_DAT,W	; Wreg <--- CONV_DAT - 16
	btfsc	STATUS,C
	goto	Conv_b2a_error

	movlw	D'10'
	subwf	CONV_DAT,W	; Wreg ← CONV_DAT - Wreg
						; 0 か 正 のとき　C=1 (10以上のとき)
	btfss	STATUS,C		
	goto	ZERO_TO_NINE
;	a～f
	movlw	D'87'
	addwf	CONV_DAT,F
	goto	Conv_b2a_end
ZERO_TO_NINE
	movlw	D'48'
	addwf	CONV_DAT,F
	goto	Conv_b2a_end
Conv_b2a_error
	movlw	D'1'
	movwf	CONV_ERR
	movlw	A'x'
	movwf	CONV_DAT
Conv_b2a_end
	return

;------- PORTB bit7 を点滅させ、エラーコードを bit 0-6 に表示する --------

Disp_warning
	banksel	00h

	movf	ERR_CODE,W
	movwf	PORTB

	movlw	D'3'
	movwf	C1
E1
	bsf		PORTB,7
	call	DELAY500
	bcf		PORTB,7
	call	DELAY500
	decfsz	C1,F
	goto	E1

	return

;------- PORTB bit7 を点滅させる --------

Disp_notice
	banksel	00h

	movlw	D'3'
	movwf	C1
E11
	bsf		PORTB,7
	call	DELAY200
	bcf		PORTB,7
	call	DELAY200
	decfsz	C1,F
	goto	E11

	return

;------ LED を点滅させ、エラーコード表示 ---------
;       RS-232C に "#E?$" を送る

Disp_error
	banksel	00h

;	call	Disp_warning

	movf	ERR_CODE,W
	movwf	DATA_L
	movwf	DATA_H
	swapf	DATA_H,F	; 上位　4 bit と下位 4 bit の入れ替え

	movlw	B'00001111'
	andwf	DATA_L,F
	andwf	DATA_H,F

	movf	DATA_H,W
	movwf	CONV_DAT
	call	Conv_binary2ascii
	movf	CONV_DAT,W
	movwf	DATA_H

	movf	DATA_L,W
	movwf	CONV_DAT
	call	Conv_binary2ascii
	movf	CONV_DAT,W
	movwf	DATA_L

	movlw	A'#'
	movwf	OUTPUT_BUF_TOP
	movlw	A'E'
	movwf	OUTPUT_BUF_2nd
	movf	DATA_H,W
	movwf	OUTPUT_BUF_3rd
	movf	DATA_L,W
	movwf	OUTPUT_BUF_4th
	movlw	A'$'
	movwf	OUTPUT_BUF_5th
	call	Send_command

	return

;--------- コマンドの送信 　先頭は 0x30　--------
;          0x30 は '#', 最後の文字は '$'
;
Send_command	
	movlw	OUTPUT_BUF_TOP
	movwf	FSR

TX_LOOP
	banksel	TXSTA		; bank 1
	btfss	TXSTA,TRMT	; 送信バッファをチェック  1=empty  0=full
	goto	TX_LOOP		; 空になるまで待つ

	banksel	00h			; bank 0
	movf	INDF,W
	movwf	TXREG		; TXREG に入れると送出する
	incf	FSR,F

	sublw	A'$'		; $ を見つけたら終了
	btfsc	STATUS,Z
	goto	Send_end

	movf	FSR,W
	sublw	OUTPUT_BUF_END	; 出力用バッファの最後を超えたが $ がない
	btfsc	STATUS,C
	goto	TX_LOOP	

;	出力用バッファの最後に $ がないとき以下を実行する。
;   この場所へ来たと言うことは、本プログラム中にバグがある
;	出力文字列の最後に "Err$" を付加して送る。

	movlw	A'E'
	movwf	SEND_BUF
	call	Send_1byte
	movlw	A'r'
	movwf	SEND_BUF
	call	Send_1byte
	movlw	A'r'
	movwf	SEND_BUF
	call	Send_1byte
	movlw	A'$'
	movwf	SEND_BUF
	call	Send_1byte

Send_end
	return

;--------- SEND_BUF に入れた 1 バイトを送信する ----------

Send_1byte
	banksel	TXSTA		; bank 1
TX_LOOP2
	btfss	TXSTA,TRMT	; 送信バッファをチェック  1=empty  0=full
	goto	TX_LOOP2	; 空になるまで待つ
	banksel	SEND_BUF
	movf	SEND_BUF,W
	movwf	TXREG
	return

;--------- 1 バイト受信して RECV_BUF に入れる　---------
;
;	PIC のバッファは 2 byte しかない。 Disp_warning などを実行時に
;	PC から 3 バイト送ると、オーバーランエラーのフラグが立つ。
;
;	フラグをクリアするには RCSTA　のビット CREN を 0 --> 1 とセットする。
;
;	フラグのクリアを怠って順番に読み出すと
;
;   1 byte 目 ---> 2 byte 目 ---> 2 byte 目 ---> 2 byte 目
;
;	となり、永遠に 2 byte 目が読み出され、新しいデータを読み込めない。
;
;	フラグをクリアしてから順番に読み出すと
;
;	1 byte 目 ---> 2 byte 目 ---> 次のデータ
;
;	となり、3 バイト目は失われた状態で読み込みが起こる。
;
;	本ルーチンではオーバーランエラーが発生した場合、何らかのデータが失われたと
;	考えられるので、バッファをクリアして RECV_BUF に ? を入れて戻る。
;
;	しかし、RECV_BUF 内のデータが ? か否かを上位のルーチンでチェックしていない。

Recv_1byte
	banksel	PIR1		; bank 0
	btfss	PIR1,RCIF	; 受信バッファ 0=empty  1=full
	goto	Recv_1byte

	btfsc	RCSTA,FERR	; フレーミングエラーの検知
	goto	Recv_frame_err

	btfsc	RCSTA,OERR	; オーバーランエラーの検知
	goto	Recv_overrun_err

	movf	RCREG,W
	movwf	RECV_BUF

	goto	Recv_1byte_end
;
;	フレーミングエラー、オーバーランエラーのエラー処理は 
;	後閑哲也氏の PIC16F 活用ガイドブック p.264 を参考にした
;
Recv_frame_err
	movf	RCREG,W		; エラー発生のデータを読み出す
	movlw	A'?'		; 代わりに ? を入れる
	movwf	RECV_BUF
	btfss	RCSTA,OERR	; オーバーランエラーもあるか
	goto	Recv_overrun_err
	goto	Recv_1byte_end

Recv_overrun_err
	bcf		RCSTA,CREN	; オーバーランエラーのクリア方法は CREN を
	bsf		RCSTA,CREN	; 0 --> 1 する

	movf	RCREG,W		; 2 回読み出してバッファを空にする
	movf	RCREG,W
	movlw	A'?'		; 代わりに ? を入れる
	movwf	RECV_BUF

;	RECV_BUF に入れたデータを PORTB bit 0-6 に表示

Recv_1byte_end
	movf	PORTB,W
	andlw	B'10000000'	; PORTB の bit 7 を BUF に格納
	movwf	BUF
	movf	RECV_BUF,W
	andlw	B'01111111'	; 受信文字の下位 7 bit を Wreg に格納
	iorwf	BUF,W		; Wreg <-- BUF || Wreg
	movwf	PORTB

	return

;-------- LED のテスト -----------

LED_test
	banksel	PORTB
BLINK
	movlw	B'10101010'
	movwf	PORTB
	call	DELAY500
	movlw	B'01010101'
	movwf	PORTB
	call	DELAY500
	goto	BLINK

;------- ディレイ 20 MHz 用　-------------

; 0.2ms
DELAY0_2
	movlw	D'250'
	movwf	T1
DLOOP1
	nop
	decfsz	T1,F
	goto	DLOOP1
	return

;　20ms
DELAY20
	movlw	D'100'
	movwf	T2
DLOOP20
	call	DELAY0_2
	decfsz	T2,F
	goto	DLOOP20
	return

;　50ms
DELAY50
	movlw	D'250'
	movwf	T2
DLOOP21
	call	DELAY0_2
	decfsz	T2,F
	goto	DLOOP21
	return

; 200ms
DELAY200
	movlw	D'4'
	movwf	T3
DLOOP30
	call	DELAY50
	decfsz	T3,F
	goto	DLOOP30
	return

; 500ms
DELAY500
	movlw	D'10'
	movwf	T3
DLOOP31
	call	DELAY50
	decfsz	T3,F
	goto	DLOOP31
	return

; 2s
DELAY2S
	movlw	D'20'
	movwf	T3
DLOOP32
	call	DELAY50
	decfsz	T3,F
	goto	DLOOP32
	return

;-------　Conv_binary2ascii のルーチンのチェック --------

CHECK_CONV

	movlw	D'0'
	movwf	C1
LL
	movf	C1,W

	movwf	DATA_L
	movwf	DATA_H
	swapf	DATA_H,F		; 上位　4 bit と下位 4 bit の入れ替え

	movlw	B'00001111'
	andwf	DATA_L,F
	andwf	DATA_H,F

	movf	DATA_H,W
	movwf	CONV_DAT
	call	Conv_binary2ascii
	movf	CONV_DAT,W
	movwf	DATA_H

	movf	DATA_L,W
	movwf	CONV_DAT
	call	Conv_binary2ascii
	movf	CONV_DAT,W
	movwf	DATA_L

	movlw	A'#'
	movwf	OUTPUT_BUF_TOP
	movf	DATA_H,W
	movwf	OUTPUT_BUF_2nd
	movf	DATA_L,W
	movwf	OUTPUT_BUF_3rd
	movlw	A'$'
	movwf	OUTPUT_BUF_4th

	call	Send_command

	call	DELAY500
	incf	C1,F

	goto	LL

CHECK_CONV2

	movlw	D'0'
	movwf	C1
LL2
	movf	C1,W
	movwf	CONV_DAT
	call	Conv_binary2ascii
	movf	CONV_DAT,W
	movwf	SEND_BUF
	call	Send_1byte
	call	DELAY500
	incf	C1,F
	goto	LL2
	
	END
