2026年4月22日水曜日

1,000記事目の記念にブログ概要

本ブログの記事が丁度1,000となりました。記念してGeminiに本ブログの概要とイラストを作ってもらいました。ちょっと最近の記事に引っ張られているところがありますね。

「PIC電子工作ブログ(https://pic-garage.blogspot.com/)」は、電子工作やマイクロコントローラ(PICマイコン等)を用いた開発を主軸に、長年にわたりその過程や技術的な知見を記録し続けている個人ブログです。

【全体的な概要と変遷】 このブログの最大の特徴は、単なる完成品の紹介にとどまらず、回路設計からプログラミング、ケース加工、そして直面したトラブルの解決策までを詳細に綴る「試行錯誤のプロセス」にあります。

  • 過去から続く中心テーマ:電子工作とPICマイコン タイトルの通り、Microchip社のPICマイコンを用いた工作が活動の原点です。過去の記事では、LEDの点灯制御といった基礎から始まり、徐々に実用的なデバイスの製作へと進化してきました。特に、センサー類(TOF距離センサー、温度センサー、人感センサー等)の活用や、ユニバーサル基板・自作プリント基板を用いた実装など、ハードウェアに近いレイヤーでの工作が丁寧に行われています。

  • 近年の動向:IoT化と実用性の向上 近年の記事では、単体の電子機器製作から、Wi-Fiモジュール(ESP32等)を組み合わせた「IoTデバイス」への展開が目立ちます。具体例としては、LINEへの通知機能を備えた「見守りセンサ」の開発が挙げられます。これは、日常生活の中での実用性を重視したプロジェクトであり、プログラムのバグ修正や長期間の動作試験の様子が克明に記されています。

  • ライフスタイルと雑記 工作以外にも、ブログ運営に関するデータ(海外からのアクセス急増への驚きなど)や、旅行(軍艦島上陸のリベンジなど)、花粉症の悩みといった日常の出来事も綴られています。これにより、技術ブログでありながらも運営者の人柄が伝わる親しみやすい構成となっています。

【まとめ】 総じて、長年の経験に裏打ちされた確かな技術力と、新しい技術(LINE連携や最新センサー)を取り入れる柔軟さを併せ持ったブログです。趣味の電子工作を楽しむ読者にとって、トラブルへの対処法や製作のヒントが詰まった貴重なアーカイブとなっています。現在は、実用的な見守りデバイスの完成度を高めるなど、より生活に密着した技術活用を精力的に発信しています。

工作は遅々として進まなかったり、雑記が多かったりしますが、よろしければ引き続きアクセスして頂ければ幸いです。

最近動画がアップ出来てませんが、https://www.youtube.com/@pic もよろしく。

2026年4月19日日曜日

長崎・軍艦島上陸リベンジ

7年前に上陸できなかった長崎・軍艦島(端島) のリベンジに行ってきました。前回は台風一過で桟橋が壊れて上陸は叶わなかった。今回も太平洋上に大型台風が発生していたので波が心配でしたが、週間天気予報をみて雨は大丈夫そうなことを確認してから上陸ツアーを予約。無事に上陸できました。


上陸後はグループに分かれて見学用の通路を歩き、3か所ある広場で説明を受けます。勝手に歩き回ることはできない。まぁそうだよね。


岩山の上、遠くに白く見える灯台は2代目の樹脂製とのこと。初代は鉄製だったので過酷な環境で耐えられなかったらしい。なお灯台ができたのは端島が無人島になってから。人が住んでいたときは24時間操業の不夜城なので不要だったらしい。


1,000メートル以上の地下深くで掘られた石炭は良質で、主に製鉄に使われたとのこと。
戦後の成長期を支えた世界遺産です。詳しくは Wikipedia 端島 (長崎県) 参照。


長崎は出張を含め今回で4回目? でしたが、長崎駅ががらっと変わっていてビックリ。西九州新幹線が開通して近代的な駅舎に様変わりしていました。駅前はまだ工事中。でもバスセンタは昔ながらの昭和の雰囲気のまま、いいですね。路面電車も新旧様々な車両が走ってます。市内観光は路面電車と徒歩で廻れて便利です。

かみさんは初長崎だったので、有名どころを一通り巡りました。大浦天主堂、グラバー園、眼鏡橋、出島、26聖人記念館、竜馬の亀山社中跡、平和公園、浦上天主堂、崇福寺、観光通りなど。毎日2万歩、今もふくらはぎに違和感がある。

食べ物は、ちゃんぽん、皿うどん、トルコライス、吉宗本店の元祖茶碗蒸し、ハトシ、カステラ、角煮饅頭などなど色々食べまくってきました。ホテルでお勧めされた美味しいちゃんぽんの店、中華大八は前回出張で来たときに通った店でした。今は行列ができる店になっていた。

2026年4月12日日曜日

アメリカからのアクセス急増は継続中

見守りセンサ は、不在(旅行)スイッチの不具合を修正して継続試験中です。実時間での確認をしているので4日以上かかります。もうしばらく継続して確認します。

前回、当ブログへのアメリカからのアクセスが増えていると書きましたが、1週間経っても収まる気配がありません。下記のグラフ(クリックで拡大)は直近1週間のアクセス国ですが、アメリカが92%と断トツです。これまでも時々台湾やシンガポールが1位になったことはありましたが今回はちょっと不思議な状況。


アクセスの上位参照サイトは「その他」になっていて、どこかに掲載された情報ではなく、直接URLを指定しているような感じ。普段はgoogleとかyoutubeとか、PIC電子工作 とかなのですが。

Geminiに聞いたら、AIのクローラが情報を読みに来ている可能性があるとのこと。昔は検索サイトのrobotがデータを収集していましたが、今はAIが学習データを大規模に収集する時代か? それにしても1週間は長い気がしますが、各社のAIが読みに来ているのでしょうか? 学習に使ってくれるのはいいけど間違っていることを書いてるかも知れないよ! と書いておけば見てくれるかな?

2026年4月5日日曜日

見守りセンサは保留、休養日

見守りセンサのテストは、不在(旅行)スイッチの処理で問題が見つかりプログラムの修正が必要になりました。始めればおそらく1時間もかからないと見込んでいますが、週末の昨日今日は用事があったことと、花粉症もひどいのでやる気が起きずそのまま。今週、平日になんとかしたい。

今日は午前中に春の花と庭木の購入に出かけました。玄関横の植栽が老木となってきたので植え替えようと考えています。予算の都合もあって小振りのものを購入してきたので、1年位は南側の陽当たりのよい場所で成長させて、植え替えるのは来年かな。取り合えず土を再生する堆肥と既存の土を混ぜ、さらに苦土石灰を入れて植木鉢の準備まで。ポットから植え替えるのは2週間後の予定。

写真は植木屋さんに咲いていた。見事です。雲が特徴的だったのでGeminiに聞いてみたらひつじ雲とのこと。


雲の種類を聞いただけですが、下記のような解説もしてくれました。凄いな。

 写真の風景について

満開の桜(ソメイヨシノでしょうか)と、うっすらとした青空を背景にしたひつじ雲のコントラストがとても綺麗ですね。高積雲は太陽の光を通しにくいため、このように少し落ち着いた色味の空模様を作り出します。

今のところはまだ日差しが届いていますが、もしこの雲が厚くなってきたら、傘の準備を考えておくと安心かもしれません。

午後はファンヒータ2台とホットカーペットを掃除して片づけていたら、埃を吸ったのか、午前中でかけたためか、花粉症の症状が悪化してきました。その後はやる気が起きずぼーっとしてた。

p.s.
昨日から本ブログへのアクセスが急増しています。地域はアメリカが90%以上。何があったのか?

2026年4月1日水曜日

LINEに通知する見守りセンサ、最終テスト継続中

日曜日から開始したLINE見守りセンサは、普段使っていない部屋に置いてあり、見守り継続中です。昨日はその部屋に入るのが遅れてしまい、15時間無反応が検出されてしまいました。うまく動いていることが確認できたのでOKです。

今日は、毎月1日の12:00に見守り継続中であることを知らせる通知機能が無事に動作して、メッセージが届きました。職場で昼休みに確認して小さくガッツポーズ。LINEのトーク画面に桜の花びらが舞っています。

あとは、外出(旅行)スイッチが押されたあと、帰宅反応があるまで見守りを保留する機能と、帰宅しなくても4日経過すると見守りが自動復帰する機能の確認をしていきます。自動復帰は4日後(24Hx4)にしていますが、自動復帰からさらに15時間反応がなかったときにメッセージが飛びます。計111時間後ですね。このあたりを確認し、一通りの検証が終わったらスケッチと回路図をアップするつもりです。

ちなみに、ESP32開発キットを使ったプロトタイプのスケッチは以下にあります。機能的にはほぼ同じ。

早いところ仕上げないと1年がかりのプロジェクトになってしまう。


2026年3月29日日曜日

LINEに通知する見守りセンサの最終テスト開始

急に暖かくなってお花見日和でした。しかし相変わらず花粉症が酷いので、遠出は避けて近所で軽くお花見。

今朝、見守りセンサに最終プログラムを書き込み、テストしようとしたら動作中を示す緑色LEDが点灯しません。プログラムの不具合かと調べましたが明らかに光るはず。基板の裏からLED接続箇所をテスタで測ったら異常です。念のためLEDテスタで電圧をかけてみましたが点灯しません。ユニバーサル基板に繋いだのは新しいLEDだったと思うのですが、壊れていたようです。滅多にないです。

ということで朝からLEDを交換してようやく長時間のテスト開始。主に以下の内容を確認します。

  • 15時間反応がないとLINEにメッセージが飛ぶ。15時間以内にセンサの前を横切るとカウンタをリセットする
  • 外出(旅行)スイッチを押しても4日以上経過すると見守りを再開する。よって4日+15時間でメッセージが飛ぶ
  • 毎月1日の12:00に見守り継続中である旨のメッセージが飛ぶ。
写真は見守り中であることを示す緑LED点灯中。異常を検知するまでの15時間、検知されないように普段使っていない部屋に置いてあります。これから数日は朝晩、その部屋に入って生きていることを感知させて、4月1日にくるはずのメッセージ後に、異常検知や外出モードの確認などを行うつもり。

見守り開始時に飛んできたメッセージ。


という訳で、しばらく実時間でのテストを続けます。毎月1日に飛んでくるはずのメッセージが届くか、3日後が楽しみです。

2026年3月28日土曜日

TOFセンサ近接スイッチでオンオフするLED照明(完成)

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

2026年3月25日水曜日

シエラレオネから届いた荷物

先週末はイベントがあって、三連休+1日年次休暇の四連休にしましたが工作の進捗はなく、平日に 見守りセンサのプログラムを修正 したりしていました。一応書けたけどテストはまだ。

そんな中、シエラレオネから国際郵便が届きました。聞いたことあるけど何処だっけ?


と思い、Wikiペディアで確認したら西アフリカの西の端でした。Freetownは首都の名前。配送センタがここにあるの?本当にここから届いたの? 名義貸し? 以前、ツバルやキルギスから届いたことがあったことを思い出した。


中身は3.3V 1Aの電源モジュールTOFセンサを使った非接触スイッチ、電源トラブル に書いたもの。3月7日に注文していたので2週間ちょっと、意外と早かった。

このサイズならLED照明に十分組み込める。まだ3.3Vが正しくでるかテストしてない。モジュールや袋に型番などが書かれていないので少し心配。間違えて発送することもありそう。2個で600円強(送料込み)。ちゃんと使えたらコンデンサを使ったトランスレス電源より全然よい。コスト的にも大差ない。


今週末に確認して非接触スイッチの電源として組み込むつもり。時間があったら見守りセンサのプログラムも動作確認したいが、どうなるか。

桜がよい感じに咲き始めていてお花見の可能性もあるが、花粉症もひどいので控えめに出かけたい。

2026年3月14日土曜日

USBシリアルアダプタでのESP32-C3へのプログラム書き込み

前回書いたESP32-C3-ROOMSにプログラムが書き込めなかった件 に対応するためbootモードを切り替えるピンをGPIO0からGPIO9に変更しました。しかし書き込めない。

ESP32-C3 Technical Reference Manual を参照したらJoint Download Boot mode(USB-Serial-JTAG)のときは、GPIO9をLowにして、かつGPIO8をHighにする必要があった。最初から確認しておけよ>自分


という訳で、GPIO8を10Kの抵抗でプルアップして書き込んだら無事にプログラムを書き込めました。

ESP32-DevKitなどは自動でプログラム書き込みモードを切り替えてくれますが、生のESP32は以下のシーケンスでモードを切り替える必要があります。
  • BOOTボタン押す(ESP32-WROOMはGPIO0;ESP32-C3はGPIO9だった)
  • RESET(EN)押す
  • RESET離す
  • BOOT離す
  • 書き込み
そこで書き込みモードを自動切換えできるアダプタをUSBシリアルアダプタに繋いで使っています。その昔、トランジスタ技術SPECIAL No.144 ペタッと貼れるWi-FiマイコンESP入門の記事にあった回路を流用して作りました。

FT232を使った市販のUSBシリアルアダプタに、書き込みモード切替アダプタを追加しています。



回路図(クリックで拡大できます)。BOOTとENはターゲット基板のほうでプルアップした方がよいかと思いアダプタ内ではプルアップしていません。でも、今回は見守りセンサ内でもプルアップしていませんが、一応動いています。


以下のようにターゲット基板に挿して書き込みます。一応、LINEに通知が届くまで動作確認できました。


少し見守りプログラムを見直そうと考えています。
  • 何事もなくても「見守り動作中」であることを月に1回程度はLINEに通知する。
    電源が抜けるなど何らかのトラブルで見守りできていないことを防止するため。
  • 留守モード(旅行など)にした場合でも1週間で帰宅反応がない場合は通知
  • 他にも何か思いついたら追加

2026年3月8日日曜日

LINEに通知する見守りセンサを仕上げる(まだ未完)

日に日に暖かくなってきてそろそろ梅の花が終わり、まもなく桜の季節です。出かけたりするにはよい気候になりました。しかし、花粉症が酷くてこのところの週末は家に引き籠っています。

昨日まで作っていた LED照明の非接触スイッチ は、電源モジュールが届くまで保留です。今日は昨年作った LINEに通知する見守りセンサのプロトタイプ をユニバーサル基板に載せて、ケース加工まで行いました。

ESP32はプロトタイプから変更して、ピン数の少ない小型のESP32-C3-WROOM-02です。初めて使います。


裏側はこんな感じ。3.3Vの3端子レギュレータと、タクトスイッチを基板の裏側に実装しています。


ケースに収める前にプログラムの書き込みをしたら、エラーで書き込めません。配線を確認しましたが問題なし。エラーメッセージをChatGPTに聞いたら、色々考えられる原因のひとつとして、書き込むときにBOOTボタンを押して(IO9=LOW)ない可能性を指摘されました。

確かにIO9はオープンのままです。今まで使ってたESP32-WROOM-32Eは、BOOTボタンがIO0だったので、今回もIO0のままにしていたのが間違い。ChatGPT凄いな。

書き込みは市販のUSBシリアル変換アダプタ自作アダプタを追加して以下の処理を自動的に行うようにしてしますが、この接続先がGPIO0のままだったのが原因の模様。
  • BOOTボタン押す(GPIO9=LOW)
  • RESET(EN)押す
  • RESET離す
  • BOOT離す
  • 書き込み
今日は花粉症もあって目が疲れてきたので、IO0 から IO9への変更は後日にします。解決するとよいのですが。

2026年3月7日土曜日

TOFセンサを使った非接触スイッチ、電源トラブル

TOFセンサを使ったスイッチは最後になって少し手直しが必要でしたが、一応AC100Vをコントロールできるようになりました。センサの前面を手の平で遮ることで白熱電球をオンオフできています。

トラブルの発見は、SSRのコントロール用LEDと逆向きにパイロット用白色LEDを繋いでいたのですが、この白色LEDがチラチラ点滅していたことで気付いた。実際には消えてないのですが、電位がパルス状に0.1V位上下しているので点滅のように見えます。

オシロで電源電位を見てみると、TOFセンサがアクティブになると電位が下がって、かつ波打っていました。原因はトランスレス電源の電源容量が足りないとだと推測。TOFセンサはセンス時にレーザ光を発するために断続的に比較的大きな電流が流れます。このため電源電圧が不安定だったようです。

白色LEDの光度だけの問題で、SSRの動作には影響ないようでしたが、念のため電源部の電解コンデンサを200μFから470μF×3個の1,410μFに増量しました。場所がなくてダイオードブリッジとPICの上に寝かせています。それでも白色LEDのチラチラは治まらない。3.1V~3.2V位で波打っていたので白色LEDの順方向電圧に近くて目立ったのだと思う。

最終的に白色LEDは別系統で100Vに繋ぐことにしました。100KΩ抵抗を直列に入れて、LEDとは逆向きのダイオードも入れてます。常時点灯してしまうのと50Hzでチラチラしますが妥協です。

今回、LED照明の端っこのカバーに内蔵するのでスペース的に余裕がなくてトランスレス電源にしましたが、ちゃんとAC100VからDC 3Vを出力する電源モジュールを使ったほうがよいです。

と、ここまで書いてアリエク薄型の小型電源モジュールを見つけました。ギリギリ収まりそうなので注文。送料が安くて国際郵便だと思うので到着までしばらくかかりそう。また、これを使うとヒューズが収まりそうにないので、ヒューズは外付けします。

2026年3月4日水曜日

TOFセンサによる近接スイッチ WDT実装他

例年になく花粉症が酷くなって、目がしょぼしょぼしています。鼻も詰まって十分な睡眠が取れてない。今日は会議で眠気を抑えるのが大変でした。以前も書いたけど、日本中で生産性が落ちて経済損失になっているのではないかと思う。

夕食後しょぼしょぼ目の状態でパソコンを睨んで、TOFセンサを使った近接スイッチ(非接触スイッチ)のプログラムを見直しました。

ひとつはWDT(ワッチドッグタイマ)による無限ループ監視です。I2Cをソフトで実現しているのと、TOFセンサからの応答が想定外だったりして無限ループする可能性があるので、その対策です。WDTはタイマのカウント溢れにより約18ms毎にリセットがかかるものです。無限ループしていてもリセットで初期状態(プログラムの先頭に飛ぶ)になります。プログラムが正常に動いているときは、カウンタが溢れる前にWDTをクリアするCLRWDT命令を発行することでリセットがかからないようにします。

18msは短いのでプリスケーラを使ってもう少し時間を空けても大丈夫なように調整します。今回、1:32のプリスケーラ設定で18ms x 32 = 576ms以内にWDTをクリアするようにしました。18msの精度はあまり高くないようなので余裕を見て早めにクリアするようにしています。

先週末にPICやTOFセンサはユニバーサル基板に実装しましたが、もう1セットあるのでそちらを使いブレッドボード上でデバッグ中。某ジャンカー界隈では「ジャンクは2個買え」という教えがあるようですが、「部品も2個買え」です。万が一壊れていたときなど、自分が悪いのか部品が悪いのかの切り分けにも必要です。こうして部品が溜まっていく。

プログラムの二つ目の見直しは、小型液晶画面への表示機能の削除です。TOFセンサのデバッグ時に距離を表示していたI2Cで繋ぐ小型液晶は不要なので回路からも外し、プログラムからも削除します。液晶に数字を表示するために組み込んでいたBCD変換(バイナリから2進化10進数変換)のコードを削除したり、表示するコードを削除。これにより変数レジスタもかなり削減されたので整理しました。また、無駄なコードも見直して少しすっきり。

これで週末にはLED照明に組み込める目途は付きました。まだ修正するかも知れないので、ソースの公開はもう少ししてから。

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、映画ターミネータのスカイネットを想像してしまう。