2026年2月22日日曜日

TOFセンサとPICで作った近接スイッチプロトタイプ

ToFセンサVL6180とPIC12F629を使った近接スイッチのプロトタイプができました。以下、動作の様子、42秒ほどの短い動画です。

点灯している赤色LEDの代わりにSSR(Solid State Relay)を繋ぐことでLED照明のスイッチにします。

以下、ソースコードです。バグがあるかも知れません。無保証です。

VL6180Xの初期化とコンフィグはarduinoライブラリのソースを参考にしていますが、これで十分なのか過剰なのか理解できていません。データシートが英語で87ページもあって全ては読めませんでした。読んでも理解できたか不明ですが。一応動いているようなので趣味で使うにはOKとしてます。

;---------------------------------------------------------------------
; TOF近接センサVL6180Xを使った非接触スイッチ
;
;                                                      2026.02.22 naka
;  1. 概要
;     近接センサの前で手をかざすとオンオフ動作するスイッチ
;     ・距離は150mm位まではOK(動作確認時190mm程度までは反応した)#defineで設定
;     ・スイッチ動作はオルタネート(一度近づくとオン、一旦離れてもう一度でオフ)
;     ・距離測定は0.1秒毎、オンオフ動作時は1秒後に確認(チャタリング的な動作を避けるため)
;
;  2. ピンアサイン
;
;    (1). GP0  [in] : (ICSP DAT)
;    (2). GP1  [in] : (ICSP CLK)
;    (3). GP2  [out]: LED(デバッグ時に使用;最終的にSSRに置き換える)
;    (4). GP3  [in] : (ICSP VPP)
;    (5). GP4  [in] : I2C SDA
;    (6). GP5  [in] : I2C SCL
;
; 3. 備考
;   ・動作クロック :内蔵OSC 4MHz
;   ・電源         :3V(TOFセンサが2.8-3.0Vなので)
;
; 4. 改版履歴
;    2026.02.14 new
;    2026.02.22 色々修正
;
;---------------------------------------------------------------------
;---------------------------------------------------------------------
;  デバイス定義
;---------------------------------------------------------------------
	list    P=12F629
	include <P12F629.INC>
	__config _INTRC_OSC_NOCLKOUT & _WDT_OFF & _PWRTE_ON & _MCLRE_OFF & _BODEN_OFF & _CP_OFF
	ERRORLEVEL	-302	;アセンブル時のバンク警告メッセージ抑制

;---------------------------------------------------------------------
;  ピン定義
;---------------------------------------------------------------------
#define	LED	2
#define	SDA	4
#define	SCL	5

;---------------------------------------------------------------------
;  TOFセンサ VL6180X I2Cアドレス
;---------------------------------------------------------------------
#define TOFADDR	0x52

;---------------------------------------------------------------------
;  TOFセンサが反応する距離(mm) これより近いとオン/オフする
;---------------------------------------------------------------------
#define ACTDIST	D'150'

;---------------------------------------------------------------------
;  変数レジスタの定義
;---------------------------------------------------------------------
WAIT1	EQU	H'20'
WAIT2	EQU	H'21'
CNT	EQU	H'22'
TMP	EQU	H'23'
CNT1	EQU	H'24'
CNT2	EQU	H'25'
CNT3	EQU	H'26'
BUFF	EQU	H'27'	; 27-2B (LCD 5文字分)
;
binH	EQU	H'30'
binL	EQU	H'31'
bcdH	EQU	H'32'
bcdM	EQU	H'33'
bcdL	EQU	H'34'
counter	EQU	H'35'
temp	EQU	H'36'
;
OFFSET	EQU	H'37'
RANGE	EQU	H'38'
TIMOUTH	EQU	H'39'
TIMOUTL	EQU	H'3A'
TOGGLE	EQU	H'3B'	; 0ビット:トグル、1ビット:前回状態
; H'40'からI2C通信に利用(下の方で定義)
;
;---------------------------------------------------------------------
;  マクロ
;---------------------------------------------------------------------
	; TOFセンサ8ビットレジスタ設定
	
REG8BIT	MACRO	IDXH,IDXL,DATA
	RETLW	IDXH
	RETLW	IDXL
	RETLW	DATA
	ENDM
	
	; TOFセンサ16ビットレジスタ設定
