2026年3月1日日曜日

TOFセンサによる近接スイッチのユニバーサル基板実装

花粉症が酷いので外出もせず、昨日のToFセンサによる近接スイッチのLED照明への組み込みの続きです。と言っても昨日は何もしなかったのですが。LED照明のカバー内へ組み込むためにユニバーサル基板に載せてみました。

写真はトランスレス電源が正しく動いているかの確認をしているところです。左の白い2本のコードからAC100Vを供給しています。ツェナーダイオードが手元に3.3Vのものしかなかったので、出力先にシリコンダイオードを直列に入れて少し電圧をドロップさせています。それでもLED程度の負荷で3.2V弱でていました。ToFセンサの定格3Vを若干オーバしていますが、PICやToFセンサを繋げば若干下がることを期待。


トランスレス電源が上手く動いていることが確認できたので、他の部品も載せて基板内の配線まで完了です。基板の中央が空いているのは、ここにLED照明の電源コネクタがくるためです。黄色いコードが出力で、LED照明の電源部に接続します。


全景はこんな感じ。カバーにToFセンサの長円穴、その隣にΦ3mmのLED用の穴を開けました。LEDはパイロットランプとして、LED照明が点灯していないときに点灯させます。夜、真っ暗な中でスイッチの場所が分かるように。


昨日の写真の再掲ですが、上記の基板を収める場所がここのカバーです。


今日の作業はここまで。今週どこかでプログラムの改変を行うつもりです。昨日書いたWDTによる無限ループ監視と、プロトタイプで距離を表示していたLCD表示の削除です。

今週末には完成させて、キッチンに取り付けたい、と思っています。そのためにも花粉症が酷くならないことを願っています。

2026年2月28日土曜日

TOFセンサによる近接スイッチを照明機器へ組み込む検討

例年のことですが花粉症の症状が酷くなってきました。今週クリニックで薬を処方してもらい、点眼薬も始めたのですが目が痒くて辛い。鼻水のため鼻のかみすぎで鼻の下が赤くなってきてしまった。

そんな中、TOFセンサとPICで作った近接スイッチ を照明機器に組み込む検討を始めました。組み込む前にプログラムを一部改善して、WDT(ワッチドッグタイマ)で無限ループを避けるようにしたいと思っています。I2Cをソフトで実現しているのと、TOFセンサからの応答待ちなど、何らかのタイミングで無限ループしないとも限りません。WDTは時々タイマをリセットしないと、強制的にリセットがかかる(レジスタなどはそのままですが)仕掛けです。デッドマンスイッチのようなもの。

その改善前にLED照明機器に今回のスイッチが組み込めるか検討しています。LED照明はアマゾンで購入したそれほど高価ではないもの。2本購入して1本は納戸に取り付けました。 これをキッチンのシンクの上に取り付けようと考えています。現在はプルスイッチタイプの蛍光灯がついています。

ケーブルの途中に中間スイッチがあって、点灯させると結構明るい。明るすぎてゴーストがでています。


端っこのカバー内に近接スイッチの組み込みを考えています。


裏側はこんな感じで2本のビスを抜けば外せそうです。


カバー内部のスペースには余裕がありそうですが、樹脂が薄くて加工すると割れそう。


組み込む大物部品を並べてみました。安全のためのヒューズボックストランスレス電源に使う1μF,250Vコンデンサ、整流のためのダイオードブリッジ平滑用コンデンサSSR(ソリッドステートリレー)です。TOFセンサPICマイコンは写真に含まれていません。また、他に抵抗3Vツェナーダイオード0.1μFパスコンなどが載ります。全てを1枚のユニバーサル基板に載せるのは厳しそうですが、スペース的には十分です。


課題は、TOFセンサの窓を上手く開けられるかですね。一応、タカチのケースに収めるプランBもあります。


どうするか、カバー内への収容レイアウトも検討して決めるつもりです。

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
;---------------------------------------------------------------------
;  終わり
;---------------------------------------------------------------------

2026年2月20日金曜日

TOFセンサをPIC12F629で使う(動いた)

ようやくTOFセンサ VL6180XPIC12F629で動かすことができました。設定パラメタを何度も見返したりしましたが分かりません。他のArduinoライブラリを見たりしても大きな違いはないように見えました。

基本に戻ってI2Cのコードを見ていたら読み出しのタイミングにおかしいところがあるのに気付きました。そこを直したら難なく動いた次第。トホホです。取り合えず書いたコードなので、この3連休で少しキレイにしようかと思います。


写真は消しゴムのMONOまでの距離を表示しているところです。最終的な目的は、非接触スイッチへの利用なのでLCD表示などは不要になりますが、デバッグ時は繋げておくつもり。

手をかざすことでキッチンのシンク上にある照明のオンオフをしようと考えています。今は紐を引っ張ってオンオフするプルスイッチの蛍光灯ですが、LED照明に交換すると共に非接触化を図りたい。濡れた手でスイッチを触りたくないので。センサもPICも小さいので組み込めることを期待しています。

2026年2月15日日曜日

TOFセンサをPIC12F629で使う(使えてない)

昨日書いたChatGPTから吐き出されたコードがダメダメだった 件の続きで、コードを自力で書いてみました。先に結論を言うとまだ使えてません。VL6180Xはムズイ。

