;**********************************************************************
;  TempLan28  May 4th 2006
;  LM35DZ 用の　ゼロ点補正（約20mV)を含む
;  AD変換値から20(0x14)を単純に２バイト減算する
;**********************************************************************
	list      p=16f873a
	#include <p16f873a.inc>

	__CONFIG _CP_OFF & _WDT_OFF & _BODEN_ON & _PWRTE_ON & _HS_OSC & _WRT_OFF & _LVP_OFF & _CPD_OFF

w_temp		EQU	0x20 
status_temp	EQU	0x21
CNT1		EQU	0x22
CNT2		EQU	0x23
CNT3		EQU	0x24
TMP_DATA	EQU	0x25
TMP_DATA_B	EQU	0x26 ; busyチェック用
TMP_CNT		EQU	0x27
CCNT		EQU	0x28 ; 文字数カウンタ
LCNT		EQU	0x29 ; 行番号フラグ
TMP_CHR		EQU	0x2a
TMP_ADD		EQU	0x2b

H_comp		EQU	0x2c ;LM35DZ温度補正値(上位バイト)
L_comp		EQU	0x2d ;LM35DZ温度補正値(下位バイト)

;バイナリ->BCD変換用
count		EQU	0x30
temp		EQU	0x31
H_byte		EQU	0x32
L_byte		EQU	0x33
R0		EQU	0x34
R1		EQU	0x35
R2		EQU	0x36

TXTEMP		EQU	0x37
TXDT_1		EQU	0x38
TXDT_2		EQU	0x39
TXDT_3		EQU	0x3a


;Symbols For LCD
#define	LCD_DATA	PORTB
#define	LCD_DDIR	TRISB
#define	LCD_RS		PORTB,0
#define	LCD_RW		PORTB,1
#define	LCD_E		PORTB,2
#define	BUSY_BIT	7

#define	ROWS		d'16' ; 横方向は16文字

#define Hcomp		0
#define Lcomp		d'20' ; 20mV
;**********************************************************************
		ORG     0x000             ; processor reset vector
		clrf    PCLATH            ; ensure page bits are cleared
  		goto    main              ; go to beginning of program


		ORG		0x004             ; interrupt vector location
		movwf		w_temp            ; save off current W register contents
		movf		STATUS,w          ; move status register into W register
		bcf			STATUS,RP0        ; ensure file register bank set to 0
		movwf		status_temp       ; save off contents of STATUS register


; isr code can go here or be located as a call subroutine elsewhere


		bcf			STATUS,RP0        ; ensure file register bank set to 0
		movf		status_temp,w     ; retrieve copy of STATUS register
		movwf		STATUS            ; restore pre-isr STATUS register contents
		swapf		w_temp,f
		swapf		w_temp,w          ; restore pre-isr W register contents
		retfie                    ; return from interrupt

main

		call		dly_10m	  ; 周辺待ち

		bcf			STATUS,RP0
		bcf			STATUS,RP1 ; バンク0に設定

		clrf		INTCON ; 割り込みを禁止

;***********************************************************
;       初期化
;***********************************************************

		bsf			STATUS,RP0 ; バンク1に設定

		movlw		b'10111111'	; RC7/RX（入力），RC6/TX（出力）
		movwf		TRISC		; PORTC の設定
		clrf		LCD_DDIR  ; LCDデータポートを出力に

		clrf		PORTA
		movlw		b'11111111'
		movwf		TRISA	   ; PORTAを入力に
		
		movlw		b'00100100'	; 8BIT,送信許可,非同期,高速
		movwf		TXSTA		; TXSTA レジスタの設定
		movlw		81H			; ボーレート 9600bps (20MHz：高速設定時)
		movwf		SPBRG		; SPBRG レジスタの設定
		bcf			STATUS,RP0	; Bank 0 へ戻す
		movlw		b'10010000'	; シリアル,8BIT,継続受信許可
		movwf		RCSTA		; RCSTA レジスタの設定

		; A/Dコンバータ設定
		movlw		b'11000001'
		movwf		ADCON0
		bsf			STATUS,RP0  ; bank1
		movlw		b'10000000' ; ADFM=0,VREF=Vcc
		movwf		ADCON1
		bcf			STATUS,RP0  ; bank0

		bcf			LCD_RS    ;
		bcf			LCD_RW    ; LCDの制御信号をゼロに
		bcf			LCD_E     ;
		clrf		LCD_DATA  ;

		movlw		Lcomp
		movwf		L_comp
		movlw		Hcomp
		movwf		H_comp

main_init
		call		dly_10m   ; 念のため10mS待つ
		call		lcd_init  ; LCD初期化
		call		dly_10m

		movlw		b'00001100' ;カーソルオフ、左から右へ表示
		call		cmd_send
		call		dly_10m
		clrf		CCNT      ; キャラクタ数カウンタをリセット
		clrf		LCNT      ; 行フラグをリセット

		clrf		TMP_CNT   ; テンポラリカウンタをクリア