REG16BIT MACRO	IDXH,IDXL,DATAH,DATAL
	RETLW	IDXH
	RETLW	IDXL
	RETLW	DATAH
	RETLW	DATAL
	ENDM
	;
	; TOFセンサレジスタ書き込み
WTREG	MACRO	HIGH,LOW,DATA
	MOVLW	TOFADDR
	CALL	I2CWSTART
	MOVLW	HIGH
	MOVWF	datao
	CALL	TX
	MOVLW	LOW
	MOVWF	datao
	CALL	TX
	MOVLW	DATA
	MOVWF	datao
	CALL	TX
	CALL	I2CSTOP
	ENDM

RDREG	MACRO	HIGH,LOW
	MOVLW	TOFADDR
	CALL	I2CWSTART
	MOVLW	HIGH
	MOVWF	datao
	CALL	TX
	MOVLW	LOW
	MOVWF	datao
	CALL	TX
	CALL	I2CSTOP
	;
	MOVLW	TOFADDR
	CALL	I2CRSTART
	CALL	RX
	CALL	I2CSTOP
	ENDM
	;
;---------------------------------------------------------------------
;  リセットベクタ
;---------------------------------------------------------------------
	ORG	00H		; リセット時の飛び込み先
	GOTO	MAIN		;
	;
	ORG	04H		; 割り込み時の飛び込み先
;---------------------------------------------------------------------
;  割り込み処理
;---------------------------------------------------------------------
INTRUPT
	RETFIE
;---------------------------------------------------------------------
;  メイン処理
;---------------------------------------------------------------------
MAIN
	CALL	DEVINIT
	CALL	LCDINIT
	;
	CALL	VL6180INIT
	CALL	VL6180CONFIG
	;
	MOVLW	D'255'
	CALL	DSPLCD
	;
	CLRF	TOGGLE
MAIN_LP
	;
	CLRF	RANGE
	CALL	READRANGE	; 測定
	;
	MOVF	RANGE,W
	SUBLW	ACTDIST		; アクティブか否かチェック
	BTFSS	STATUS,C
	GOTO	INACT
	; 前回もアクティブなら何もしない(そうしないと点滅する)
	BTFSC	TOGGLE,1
	GOTO	MAININTR
	BSF	TOGGLE,1	; 前回アクティブではないのでトグル動作
	GOTO	TOGGLESW
	;
INACT
	BCF	TOGGLE,1
	GOTO	MAININTR

TOGGLESW
	MOVF	TOGGLE,W
	XORLW	H'01'
	MOVWF	TOGGLE
	;
	BTFSS	TOGGLE,0
	GOTO	$+3
	BSF	GPIO,LED
	GOTO	$+2
	BCF	GPIO,LED
	;
	MOVF	RANGE,W
	CALL	DSPLCD		; LCD表示
	;
	CALL	W05S		; トグル動作時は1秒待つ
	CALL	W05S
	GOTO	MAIN_LP
	;
MAININTR
	CALL	W100MS		; 100ミリ秒ごとに測定
	GOTO	MAIN_LP
	;
;---------------------------------------------------------------------
;  初期化
;---------------------------------------------------------------------
DEVINIT
	CLRF	INTCON		;全割込み禁止
	;
	BANKSEL CMCON
	MOVLW	B'00000111'	; GP0-2をデジタルI/Oに設定
	MOVWF	CMCON		; デフォルトはコンパレータ

;	BANKSEL	1
;	CALL	3FFH		; 内部OSCのキャリブレーションデータ
;	MOVWF	OSCCAL		; OSCCALレジスタにセット

	BANKSEL	TRISIO
	MOVLW	B'00000011'	; RA0,RA1 input
	MOVWF	TRISIO
	BANKSEL GPIO
	;
	BCF	GPIO,LED
	;
	RETURN
	;
;---------------------------------------------------------------------
;  文字列表示
;---------------------------------------------------------------------
DSPTXT
	MOVLW	D'5'
	MOVWF	CNT
	CLRF	TMP
	MOVLW	BUFF
	MOVWF	FSR
	;
	MOVLW	H'80' + H'0B'	; LCD1行目先頭へ
	CALL	LCDCMD
