ようやくTOFセンサ VL6180X をPIC12F629で動かすことができました。設定パラメタを何度も見返したりしましたが分かりません。他のArduinoライブラリを見たりしても大きな違いはないように見えました。
基本に戻ってI2Cのコードを見ていたら読み出しのタイミングにおかしいところがあるのに気付きました。そこを直したら難なく動いた次第。トホホです。取り合えず書いたコードなので、この3連休で少しキレイにしようかと思います。
https://pic-garage.blogspot.com/
ようやくTOFセンサ VL6180X をPIC12F629で動かすことができました。設定パラメタを何度も見返したりしましたが分かりません。他のArduinoライブラリを見たりしても大きな違いはないように見えました。
基本に戻ってI2Cのコードを見ていたら読み出しのタイミングにおかしいところがあるのに気付きました。そこを直したら難なく動いた次第。トホホです。取り合えず書いたコードなので、この3連休で少しキレイにしようかと思います。
昨日書いたChatGPTから吐き出されたコードがダメダメだった 件の続きで、コードを自力で書いてみました。先に結論を言うとまだ使えてません。VL6180Xはムズイ。
使ったのはPIC12F629という古い8ピンタイプで、メモリ1Kワード、I2Cなしです。うまく動いたArduinoのTOPセンサVL6180Xライブラリコードを見ながらアセンブラで移植しました。古いアーキのPICなので最近の便利な命令が使えません。それでも書き始めたら思い出してきてなんとかなった(なってない)。
Arduinoのライブラリを丸ごと移植するのは大変だし、メモリ容量的にも厳しい。適当に端折って移植しましたが、上手く動きません。初期化、コンフィグ、距離測定の3機能だけですが、ダメです。距離が7mmで返ってきます。最小値かな? I2C接続のLCDには表示できているのでI2Cは大丈夫だと思う。端折ってしまったところで、何か必要な設定ができていないのか、処理の呼び出し方をミスっているのかと推測。
朝からコードを見直して1か所、設定場所を間違えている箇所に気付いて修正しましたが、結果は変わらず。根を詰めてもよろしくないし、頭を切り替えたら何か思いつくかもという期待を込めて今日はここまで。
先日試した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、映画ターミネータのスカイネットを想像してしまう。
先日、東京アプリによる給付について書きました が一応、ポイント申請してみました。今朝メールが届いたのでアプリで確認したら保有ポイントが11,000Pになっていた。申請してからポイントが付くまで1日半ほどでした。
で、d払いアプリなるものを入れて使うらしいとのことで、入れてポイントをみたら12,345円になっていた。限定123Pというのが分からないけど。それでも1,000ポイントより多い。この12345というのはサンプル画面なのか?
よく分からないけどあまり信用できそうにないのと色々操作を覚えないと使いこなせそうにないので、早めにポイントを使い切って東京アプリもdポイントアプリもアンインストールしようと思う。とにかくアプリやらポイントに振り回されず、生活をシンプルにしたい。
ドコモに渡した個人情報のみ少し後悔。こんなことなら11,000P諦めればよかった。
(追記26.2.7) 東京アプリと認証アプリはアンインストールしたけどアカウントは残ったままになるのかな?アプリを消す前にアカウント削除すべきだったか?
(追記26.2.14) 東京アプリのアカウントの削除は、アプリ内でしかできないようだったので、アプリを入れ直して、アカウント削除(退会)しました。その後再度アンインストール。アマゾンとの連携も個人情報がどこまで連携されるのか不安でやめることにした。で、dポイントはリアル店で使い始めましたが最初手間取りました。早いとこ使い切りたい。最後に残るだろう千円以下の端数ポイントは、普段dポイントを使っている知人にあげちゃうつもり。
東京都が実施する生活支援キャンペーンで、東京都が公式スマートフォンアプリ「東京アプリ」を通じて、現金ではなく 11,000ポイント(1ポイント = 1円相当)受け取れる給付制度です。2月2日からはじまった。
よくわからなかったのでchatGPTとチャットして色々と教えてもらったら、驚愕の事実が、、、(検証はしてないので間違いがあるかも)
まず、付与されたポイントは以下の民間のポイントサービスに1ポイント=1円で交換できるらしい。
しかし個人的にはこれらのポイントサービスは使ってない。昔からポイントカードとかは面倒で使ってないのです。例外はポイントサービスの元祖であるヨドバシのポイント、アマゾンのポイント、クレジットカードのポイントだけ。
chatGPTが言うにはdポイントはアマゾンと連携して使えるらしい。でもアマゾンギフトカードは買えないよ、と教えてくれた。手順は以下のような感じ。
以上、面倒な作業が続く。「スマホが使えない独居の高齢者に無理だね」ということをchatGPTに聞いたら、「そうですね、本当に困窮している人には届かない施策」とのこと。
事業費なども聞いたら、給付用に450億円で、これは支給対象者の約1/3分しかない。要するに、元々全員に配る(申請する)とは考えてない。また、給付額を含む総事業費が799億円とのことなので349億円がシステム構築、運用管理、宣伝費など。これらには職員の人件費は含まないようなので、それを含めたらもっとかかっている計算。
なんだかなぁ、と思った次第。個人的には残された時間を考えると極力手間のかかることに時間を使いたくない、と思う今日この頃。でもサーバの混雑が解消したころに申請すると思う。
サクッと作ろうと思っていた温度ロガーですが、昨年の9月から始めてようやく完成。製作記事がふっとんで気力回復がイマイチなのでここまで。
特徴は次のような感じ。
# 温度ロガー設定ファイル # 例) # SSID mySSID # PW myPassWord # Interval 0 (0:1秒, 1:10秒, 2:30秒, 3:1分, 4:5分, 5:10分) # SSID mySSID PW myPassWord Interval 0
//---------------------------------------------------------------------------------------
// '26.01.31 naka
// ver.0 '25.09.14 naka
// ESP32 2ch温度ロガー(小型液晶に時刻も表示)
//
// ・測定の正確な日時はWiFi経由のntpサーバから取得
// ・microSDのsetup.txtファイルに平文でWiFiのSSID,Password 及び測定時間間隔の
// デフォルトの番号を記載(0:1秒, 1:10秒, 2:30秒, 3:1分, 4:5分, 5:10分)
// 例)SSID mySSID
// PW myPassWord
// Interval 0
// ・時間間隔は電源投入後にタクトスイッチでも変更可能(5秒経過すると測定を開始)
// ・WiFiがない環境で使う際は、タクトスイッチを押しながら電源オン
// ・WiWi設定があっても繋がらない場合には、複数回トライして諦める
// ・WiWiがない場合、或いは何度トライして繋がらない場合には日時を26年1月1日00:00:00とする
// ・ログはmicroSD内にタイムスタンプ付のcsvファイルとして格納する
// ・ファイル名が重複する場合にはファイル名に追番が付く
// ・WiFiに繋がない、繋がらない、ntpサーバに繋がらない際の日時は"2026-01-01 00:00:00"となる
// ・測定は指定した時刻が時間間隔で正時になったとき
// 例)10秒毎なら0秒、10秒、20秒…のとき、1分毎なら毎分0秒のとき
// ・スリープから1秒毎の割り込みで目覚めて正時になったか確認(再びスリープ)
//---------------------------------------------------------------------------------------
#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <ESP32Time.h>
#include <SD.h>
#include "FS.h"
#include "SPIFFS.h"
#include "esp_adc_cal.h"
ESP32Time rtc;
#define SD_CS 16 // SD card chip select
#define TACT_SW 25 // タクトスイッチ(WiFi未使用指示、測定時間間隔セット用)
const int SENSOR_PIN1 = 32; // 温度センサMCP9700Aの出力ピンを接続したADCピン
const int SENSOR_PIN2 = 33; // 温度センサMCP9700Aの出力ピンを接続したADCピン
esp_adc_cal_characteristics_t adc_chars;
#define SETUP_FILE "/setup.txt"
#include <FaBoLCDmini_AQM0802A.h>
FaBoLCDmini_AQM0802A lcd;
// microSDのsetupファイルに記載されているものが設定される
char ssid[24];
char password[24];
int interval;
int interval_i = 0;
const int interval_tbl[] = {1,10,30,60,300,600}; // 測定間隔(秒)
const int interval_tbl_size = 6;
char LogFile[64]; // 記録用のcsvファイル名(タイムスタンプから自動作成)
void setup()
{
char msg[17];
struct tm timeinfo;
char logfilename[64];
pinMode(TACT_SW, INPUT);
pinMode(SENSOR_PIN1, ANALOG);
pinMode(SENSOR_PIN2, ANALOG);
analogReadResolution(12); // 分解能12bit
analogSetAttenuation(ADC_11db);
// ADCキャリブレーション
esp_adc_cal_characterize(
ADC_UNIT_1, // GPIO32?39
ADC_ATTEN_DB_11, // 0?3.3V
ADC_WIDTH_BIT_12,
1100, // デフォルトVref(mV)
&adc_chars
);
// モニタLCD設定
SetupLCD();
delay(1000);
// setupファイルを読み、WiFiのssid,password、測定間隔のデフォルトを取得
if (!SD.begin(SD_CS, SPI, 24000000)) {
dispLCD_msg("microSD failed "," ");
while(true);
}
read_setup_file(SETUP_FILE);
bool wifi_flag = false;
if (digitalRead(TACT_SW)==LOW) {
dispLCD_msg("WiFi dosen't use"," ");
while(digitalRead(TACT_SW)==LOW);
}
else {
dispLCD_msg("Connecting WiFi "," ");
if (wifi_connect()) {
wifi_flag = true;
}
else {
dispLCD_msg("Connect failed "," ");
delay(1000);
}
}
delay(1000);
if (wifi_flag) {
// WiFi接続に成功した場合、NTPサーバに接続し、時刻設定
configTime(9 * 3600L, 0, "ntp.nict.jp", "time.google.com", "ntp.jst.mfeed.ad.jp");
int loopcnt = 0;
while (!getLocalTime(&timeinfo)) {
dispLCD_msg("Failed get time ","Retrying ... ");
if (++loopcnt>5) { // 念のため5回繰り返してダメなら抜ける
wifi_flag = false;
break;
}
delay(500);
}
dispLCD_msg(" "," ");
wifi_disconnect(); // 以降はWiFi未接続にする
}
// 起動時にSWが押されていたか、WiFi接続に失敗か、ntpサーバからの時刻取得に失敗した場合は下記の日付と時刻設定
if (!wifi_flag) {
rtc.setTime(1767225600); // 2026-01-01 00:00:00
}
// 測定時間間隔の設定(5秒無操作で戻ってくる)
set_interval();
// ログファイル名を決めるためにタイムスタンプ取得
getLocalTime(&timeinfo);
sprintf(logfilename, "%02d%02d%02d_%02d%02d%02d.csv",(timeinfo.tm_year + 1900)%100, timeinfo.tm_mon + 1, timeinfo.tm_mday,timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec);
// WiFiに繋がない場合、時刻情報を取得できないためタイムスタンプのファイル名が同じになることを防ぐ。
get_unique_filename("",logfilename,LogFile,sizeof(LogFile));
// 測定開始メッセージ
dispLCD_msg("Start "," measurement");
// 1,000,000us = 1sのタイマー設定
esp_sleep_enable_timer_wakeup(1000000);
}
void loop()
{
// 温度を測定してログファイルに書き出す
measurement(interval);
// ライトスリープ(タイマー割り込みで1秒毎に目覚める)
esp_light_sleep_start();
}
void set_interval() {
disp_interval(interval_i); // 現在の設定時間を表示
int prevmsec = millis();
while ((millis() - prevmsec)<5000) { // 5秒反応が無ければ時間設定を抜ける
if (digitalRead(TACT_SW)==LOW) {
interval_i++;
prevmsec = millis();
if (interval_i>=interval_tbl_size) interval_i = 0;
disp_interval(interval_i); // 現在の設定時間を表示
while (digitalRead(TACT_SW)==LOW) {} // SWが離されるまで待つ
delay(20); //チャタリング対策
prevmsec = millis();
}
}
interval = interval_tbl[interval_i];
return;
}
void disp_interval(int i) {
int time = interval_tbl[i];
char msg[20];
if (time<60)
sprintf(msg,"%11d(sec)",time);
else
sprintf(msg,"%11d(min)",time/60);
dispLCD_msg("set interval ",msg);
}
void measurement(int period) {
char yymmddhhmmss[17],hhmmss[10],timestamp[17];
struct tm timeinfo;
getLocalTime(&timeinfo);
// 測定する時間なのか確認(割り込みは1秒毎なので)
bool flag = false;
if (period==1) flag = true;
else if (period==10 && timeinfo.tm_sec%10==0) flag = true;
else if (period==30 && timeinfo.tm_sec%30==0) flag = true;
else if (period==60 && timeinfo.tm_sec==0) flag = true;
else if (period==120 && timeinfo.tm_sec==0 && timeinfo.tm_min%2==0) flag = true;
if (flag) {
sprintf(timestamp,"%02d:%02d:%02d",timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec);
sprintf(yymmddhhmmss, "%02d%02d%02d %s",(timeinfo.tm_year + 1900)%100, timeinfo.tm_mon + 1, timeinfo.tm_mday, timestamp);
float temp1 = temp_sensing(SENSOR_PIN1);
float temp2 = temp_sensing(SENSOR_PIN2);
char buff1[6],buff2[6],buff[20];
dtostrf(temp1,4,1,buff1);
dtostrf(temp2,4,1,buff2);
sprintf(buff, "%4s%cC , %4s%cC",buff1,0xDF,buff2,0xDF);
dispLCD_msg(yymmddhhmmss,buff);
write_logfile(timestamp,buff1,buff2); // microSDに書き込み
}
}
float temp_sensing(const int sensor) {
float offset;
uint32_t voltage_mV = 0;
const int N = 100;
for ( int i = 0 ; i < N ; i++ ) {
int adcRaw = analogRead(sensor);
// ADC値 → 電圧(mV)(補正済み)
voltage_mV += esp_adc_cal_raw_to_voltage(adcRaw, &adc_chars);
}
// 電圧 → 温度(℃)
float temperatureC = ((float)voltage_mV/N - 500.0) / 10.0;
// 温度センサ毎の校正
if (sensor==SENSOR_PIN1) offset = -0.9;
else offset = -1.2;
return temperatureC + offset;
}
void dispLCD_msg(char msg1[],char msg2[]) {
lcd.clear();
lcd.setCursor(0, 0); // Col,Raw
lcd.print(msg1);
lcd.setCursor(0, 1); // Col,Raw
lcd.print(msg2);
}
void write_logfile(char* timestamp, char* buff1,char* buff2){
char buff[32];
File outputFile = SD.open(LogFile,FILE_APPEND);
sprintf(buff,"%s,%s,%s",timestamp,buff1,buff2);
outputFile.println(buff);
outputFile.close();
}
void SetupLCD() {
delay(150);
lcd.begin();
lcd.command(0x38);
delay(1);
lcd.command(0x39);
delay(1);
lcd.command(0x14);
delay(1);
lcd.command(0x71);
delay(1);
// lcd.command(0x51); // 5V
lcd.command(0x56); // 3.3V
delay(2);
lcd.command(0x6c);
delay(300);
lcd.command(0x38);
delay(1);
lcd.command(0x01);
delay(2);
lcd.command(0x0c);
delay(2);
}
// Wifi接続
bool wifi_connect() {
char msg[128];
bool connected = false;
for (int i=0;i<3;i++) { // WiFi接続、3回繰り返す
WiFi.begin(ssid, password);
long int StartTime=millis();
while (WiFi.status() != WL_CONNECTED) {
delay(500);
if ((StartTime+5000) < millis()) break; // 5秒待って繋がらないときは諦める
}
if (WiFi.status() == WL_CONNECTED) {
IPAddress ip = WiFi.localIP();
sprintf(msg,"%d.%d.%d.%d",ip[0], ip[1], ip[2], ip[3]);
dispLCD_msg("Connected IP ",msg);
connected = true;
break;
}
delay(100);
}
if (connected)
return true;
else {
wifi_disconnect();
delay(100);
return false;
}
}
void wifi_disconnect() {
WiFi.disconnect(true);
WiFi.mode(WIFI_OFF);
}
int read_setup_file(char* fileName) {
char buff[128];
char key[128],val[128];
File setupFile = SD.open(fileName,FILE_READ);
if (setupFile) {
while (readLine(setupFile,buff)>=0) {
if (buff[0]!='#') {
sscanf(buff,"%s %s",&key,&val);
if (strcmp(key,"SSID")==0) {
strcpy(ssid,val);
}
else if (strcmp(key,"PW")==0) {
strcpy(password,val);
}
else if (strcmp(key,"Interval")==0) {
int ival;
sscanf(val,"%d",&ival);
if (ival>=0 && ival<interval_tbl_size) { // 異常値チェック
interval_i = ival;
}
}
}
}
setupFile.close();
}
return 0;
}
// microSDから1行読み取る
int readLine(File fp, char *buff){
int i = 0;
if(!fp.available()) {
return -1;
}
while (fp.available()) {
char c = fp.read();
if (c=='\r');
else if (c=='\n') break;
else buff[i++] = c;
}
buff[i] = 0;
return i;
}
/**
* 重複しないファイル名を生成する関数 (ChatGPTに書いてもらった)
* @param fs_prefix マウントポイント (例: "/spiffs")
* @param base_name 元のファイル名 (例: "data.txt")
* @param out_path 結果を格納するバッファ
* @param max_len バッファの最大サイズ
*/
void get_unique_filename(const char* fs_prefix, const char* base_name, char* out_path, size_t max_len) {
char temp_path[128];
char name_part[64];
char ext_part[16];
// 拡張子を探す
const char *dot = strrchr(base_name, '.');
if (dot) {
size_t name_len = dot - base_name;
strncpy(name_part, base_name, name_len);
name_part[name_len] = '\0';
strcpy(ext_part, dot);
} else {
strcpy(name_part, base_name);
ext_part[0] = '\0';
}
// 最初は元の名前でチェック
snprintf(out_path, max_len, "%s/%s", fs_prefix, base_name);
struct stat st;
int counter = 1;
// ファイルが存在し続ける間、ループ
while (SD.exists(out_path)) {
// "パス/ベース名 + 数字 + 拡張子" を組み立て
snprintf(out_path, max_len, "%s/%s_%d%s", fs_prefix, name_part, counter, ext_part);
counter++;
// 無限ループ防止(必要に応じて)
if (counter > 999) break;
}
}
//---------------------------------------------------------------------------------------
// EOF
//---------------------------------------------------------------------------------------