TOFセンサを使った近接スイッチでLED照明のオンオフを行う工作もいよいよ大詰め。
先日届いた小型の電源モジュール にAC100Vを繋いで動作確認したら全然電圧がでません。壊れているのかと思い、もう1個調べても同じ。調べてみると購入したショップの商品説明には記載がなかったのですが、他のショップの説明欄を見ると、外付けに耐圧の大きなコンデンサ(物理的にも大きくなる)が必要なことが判りました。これでは小さく作れません。トホホです。
諦めて当初の計画通りトランスレス電源で行くことにしました。TOFセンサが発光するタイミングで電位が下がるため、モニタ用に点灯させている白色LEDがチラチラします。そこで白色LEDはやめて緑色にしたら若干目立たなくなったのでOKとしました。
写真はLED照明の端カバーに基板を収めた様子です。照明の拡散カバーの切り欠きはTOFセンサと干渉するためカットした跡です。
LED照明の端はこんな形のコネクタ。
全長は120cmあります。電源ケーブルは付属していた中間スイッチ入りケーブルです。通常はそのスイッチでオンオフします。
通電中、緑LEDが点灯します。このLEDが若干チラチラする。
SSRのLEDと逆向きに繋いであるので、照明点灯中は緑色LEDは消えます。
今日はここまで。キッチンに取り付ける工事はまた別途。
参考にされる方がいるか不明ですが、回路図(クリックで拡大)です。途中、色々変更したので汚くて恐縮です。無保証です。AC100Vを扱うので参考にされる方は十分ご注意ください。ヒューズ必須です。
また、1uF250Vコンデンサに並列に入っている1MΩの抵抗は、コンデンサに溜まった電荷を逃がすためのもの。これがないとコンセントから抜いても電荷が残ってしまいプラグを触ったりすると感電する可能性があります。
プログラム(PIC アセンブラ)です。こちらも無保証です。著作権等は留保しますが、流用・改造などご自由にどうぞ。
;---------------------------------------------------------------------
; TOF近接センサVL6180Xを使った非接触スイッチ
;
; 2026.02.22 naka
; 1. 概要
; 近接センサの前で手をかざすとオンオフ動作するスイッチ
; ・距離は180mm位までは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なので)
; ・I2Cの応答待ちなどによる無限ループ対策にWDTを利用
;
; 4. 改版履歴
; 2026.02.14 new
; 2026.02.22 色々修正
;
;---------------------------------------------------------------------
;---------------------------------------------------------------------
; デバイス定義
;---------------------------------------------------------------------
LIST P=12F629
INCLUDE <P12F629.INC>
__CONFIG _INTRC_OSC_NOCLKOUT & _WDT_ON & _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'180'
;---------------------------------------------------------------------
; 変数レジスタの定義
;---------------------------------------------------------------------
WAIT1 EQU H'20'
WAIT2 EQU H'21'
CNT1 EQU H'22'
CNT2 EQU H'23'
OFFSET EQU H'24'
RANGE EQU H'25'
TIMOUTH EQU H'26'
TIMOUTL EQU H'27'
TOGGLE EQU H'28' ; 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 VL6180INIT
CALL VL6180CONFIG
;
CLRF TOGGLE
;
MAIN_LP
CLRF RANGE
CALL READRANGE ; 測定
;
MOVF RANGE,W
SUBLW ACTDIST ; アクティブか否かチェック
BTFSS STATUS,C
GOTO INACT
; 前回もアクティブなら何もしない(そうしないと点滅する)
BTFSC TOGGLE,1
GOTO NEXTREAD
BSF TOGGLE,1 ; 前回アクティブではないのでトグル動作
GOTO TOGGLESW
;
INACT
BCF TOGGLE,1
GOTO NEXTREAD
TOGGLESW
MOVF TOGGLE,W
XORLW H'01'
MOVWF TOGGLE
;
BTFSS TOGGLE,0
GOTO $+3
BSF GPIO,LED
GOTO $+2
BCF GPIO,LED
;
CALL W05S ; トグル動作時は1秒待つ
CALL W05S
GOTO MAIN_LP
;
NEXTREAD
CALL W100MS ; 100ミリ秒ごとに測定
CLRWDT
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
;
BANKSEL 0
CLRWDT ; Clear WDT
CLRF TMR0 ; Clear TMR0
;
BANKSEL OPTION_REG
MOVLW b'00101101' ; WDTプリスケーラ 1:32 (576ms)
MOVWF OPTION_REG
BANKSEL 0
;
BCF GPIO,LED
;
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
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'100'
MOVLW H'01'
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
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'01'
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
;
;---------------------------------------------------------------------
; ウェイト色々
;---------------------------------------------------------------------
W1MS
MOVLW D'110'
MOVWF WAIT1
W1MSLP
GOTO $+1
GOTO $+1
GOTO $+1
DECFSZ WAIT1,F
GOTO W1MSLP
GOTO $+1
GOTO $+1
NOP
RETURN
;
W100MS
MOVLW D'100'
MOVWF WAIT2
W100MSLP
CALL W1MS
DECFSZ WAIT2,F
GOTO W100MSLP
CLRWDT
RETURN
;
W05S
CALL W100MS
CALL W100MS
CALL W100MS
W200MS CALL W100MS
CALL W100MS
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
;
;---------------------------------------------------------------------
END
;---------------------------------------------------------------------
; 終わり
;---------------------------------------------------------------------