DSPTXTLP
	MOVF	CNT,W
DSPTXT1
	MOVF	INDF,W
	CALL	LCDDATA
	INCF	FSR,F
	;
	DECFSZ	CNT,F
	GOTO	DSPTXTLP
	;
	RETURN
;---------------------------------------------------------------------
;  LCD初期化(データシート通り)
;---------------------------------------------------------------------
LCDINIT
	CALL	W20MS		; 電源が安定するまでの待ち時間
	CALL	W20MS
	;
	MOVLW	H'38'		; Function set
	CALL	LCDCMD
	;
	MOVLW	H'39'		; Functino set
	CALL	LCDCMD
	;
	MOVLW	H'14'		; Intrenal OSC frequency
	CALL	LCDCMD
	;
	;			; Contrast= B'10 1000' = D'40'
	MOVLW	H'70'+H'08'	; Contrast set
	CALL	LCDCMD
	;
	MOVLW	H'54'+H'02'	; Power/ICON/Contrast control
;	MOVLW	H'51'		; +5V
	CALL	LCDCMD
	;
	MOVLW	H'6C'		; Follower control
	CALL	LCDCMD
	CALL	W200MS
	;
	MOVLW	H'38'		; Function set
	CALL	LCDCMD
	;
	MOVLW	H'0C' + H'01'	; Display ON/OFF control
	CALL	LCDCMD
	;
	MOVLW	H'01'		; Clear Display
	CALL	LCDCMD
	;
	RETURN
	;
;---------------------------------------------------------------------
;  LCDコマンド (W:CMD)
;---------------------------------------------------------------------
LCDCMD
	MOVWF	TMP		; 一時退避
	;
	MOVLW	H'7C'		; I2Cアドレス
	CALL	I2CWSTART
	MOVLW	H'00'		; Command (RS=0)
	MOVWF	datao
	CALL	TX
	MOVF	TMP,W
	MOVWF	datao
	CALL	TX
	CALL	I2CSTOP
	;
	MOVLW	H'01'		; Clear Display
	SUBWF	TMP,W
	BTFSC	STATUS,Z
	GOTO	LCDW1MS
	MOVLW	H'02'		; Return Home
	SUBWF	TMP,W
	BTFSC	STATUS,Z
	GOTO	LCDW1MS
	;
	CALL	W27US		; Normal command
	RETURN
LCDW1MS
	CALL	W1MS
	RETURN
	;
;---------------------------------------------------------------------
;  LCD データ(Wレジ内容をLCDに書き込む)
;---------------------------------------------------------------------
LCDDATA
	MOVWF	TMP		; 書き込みデータ一時退避
	;
	MOVLW	H'7C'
	CALL	I2CWSTART
	;
	MOVLW	H'40'		; Data (RS=1)
	MOVWF	datao
	CALL	TX
	;
	MOVF	TMP,W
	MOVWF	datao
	CALL	TX
	;
	CALL	I2CSTOP
	;
	RETURN
	;
;---------------------------------------------------------------------
;  LCD表示(入力W)
;---------------------------------------------------------------------
DSPLCD
	CLRF	binH
	MOVWF	binL
	CALL	_bin2bcd	; BCD変換
	;
	MOVF	bcdM,W
	ANDLW	H'0F'
	ADDLW	'0'
	MOVWF	BUFF

	SWAPF	bcdL,W
	ANDLW	H'0F'
	ADDLW	'0'
	MOVWF	BUFF+1

	MOVF	bcdL,W
	ANDLW	H'0F'
	ADDLW	'0'
	MOVWF	BUFF+2
	;
	MOVLW	'm'
	MOVWF	BUFF+3
	MOVLW	'm'
	MOVWF	BUFF+4
	;
	; ゼロサプレス(上位桁が0なら空白にする)
	MOVF	BUFF,W
	SUBLW	'0'
	BTFSS	STATUS,Z
	GOTO	DISP
	MOVLW	' '
	MOVWF	BUFF

	MOVF	BUFF+1,W
	SUBLW	'0'
	BTFSS	STATUS,Z
	GOTO	DISP
	MOVLW	' '
	MOVWF	BUFF+1
DISP
	CALL	DSPTXT
	RETURN
	;