str_out1
		movf		TMP_CNT,w  ;文字列出力
		call		INIT_MSG
		addlw		0x00      ;ゼロだったなら終了
		btfsc		STATUS,Z
		goto		msg_out
		call		chr_out
		incf		TMP_CNT,1
		goto		str_out1

msg_out
		movlw		d'100'
		movwf		TMP_CNT  ;初期メッセージ1秒表示
msg_loop
		call		dly_10m  
		decfsz		TMP_CNT,1;初期メッセージ表示遅延
		goto		msg_loop

		call		disp_clr ;表示クリア

adc_loop
		bsf			STATUS,RP0  ; bank1
		movlw		b'10000000' ; ADFM=0,VREF=Vcc
		movwf		ADCON1
		bcf			STATUS,RP0  ; bank0

		movlw		b'11000101' ;ADC CH0 ON & GO
		movwf		ADCON0
adc_loop1
		btfsc		ADCON0,GO  ; A/D変換待ち
		goto		adc_loop1
		bsf			STATUS,RP0 ; Bank=1
		movf		ADRESL,w
		bcf			STATUS,RP0 ; Bank=0
		movwf		L_byte     ; 下位バイト取り込み
		rrf			L_byte,f   ; 右ローテートで1/2する
		bcf			STATUS,C   ; キャリー無視
		movf		ADRESH,w   ; 上位バイト取り込み
		movwf		H_byte
		rrf			H_byte,f   ; 右ローテートで1/2する
		btfss		STATUS,C   ; キャリーが立っているか？
		goto		adc_do2
		movlw		b'10000000'
		iorwf		L_byte,f   ; キャリーがあれば1桁下げ
		
adc_do2


		movf		L_comp,0
		subwf		L_byte,1
		btfss		3h,0
		decf		H_byte,1
		movf		H_comp,0
		subwf		H_byte,1


		call		B2_BCD

		call		disp_clr

		movlw		0x20
		call		chr_out
		movlw		0x20
		call		chr_out

		swapf		R1,w
		andlw		0x0f
		movlw		0x20
		call		chr_out
		movf		R1,w
		andlw		0x0f
		call		BINHEX
		movwf		TXDT_1
		call		chr_out

		swapf		R2,w
		andlw		0x0f
		call		BINHEX
		movwf		TXDT_2
		call		chr_out

		movlw		0x2e
		call		chr_out

		movf		R2,w
		andlw		0x0f
		call		BINHEX
		movwf		TXDT_3
		call		chr_out


		movlw		0xdf
		call		chr_out
		movlw		0x43
		call		chr_out

;***********************************************************
; Data 転送
;***********************************************************

TEXT
		movf		TXDT_1,w
		call		TX

		movf		TXDT_2,w
		call		TX

		movlw		0x2e
		call		TX

		movf		TXDT_3,w
		call		TX

		movlw		0x0d
		call		TX

text_sdend
		movlw		d'100'
		movwf		TMP_CNT
msg_loop2
		call		dly_10m
		decfsz		TMP_CNT,f
		goto		msg_loop2

		goto		adc_loop


;***********************************************************
; 送信サブルーチン
; TRMT=1で送信可
;***********************************************************

TX
		movwf	TXTEMP		; 送信するデータを変数（TXTEMP）に格納
		bsf		STATUS,RP0	; Bank 1 へ切替
LPTX						;
		btfss	TXSTA,TRMT	; 送信可能であるかチェック（1:可能, 0:禁止）
		goto	LPTX		; 禁止であれば LPTX のラベル間を繰り返す
							;
		bcf		STATUS,RP0	; Bank 0 へ戻す
		movf	TXTEMP,W	; 変数（TXTEMP）に格納していた送信データをWregにロード
		movwf	TXREG		; 送信データはTXREGレジスタを通してシリアル出力される
		return				; メインルーチンへ戻る


;表示クリア
disp_clr
		movlw		b'00000001'
		call		cmd_send ; 表示クリア
		clrf		CCNT
		clrf		LCNT
		return

; 1文字出力
; wに表示したい文字をセット
chr_out
		call		data_send
		incf		CCNT,f ;出力した文字数を+1
		movlw		ROWS
		subwf		CCNT,w ;もしもROWSと同じになったら
		btfss		STATUS,Z
		goto		chr_done ; ROWSと同じではないので終了
line_chg
		clrf		CCNT  ;文字数カウンタをリセット
		btfss		LCNT,0 ; 現在は1行目か？
		goto		chr_ld1
		movlw		b'10000000';1行目にアドレスをセット
		call		cmd_send
		bcf			LCNT,0
		goto		chr_done
chr_ld1					; 2行目にアドレスをセット
		movlw		b'11000000'
		call		cmd_send
		bsf			LCNT,0
chr_done
		return

INIT_MSG
		addwf		PCL,1
		DT	"TempLan INIT.OK!",0x00	
BINHEX
		addwf		PCL,1
		DT	"0123456789ABCDEF",0x00