使ったのはPIC12F629という古い8ピンタイプで、メモリ1Kワード、I2Cなしです。うまく動いたArduinoのTOPセンサVL6180Xライブラリコードを見ながらアセンブラで移植しました。古いアーキのPICなので最近の便利な命令が使えません。それでも書き始めたら思い出してきてなんとかなった(なってない)。

Arduinoのライブラリを丸ごと移植するのは大変だし、メモリ容量的にも厳しい。適当に端折って移植しましたが、上手く動きません。初期化、コンフィグ、距離測定の3機能だけですが、ダメです。距離が7mmで返ってきます。最小値かな? I2C接続のLCDには表示できているのでI2Cは大丈夫だと思う。端折ってしまったところで、何か必要な設定ができていないのか、処理の呼び出し方をミスっているのかと推測。

朝からコードを見直して1か所、設定場所を間違えている箇所に気付いて修正しましたが、結果は変わらず。根を詰めてもよろしくないし、頭を切り替えたら何か思いつくかもという期待を込めて今日はここまで。

2026年2月14日土曜日

PICプログラムをchatGPTに書いてもらったけど、、、

 先日試したTOF測距センサ をPICマイコンで使いたくて、chatGPTにプログラムを書いてもらったりしていた。しかし、全然動かない。

依頼したプロンプトは以下のような感じ。

PIC12F629マイコンとTOFセンサVL6180を使って近接センサによるスイッチを作りたい。
回路(ピンの接続)とプログラムが欲しい
・あらかじめ設定した距離(cm単位で10~20cm)に近づくとオンオフ動作する
・距離の設定はプログラム内の#defineで行う
・オンオフはオルタネイト。一度近づくとオン、離れたのちもう一度近づくとオフ
・オンの間はLEDが点灯する。最終的にはこれをSSRのLEDにする。
・誤動作防止のためオンオフは指定された距離で200ms程度継続したら認識する
・オンオフの間はチャタリング防止のため500m秒程度あける(これより短い時間でオンオフしない)
・PIC12F629はI2Cモジュールがないので、ソフトウェアでI2Cを行う
・プログラムはアセンブラで書く ・適度に関数に分けたコードが欲しい(後で人手で直せるように処理内容のコメントも記載) ・プログラム書き込みに使用するピン(GP1:ICSPCLK,GP2:ISCPDAT)は使わない ・MPLABでそのままビルドできる1ファイル化 ・クロックは内蔵発信4MHz

吐き出してきたソースを見るとI2C通信のタイミングを全く無視しているし、ACKも見てない。それを指摘すると、それっぽいソースになったがまだダメです。また、TOFセンサの初期化も適当でこれで初期化できるの?という感じ。Arduinoのライブラリのソースを見ると結構多くのパラメタを設定していた。

簡単にできると思っていたのが甘かった。しかたないので諦めて自分で書くことにしました。有料のClaude codeなどを使えばすぐ動くコードを出してくれるのかな?

今日の日経に以下の記事が掲載されていた(クリックで拡大)。先日来のアンソロピックショックでITサービス系の株価が下落しているのにさらに追い打ちかけてきます。NASDAQ, FANG+が下がって痛手。 

AIが自分自身を書き換えて進化し続けたらちょっと怖いな。イーロンマスクが軌道上にAIデータセンタを作るらしいし、そこでAIが自律的に動き出したら簡単に止められない。というようなディストピアSF、映画ターミネータのスカイネットを想像してしまう。

2026年2月7日土曜日

東京アプリでポイントをゲットしたけど

先日、東京アプリによる給付について書きました が一応、ポイント申請してみました。今朝メールが届いたのでアプリで確認したら保有ポイントが11,000Pになっていた。申請してからポイントが付くまで1日半ほどでした。


しかし、dポイントへの交換でエラー発生。大丈夫? ポイントだけ消えないよね? と思いつつ何度かトライ。


無事にdポイントに変換できたようです。ただ、dポイントに交換すると+1,000ポイント増量されるという情報があったのですが、そうはなっていなかった。ちなみにdポイントのアカウント作成時に個人情報を求められて仕方なしに入れた。都がやっている施策なのに、ドコモに個人情報渡さないといけないのはなんだかな。


で、d払いアプリなるものを入れて使うらしいとのことで、入れてポイントをみたら12,345円になっていた。限定123Pというのが分からないけど。それでも1,000ポイントより多い。この12345というのはサンプル画面なのか?


その後、買い物に出かけたのでd払いできるか調べたらポイントが11,000Pに戻っていた。何これ? 結局追加の1,000ポイントはどこへ?


よく分からないけどあまり信用できそうにないのと色々操作を覚えないと使いこなせそうにないので、早めにポイントを使い切って東京アプリもdポイントアプリもアンインストールしようと思う。とにかくアプリやらポイントに振り回されず、生活をシンプルにしたい。

ドコモに渡した個人情報のみ少し後悔。こんなことなら11,000P諦めればよかった。

(追記26.2.7) 東京アプリと認証アプリはアンインストールしたけどアカウントは残ったままになるのかな?アプリを消す前にアカウント削除すべきだったか?

(追記26.2.14) 東京アプリのアカウントの削除は、アプリ内でしかできないようだったので、アプリを入れ直して、アカウント削除(退会)しました。その後再度アンインストール。アマゾンとの連携も個人情報がどこまで連携されるのか不安でやめることにした。で、dポイントはリアル店で使い始めましたが最初手間取りました。早いとこ使い切りたい。最後に残るだろう千円以下の端数ポイントは、普段dポイントを使っている知人にあげちゃうつもり。