;---------------------------------------------------------------------
;  VL6180レジスタindex (#define名は32文字まで)
;---------------------------------------------------------------------
#define	READOUT__AVERAGING_SAMPLE_PERIOD	0x01,0x0A
#define	SYSALS__ANALOGUE_GAIN			0x00,0x3F
#define	SYSALS__INTEGRATION_PERIOD		0x00,0x40
#define	SYSALS__INTERMEASUREMENT_PERIOD		0x00,0x3E
#define	SYSRANGE__VHV_REPEAT_RATE		0x00,0x31
#define	SYSRANGE__VHV_RECALIBRATE		0x00,0x2E
#define	SYSRANGE__INTERMEASUREMENT_PERIO	0x00,0x1B
#define	SYSRANGE__MAX_CONVERGENCE_TIME		0x00,0x1C
#define	SYSTEM__INTERRUPT_CONFIG_GPIO		0x00,0x14
#define	SYSTEM__INTERRUPT_CLEAR			0x00,0x15
#define	INTERLEAVED_MODE__ENABLE		0x02,0xA3
#define	RESULT__RANGE_STATUS			0x00,0x4D
#define	RESULT__INTERRUPT_STATUS_GPIO		0x00,0x4F
#define SYSRANGE__START				0x00,0x18
#define	RESULT__RANGE_VAL			0x00,0x62
;
;---------------------------------------------------------------------
;  VL6180初期化(メモリ節約のためベタ書きではなくループを回した)
;---------------------------------------------------------------------
VL6180INIT
	CALL	W20MS
	CLRF	OFFSET
	CALL	REG8BITDT
	MOVWF	CNT1		; 設定パラメタ数
VLINIT_LP1
	MOVLW	H'52'		; アドレス
	CALL	I2CWSTART
	MOVLW	D'3'		; indexHigh, indexLow, data の3バイトを送る
	MOVWF	CNT2
VLINIT_LP2
	INCF	OFFSET,F
	CALL	REG8BITDT
	MOVWF	datao
	CALL	TX		; I2C送信
	DECFSZ	CNT2,F
	GOTO	VLINIT_LP2
	;
	CALL	I2CSTOP
	;
	DECFSZ	CNT1,F
	GOTO	VLINIT_LP1
	;
	RETURN
REG8BITDT			; 以下のテーブルから順に取り出す
	ORG	H'200'
	MOVLW	H'02'
	MOVWF	PCLATH
	MOVF	OFFSET,W
	ADDWF	PCL,F
	RETLW	D'31'		; 31パラメタ
	REG8BIT	0x02,0x07,0x01	; indexHigh, indexLow, data
	REG8BIT	0x02,0x08,0x01
	REG8BIT	0x00,0x96,0x00
	REG8BIT	0x00,0x97,0xFD	; RANGE_SCALER = 253
	REG8BIT	0x00,0xE3,0x01
	REG8BIT	0x00,0xE4,0x03
	REG8BIT	0x00,0xE5,0x02
	REG8BIT	0x00,0xE6,0x01
	REG8BIT	0x00,0xE7,0x03
	REG8BIT	0x00,0xF5,0x02
	REG8BIT	0x00,0xD9,0x05
	REG8BIT	0x00,0xDB,0xCE
	REG8BIT	0x00,0xDC,0x03
	REG8BIT	0x00,0xDD,0xF8
	REG8BIT	0x00,0x9F,0x00
	REG8BIT	0x00,0xA3,0x3C
	REG8BIT	0x00,0xB7,0x00
	REG8BIT	0x00,0xBB,0x3C
	REG8BIT	0x00,0xB2,0x09
	REG8BIT	0x00,0xCA,0x09
	REG8BIT	0x01,0x98,0x01
	REG8BIT	0x01,0xB0,0x17
	REG8BIT	0x01,0xAD,0x00
	REG8BIT	0x00,0xFF,0x05
	REG8BIT	0x01,0x00,0x05
	REG8BIT	0x01,0x99,0x05
	REG8BIT	0x01,0xA6,0x1B
	REG8BIT	0x01,0xAC,0x3E
	REG8BIT	0x01,0xA7,0x1F
	REG8BIT	0x00,0x30,0x00
	REG8BIT	0x00,0x16,0x00	;SYSTEM__FRESH_OUT_OF_RESET
	;
;---------------------------------------------------------------------
;  VL6180 configureDefault
;---------------------------------------------------------------------
VL6180CONFIG
	CALL	W20MS
	CLRF	OFFSET
	CALL	CONFIGDT
	MOVWF	CNT1		; 設定パラメタ数
VLCONFIG_LP1
	MOVLW	H'52'		; アドレス
	CALL	I2CWSTART
	MOVLW	D'3'		; indexHigh, indexLow, data の3バイトを送る
	MOVWF	CNT2
VLCONFIG_LP2
	INCF	OFFSET,F
	CALL	CONFIGDT
	MOVWF	datao
	CALL	TX		; I2C送信
	DECFSZ	CNT2,F
	GOTO	VLCONFIG_LP2
	;
	CALL	I2CSTOP
	;
	DECFSZ	CNT1,F
	GOTO	VLCONFIG_LP1
	;
	; テーブルのラストにある16bitパラメタ1個のみ
	MOVLW	D'4'		; indexHigh, indexLow, dataHigh, dataLow の4バイトを送る
	MOVWF	CNT2
VLCONFIG_LP3
	INCF	OFFSET,F
	CALL	CONFIGDT
	MOVWF	datao
	CALL	TX		; I2C送信
	DECFSZ	CNT2,F
	GOTO	VLCONFIG_LP3
	;
	CALL	I2CSTOP
	;
	RETURN
	;
CONFIGDT			; 以下のテーブルから順に取り出す
	MOVLW	H'02'
	MOVWF	PCLATH
	MOVF	OFFSET,W
	ADDWF	PCL,F
	RETLW	D'9'		; 8bit 9パラメタ + 16bit 1パラメタ
	REG8BIT	READOUT__AVERAGING_SAMPLE_PERIOD,0x30
	REG8BIT	SYSALS__ANALOGUE_GAIN,0x46
	REG8BIT	SYSRANGE__VHV_REPEAT_RATE,0xFF
	REG8BIT	SYSRANGE__VHV_RECALIBRATE,0x01
	REG8BIT	SYSRANGE__INTERMEASUREMENT_PERIO,0x09	; 100ms
	REG8BIT	SYSALS__INTERMEASUREMENT_PERIOD,0x31	; 500ms
	REG8BIT	SYSTEM__INTERRUPT_CONFIG_GPIO,0x24
	REG8BIT	SYSRANGE__MAX_CONVERGENCE_TIME,0x31	; 49ms
	REG8BIT	INTERLEAVED_MODE__ENABLE,0x00
	REG16BIT SYSALS__INTEGRATION_PERIOD,0x00,0x63	; 16bitパラメタ(1個のみ)
	;
;---------------------------------------------------------------------
;  VL6180 readRange
;---------------------------------------------------------------------
READRANGE
	; デバイスがreadyになるまで待つ
	RDREG	RESULT__RANGE_STATUS
	MOVF	datai,W
	ANDLW	H'01'
	BTFSC	STATUS,Z
	GOTO	READRANGE
	;
	; 測定開始フラグ設定
	WTREG	SYSRANGE__START,0x01
	;
	CLRF	TIMOUTH		; タイムアウトカウント用
	CLRF	TIMOUTL
READRANGLP
	CALL	CHKTIMEOUT	; タイムアウト確認
	BTFSS	STATUS,Z
	GOTO	READRANGE2
	MOVLW	D'255'		; タイムアウト
	MOVWF	RANGE
	RETURN
	;
READRANGE2
	; 測定完了確認
	RDREG	RESULT__INTERRUPT_STATUS_GPIO
	MOVF	datai,W
	ANDLW	0x07
	SUBLW	0x04
	BTFSS	STATUS,Z
	GOTO	READRANGLP
	;
	; 値を読み出す
	RDREG	RESULT__RANGE_VAL
	MOVF	datai,W
	MOVWF	RANGE
	;
	; 割り込みフラグクリア
	WTREG	SYSTEM__INTERRUPT_CLEAR, 0x01
	;
	RETURN
	;
;---------------------------------------------------------------------
;  センサのタイムアウトチェック(500ms)
;  1回の測定にざっと200usかかるとして 500ms/200us ... TIMOUTH=10
;---------------------------------------------------------------------
CHKTIMEOUT
	MOVF	TIMOUTL,W
	ADDLW	D'1'
	MOVWF	TIMOUTL
	BTFSS	STATUS,Z
	RETURN
	;
	MOVF	TIMOUTH,W
	ADDLW	D'1'
	MOVWF	TIMOUTH
	SUBLW	D'10'		; Zフラグを持ってリターン
	RETURN

;---------------------------------------------------------------------
;  ウェイト色々
;---------------------------------------------------------------------
W27US
	MOVLW	D'7'
	MOVWF	WAIT1
W27USLP
	DECFSZ	WAIT1,F
	GOTO	W27USLP
	NOP
	RETURN
	;
W1MS
	MOVLW	D'110'
	MOVWF	WAIT1
W1MSLP
	GOTO	$+1
	GOTO	$+1
	GOTO	$+1
	DECFSZ	WAIT1,F
	GOTO	W1MSLP
	GOTO	$+1
	GOTO	$+1
	NOP
	RETURN
	;
W20MS
	MOVLW	D'20'
	MOVWF	WAIT2
W20MSLP
	CALL	W1MS
	DECFSZ	WAIT2,F
	GOTO	W20MSLP
	RETURN
	;
W100MS
	MOVLW	D'100'
	MOVWF	WAIT2
W100MSLP
	CALL	W1MS
	DECFSZ	WAIT2,F
	GOTO	W100MSLP
	RETURN
	;
W200MS
	MOVLW	D'200'
	MOVWF	WAIT2
W200MSLP
	CALL	W1MS
	DECFSZ	WAIT2,F
	GOTO	W200MSLP
	RETURN
	;
W05S
	MOVLW	D'100'
	MOVWF	WAIT2
W05SLP
	CALL	W1MS
	CALL	W1MS
	CALL	W1MS
	CALL	W1MS
	CALL	W1MS
	DECFSZ	WAIT2,F
	GOTO	W05SLP
	RETURN
	;
;---------------------------------------------------------------------
;  I2Cアクセスルーチン
;  流用元:Microchip Applicatin Note : AN982
;          Interfacing I2C Serial EEPROMs to PIC10 and PIC12 Drivers
;---------------------------------------------------------------------
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
;
;   Filename:           i2c_routines.inc
;   Date:               March 21, 2005
;   File Version:       1.0
;   Assembled using:    MPLAB IDE 7.00.00.0
;
;   Author:             Chris Parris
;   Company:            Microchip Technology, Inc.
;
;*******************RAM register definitions**********************
    #define STARTRAM 0x40       ; Start RAM at address 0x40

    cblock  STARTRAM
        buffer                  ; Transfer/Receive bit buffer
        datai                   ; Data input byte buffer
        datao                   ; Data output byte buffer
        bitcount                ; Bit loop counter
        bytecount               ; Byte loop counter
        addressH                 ; Word address pointer
        addressL                 ; Word address pointer
        loops                   ; Delay loop counter
        loops2                  ; Delay loop counter
        pollcnt                 ; Polling loop counter
        i2caddr
    endc
;*******************Bit definitions*******************************
DO          equ     0           ; TX/RX buffer output bit
DI          equ     1           ; TX/RX buffer input bit
ACKB        equ     2           ; ACK/NO ACK select bit
;*******************Delay Macros**********************************
;           Each macro delay for 1 inst. cycle less than
;           required, as the instruction immediately
;           before the macro call provides 1 inst. cycle.
;*****************************************************************
THIGH   macro                   ; Clock high time delay (5 us)
        goto    $+1             ; 2-inst. cycle delay (2 us)
        goto    $+1             ; 2-inst. cycle delay (2 us)
        nop			; 1us
        endm

THDSTA  macro                   ; Start condition hold time delay (5 us)
        goto    $+1             ; 2-inst. cycle delay (2 us)
        goto    $+1             ; 2-inst. cycle delay (2 us)
        nop			; 1us
        endm

TSUSTA  macro                   ; Start condition setup time delay (5 us)
        goto    $+1             ; 2-inst. cycle delay (2 us)
        goto    $+1             ; 2-inst. cycle delay (2 us)
        nop			; 1us
        endm

TSUSTO  macro                   ; Stop condition setup time delay (5 us)
        goto    $+1             ; 2-inst. cycle delay (2 us)
        goto    $+1             ; 2-inst. cycle delay (2 us)
        nop			; 1us
        endm

TAA     macro                   ; Output valid from clock delay (4 us)
        goto    $+1             ; 2-inst. cycle delay (2 us)
        goto    $+1             ; 2-inst. cycle delay (2 us)
        endm
;-------------------------------------------------------------------
;  I2Cアクセス
;-------------------------------------------------------------------
I2CWSTART
	MOVWF	i2caddr		; I2Cアドレス退避
	call    BSTART              ; Generate start bit
                                    ; Now send the control byte
                                    ; for a write, to set address
	movf    i2caddr,W		    ; I2Cアドレス
	movwf   datao               ; Copy control byte to buffer
	call    TX                  ; Output control byte to device
	RETURN

I2CSTOP
	CALL    NOACK
	call    BSTOP               ; Generate stop bit
	RETURN
    ;
I2CRSTART
	IORLW	H'01'
	MOVWF	i2caddr		; I2Cアドレス退避
	call    BSTART              ; Generate start bit
                                    ; Now send the control byte
                                    ; for a write, to set address
	movf    i2caddr,W
	movwf   datao               ; Copy control byte to buffer
	call    TX                  ; Output control byte to device
	RETURN
;*******************Start bit subroutine**************************
;           This routine generates a Start condition
;           (high-to-low transition of SDA while SCL
;           is still high.
;*****************************************************************
BSTART
    bsf     GPIO,SCL            ; Make sure SCL is high
    TSUSTA                      ; Start condition setup time delay
    BANKSEL	1
    BCF     TRISIO,SDA          ; Configure SDA to be an output
    BANKSEL	0
    bcf     GPIO,SDA            ; Pull SDA low to initiate
                                ;  Start condition
    THDSTA                      ; Start condition hold time delay
    bcf     GPIO,SCL            ; Bring SCL low in preparation
                                ;  for data transfer
    BANKSEL	1
    BSF     TRISIO,SDA          ; Configure SDA to be an input
    BANKSEL	0
    retlw   0

;*******************Stop bit subroutine***************************
;           This routine generates a Stop condition
;           (low-to-high transition of SDA while SCL
;           is still high.
;*****************************************************************
BSTOP
    BANKSEL	1
    BCF     TRISIO,SDA          ; Configure SDA to be an output
    BANKSEL	0

    bcf     GPIO,SDA            ; Pull SDA low
    bsf     GPIO,SCL            ; Make sure SCL is high
    TSUSTO                      ; Stop condition setup time delay
    BANKSEL	1
    BSF     TRISIO,SDA          ; Configure SDA to be an input
    BANKSEL	0
    retlw   0

;*******************Bit output subroutine*************************
;           This routine outputs bit 'DO' in 'buffer' to
;           the serial EEPROM device.
;*****************************************************************
BITOUT
    bcf     GPIO,SCL            ; Make sure SCL is low
    btfss   buffer,DO           ; Check for state of bit to xmit
    goto    bitlow              ; If bit is low, pull SDA low
clockout                        ; If bit is high, leave SDA high
    bsf     GPIO,SCL            ; Bring SCL high to begin transfer
    THIGH                       ; Clock high time delay
    bcf     GPIO,SCL            ; Bring SCL low again
    BANKSEL	1
    BSF     TRISIO,SDA          ; Configure SDA to be an input
    BANKSEL	0
    retlw   0

bitlow
    BANKSEL	1
    BCF     TRISIO,SDA          ; Configure SDA to be an output
    BANKSEL	0
    bcf     GPIO,SDA            ; Pull SDA low
    goto    clockout

;*******************Bit input subroutine**************************
;           This routine inputs a bit of data from the
;           serial EEPROM device, and stores it in bit
;           'DO' of 'buffer'.
;*****************************************************************
BITIN
    bcf     GPIO,SCL            ; Make sure SCL is low
    BANKSEL	1
    BSF     TRISIO,SDA          ; Configure SDA to be an input
    BANKSEL	0
    bsf     buffer,DI           ; Assume input bit is high
    bsf     GPIO,SCL            ; Bring SCL high to begin transfer
    TAA                         ; Output valid from clock delay
    btfss   GPIO,SDA            ; Check for state of SDA bit
    bcf     buffer,DI           ; If SDA is low, set bit low
    bcf     GPIO,SCL            ; Bring SCL low again
    retlw   0

;*******************Data transmit subroutine**********************
;           This routine transmits the byte of data
;           stored in 'datao' to the serial EEPROM
;           device. Instructions are also in place
;           to check for an ACK bit, if desired.
;           Just replace the 'goto' instruction,
;           or create an 'ackfailed' label, to provide
;           the functionality.
;*****************************************************************
TX
    movlw   .8
    movwf   bitcount            ; Initialize loop counter to 8

txlp
    bsf     buffer,DO           ; Assume output bit is high
    btfss   datao,7             ; Check state of next output bit
    bcf     buffer,DO           ; If low, set buffer bit low
    call    BITOUT              ; Call routine to output bit
    rlf     datao,F             ; Rotate datao left for next bit
    decfsz  bitcount,F          ; Decrement counter, check if done
    goto    txlp                ; Keep looping
    CALL    ACK
    retlw   0

;*******************Data receive subroutine***********************
;           This routine reads in one byte of data from
;           the serial EEPROM device, and stores it in
;           'datai'.  It then responds with either an
;           ACK or a NO ACK bit, depending on the value
;           of 'ACKB' in 'buffer'.
;*****************************************************************
RX
    clrf    datai               ; Clear input buffer
    movlw   .8
    movwf   bitcount            ; Initialize loop counter to 8
    bcf     STATUS,C            ; make sure carry bit is low
rxlp
    rlf     datai,F             ; Rotate datai 1 bit left
    call    BITIN               ; Read a bit
    btfsc   buffer,DI
    bsf     datai,0             ; Set bit 0 if necessary
    decfsz  bitcount,F          ; 8 bits done?
    goto    rxlp                ; If not, do another
    call    BITIN               ; Call routine to read ACK bit
    RETLW   0

ACK
    bcf     buffer,DO           ; If ACKB = 1, send ACK (DO = 0)
    call    BITOUT              ; Send bit
    retlw   0
NOACK
    bsf     buffer,DO           ; If ACKB = 1, send ACK (DO = 0)
    call    BITOUT              ; Send bit
    retlw   0
;
;---------------------------------------------------------------------
;---------------------------------------------------------------------
; 16-bit binary to BCD conversion 
; pete griffiths 2007
; http://picprojects.org.uk/projects/pictips.htm
;
; These file register variables will
; need to be defined elsewhere.
; binH
; binL
; bcdH
; bcdM
; bcdL
; counter
; temp
;
; binH, binL contain the binary value to
; convert. Conversion process destroys contents.
; Result is in bcdH, bcdM, bcdL on return.
; Call _bin2bcd to perform conversion.
;
; Executes in 454 instructions


_bin2bcd    movlw     d'16'
            movwf     counter
            clrf      bcdL
            clrf      bcdM
            clrf      bcdH 

_repeat     rlf       binL,F
            rlf       binH,F
            rlf       bcdL,F
            rlf       bcdM,F
            rlf       bcdH,F

            decfsz    counter,F
            goto      _adjust
            return

_adjust     movlw     d'14'
            subwf     counter,W
            skpnc 
            goto      _repeat
            movfw     bcdL
            addlw     0x33
            movwf     temp
            movfw     bcdL
            btfsc     temp,3
            addlw     0x03
            btfsc     temp,7
            addlw     0x30
            movwf     bcdL
            movfw     bcdM
            addlw     0x33
            movwf     temp
            movfw     bcdM
            btfsc     temp,3
            addlw     0x03
            btfsc     temp,7
            addlw     0x30
            movwf     bcdM
            goto      _repeat
; we only need to do the test and add +3 for
; the low and middle bcd variables since the
; largest binary value is 0xFFFF which is
; 65535 decimal so the high bcd byte variable
; will never be greater than 6.
; We also skip the tests for the first two
; shifts.
;---------------------------------------------------------------------
	END
;---------------------------------------------------------------------
;  終わり
;---------------------------------------------------------------------

0 件のコメント:

コメントを投稿