; 液晶を初期化
; 4bitモード
lcd_init
		call		dly_10m
		call		dly_10m
		movlw		b'00110000' ;初期化データ1 
		call		cmd_send4
		call		dly_10m
		movlw		b'00110000' ;初期化データ2
		call		cmd_send4
		call		dly_10m
		movlw		b'00110000' ;初期化データ3
		call		cmd_send4
		call		dly_100u
		movlw		b'00100000' ;4bitモードにセット
		call		cmd_send4
		call		dly_100u
		call		busy_check

		movlw		b'00101000' ;初期モード設定
		call		cmd_send

		movlw		b'00001000' ;ディスプレイオフ
		call		cmd_send

		movlw		b'00000001' ;液晶をクリア
		call		cmd_send

		movlw		b'00000110' ;エントリモードをセット
		call		cmd_send

		return

; 液晶にコマンドを送出
; wレジスタ=コマンド
; Fレジスタ: TMP_DATA
cmd_send	; CMD=w
		movwf		TMP_DATA
		andlw		0xf0
		movwf		LCD_DATA
		bcf			LCD_RW
		bcf			LCD_RS
		bsf			LCD_E
		nop
		nop
		bcf			LCD_E
		swapf		TMP_DATA,w
		andlw		0xf0
		movwf		LCD_DATA
		bcf			LCD_RW
		bcf			LCD_RS
		bsf			LCD_E
		nop
		nop
		bcf			LCD_E
		call		busy_check

		return

; 初期化用4bit幅コマンド送出
; wレジスタ=コマンド(上位4bit)
; Fレジスタ : TMP_DATA
; ビジーチェックできない期間用
cmd_send4
		movwf		TMP_DATA
		andlw		0xf0
		movwf		LCD_DATA
		bcf			LCD_RW
		bcf			LCD_RS
		bsf			LCD_E
		nop
		nop
		bcf			LCD_E

		return


; 液晶にデータを送出
; wレジスタ=データ
; Fレジスタ: TMP_DATA
data_send
		movwf		TMP_DATA
		andlw		0xf0
		movwf		LCD_DATA
		bcf			LCD_RW
		bsf			LCD_RS
		bsf			LCD_E
		nop
		nop
		bcf			LCD_E
		swapf		TMP_DATA,w
		andlw		0xf0
		movwf		LCD_DATA
		bcf			LCD_RW
		bsf			LCD_RS
		bsf			LCD_E
		nop
		nop
		bcf			LCD_E
		call		busy_check

		return

; 液晶ビジーチェック
; Fレジスタ:TMP_DATA_B
busy_check
		bsf			STATUS,RP0 ; bank=1
		movlw		0xf0
		movwf		LCD_DDIR
		bcf			STATUS,RP0 ; bank=0
busy_chk1
		bcf			LCD_RS
		bsf			LCD_RW
		bsf			LCD_E
		nop
		movf		LCD_DATA,w
		andlw		0xf0
		movwf		TMP_DATA_B
		bcf			LCD_E
		nop
		nop
		bsf			LCD_E
		nop			 			 ; 下位4ビットは無視
		nop
		bcf			LCD_E
		btfsc		TMP_DATA_B,BUSY_BIT
		goto		busy_chk1
		bcf			LCD_RW
		bsf			STATUS,RP0 ; bank=1
		movlw		0x00
		movwf		LCD_DDIR
		bcf			STATUS,RP0 ; bank=0
		return

;時間遅延ルーチン クロック20MHz用

; 100マイクロ秒遅延
; Fレジスタ: CNT1
dly_100u	; 100uS
		movlw		d'100'
		movwf		CNT1
dly_100u1
		nop
		nop			; 1uS@1path
		nop
		nop
		decfsz		CNT1,f
		goto		dly_100u1
		return

; 10ミリ秒遅延
; Fレジスタ:CNT1
dly_10m	; 10mS
		movlw		d'10'
		movwf		CNT1
dly_10m1
		call		dly_1m
		decfsz		CNT1,f
		goto		dly_10m1
		return

; 1ミリ秒遅延
; Fレジスタ:CNT2,3
dly_1m	; 1ms
		movlw		d'4'
		movwf		CNT2
dly_1m1
		movlw		d'250'
		movwf		CNT3
dly_1m2				; 250us Loop
		nop
		nop
		nop
		nop
		decfsz		CNT3,f
		goto		dly_1m2
		decfsz		CNT2,f
		goto		dly_1m1
		return

; バイナリ->BCD変換ルーチン
; Microchip アプリケーションノート AN526より

B2_BCD
		bcf			STATUS,0
		movlw		.16
		movwf		count
		clrf		R0
		clrf		R1
		clrf		R2
loop16
		rlf			L_byte,F
		rlf			H_byte,F
		rlf			R2,F
		rlf			R1,F
		rlf			R0,F

		decfsz		count,F
		goto		adjDEC
		retlw		0

adjDEC
		movlw		R2
		movwf		FSR
		call		adjBCD

		movlw		R1
		movwf		FSR
		call		adjBCD

		movlw		R0
		movwf		FSR
		call		adjBCD

		goto		loop16

adjBCD
		movlw		3
		addwf		0,W
		movwf		temp
		btfsc		temp,3
		movwf		0
		movlw		30
		addwf		0,W
		movwf		temp
		btfsc		temp,7
		movwf		0
		retlw		0

		END
