K型熱電対温度計データロガーをESP32-C3(Rust)で作り、InfluxDBで表示する
どんなもの
前回、以下を作る時に、ハンダづけの現在の温度と過去の温度の経緯を知る必要がありました。そこで、データを記録できて、グラフをリアルタイム表示するK型の熱電対温度計を作ろうと考えました。
熱電対の温度を測定するのは、デジタルコンバータ(MAX31855KASA+)です。SPIで熱電対の温度データを読み込みことができます。そのSPIを読み込むために、Wi-Fiを搭載したマイコンESP32-C3を使います。マイコンがデータを読み込み、そのデータをESP32-C3の搭載のWi-FiでLinuxサーバに送り、Linuxサーバにある時系列データベースのInfluxDBにデータを蓄積します。そして、そのダッシュボード表示機能で、温度のグラフ、現在温度をリアルタイムに表示します。また記録することで、過去のデータも簡単に参照できます。また、せっかくWi-Fiでデータを送信するようにしましたので、電源をLi-Po電池にして、USBポートからの充電で、測定時は、USBポートがなくても簡単に測定できるようにしました。電池の容量次第(今回1100mAh)ですが、1回の充電で48H以上動作しました。
InfluxDBのダッシュボードで温度・バッテリ電圧のデータをグラフ表示
今回、ESP32-C3のプログラムは、Rustで作りました。InfluxDBへのデータ送信はHTTPS(TLS)が使用できないと接続できないのですが、まだ、ESP32-C3のRust環境では使用できないので、HTTPで一度、サーバに送り、サーバ内のエージェントプログラムでHTTPSに変換して、InfluxDBのAPIに接続しています。この部分はNode.js+JavaScriptで行いました。
基板、回路図、プログラムは以下にあります。
ケース (2023/9/4追加)
部品集め
まずは部品集めです。K型熱電対は、-270℃~+1372℃まで測定できますが、ハンダの温度なので、400℃まで測定できればいいので、400℃ぐらいまでの安価なK型熱電対プローブをAmazonより購入しました。Li-Po電池、ディスプレイモジュール(SSD1306)も同じくAmazonからです。
ESP32-C3マイコンはWi-Fiがあるので、日本の場合、マイコンチップから使って作ることができません。作っても技術基準適合証明(いわゆる技適)が必要なので、技適取得済みのモジュールが売っていましたので、それを使用しました。
また、熱電対の温度を測定するデジタルコンバータMAX31855KASA+も同じく秋月電子から購入しました。マイコンより3倍も高いのは驚きです。マイコンが安すぎなんでしょう。
プローブを接続するソケットとバッテリ充電コントローラICです。
その他の部品を含めてBOM.csvに記載してあります。Digikeyか秋月電子より購入できます。
インタフェースはこのようなものです。(写真上部の抵抗はバッテリ電圧を測定するために後付けのものです。回路図、基板は修正してあります)
回路図を作る
回路図のポイントは以下です。
ESP32-C3モジュールの接続図です。USBをIO18, 19にIO0,IO1に32.768KHzの水晶発振子をつけています。IO9は10Kの抵抗でプルアップし、BOOTスイッチでGNDに落とします。IO8も10Kでプルアップします。IO2はADCがついているので、バッテリの電源を20Kで分圧して入力します。
K型熱電対のプローブをMAX31855KASA+のデジタルコンバータに接続し、SPIでESP32-C3のSCK-IO3, SO-IO4, CS-IO5に接続します。
128x64ドットのOLED白色ディスプレイモジュール(SSD1306)は、I2Cなので、SCL-IO8, SDA-IO9に接続します。
Li-Poバッテリの充電コントローラ(MCP73831-2)は、PROGピンに2Kの抵抗を付けて、充電電流を500mA(1000V/2K=500mA)に制限しています。VBATピンはバッテリへの出力で、Pch-MOSFETで負荷側に繋ぎます。USB電源使用時の逆流防止です。STATを2つのLEDで接続すると、充電時にはSTATはLOWになり、上側の赤色LEDが充電時に点灯し、充電が満了すると、HIGHになって下型の緑色LEDが点灯します。VOUTは、レギュレータ(SPX3819M5)にて+3.3Vに落とされ、ESP32-C3の電源などに入ります。
SW101がSTART/STOPスイッチになります。ESP32-C3のIO20に接続し、押されて動作開始した時に、スイッチ内蔵のLED点灯するようにIO6のGPIOで制御します。同様に、SW102がSENDスイッチでIO21で入力を検知し、IO7のGPIOでLEDを点灯します。
最後に、PWM出力用のポートを付けておきます。将来、フォトカップラの電源制御用にPWM信号出力ができるポートです。(今回は制御していません。)
基板設計
ESP32-C3は裏面に配置し、アンテナ部分を出すようにしています。飛び出したアンテナを保護する意味で、両端を膨らませています。この部分にはアンテナからの電波の妨害にならないようGNDのパターンつけないようにしています。
表面にディスプレイモジュールとK端子のソケット、プッシュSWを両端に配置します。熱電対デジタルコンバータ(U103)は、ノイズの影響を受けないように背面のESP32-C3のから一番遠いところかつ、K端子ソケットに近いところに置きました。
PCBレイアウト
Rustのコーディング
Rustの勉強を兼ねて、今回はコードをRustで実装しました。Rustで書いたプログラムがESP32-C3のような小さなマイコンで、しかもRISC-Vで動きます。Rustの環境設定等、以下の書籍がたいへん参考になりました。
コードはメインを含め大きく6つあります。
ファイル名 | 説明 |
---|---|
src/main.rs | ペリフェラルの初期化と主要ループで100ms毎のスイッチイベント確認と1秒毎の温度測定をします |
src/displayctl.rs | ディスプレイモジュールに文字、図を表示するスレッドです。100ms毎に現在温度表示や点滅、ステータスを表示更新します。 |
src/pushswitch.rs | プッシュスイッチの操作のイベントの受信処理、チャタリング防止のカウントを行うスレッドです。SWの割り込みイベントまたは10ms毎のタイムアウトでプッシュSWの状態を確認します。 |
src/templogs.rs | 温度を記憶するテーブルクラスです。ベクタで毎秒の温度を記録します。 |
src/transfer.rs | 温度データをHTTPで送信するスレッドです。SENDプッシュボタンが押された後、上記のテーブルに未送信のデータがあれば送信します。 |
src/wifi.rs | Wi-Fiアクセスポイントに起動時に接続します。 |
img/* | ディスプレイモジュールに表示するアイコンのイメージです。数字フォント、バッテリ量、Wi-FiマークのBMPデータです。 |
メインのコードについて説明します。
use std::{thread, time::Duration};
use esp_idf_hal::{gpio::*, prelude::*, spi, i2c};
use esp_idf_hal::peripherals::Peripherals;
use esp_idf_hal::ledc::{config::TimerConfig, LedcDriver, LedcTimerDriver};
use embedded_hal::spi::MODE_0;
use log::*;
use std::time::SystemTime;
use esp_idf_hal::adc::config::Config as AdcConfig;
use esp_idf_hal::adc::AdcChannelDriver;
use esp_idf_hal::adc::AdcDriver;
use esp_idf_hal::adc::Atten11dB;
// 各モジュールをロード
mod pushswitch;
mod displayctl;
mod templogs;
mod wifi;
mod transfer;
use pushswitch::PushSwitch;
use displayctl::{DisplayPanel, LoggingStatus, WifiStatus};
use templogs::{TempRecord, TempLog};
use transfer::Transfer;
// WiFiの設定値、データの送信先IPアドレスをcfg.tomlに設定し、その変数名をここでマッピングします。
#[toml_cfg::toml_config]
pub struct Config {
#[default("")]
wifi_ssid: &'static str,
#[default("")]
wifi_psk: &'static str,
#[default("")]
http_server: &'static str,
}
// 1つの温度データの構造体 tr: 測定温度、msg: エラー時のメッセージ
struct Temperature {
_ta: f32,
tr: f32,
msg: String,
}
fn main() -> anyhow::Result<()> {
// Rustでのesp_idfライブラリ使用時には指定するおまじない //
esp_idf_sys::link_patches();
// loggerーを初期化 info!()でcargo monitorで表示
esp_idf_svc::log::EspLogger::initialize_default();
// Peripherals Initialize ペリフェラル初期化
let peripherals = Peripherals::take().unwrap();
// PWM POWER-CTL-OUTのPWM出力を0にしておく。
let timer_driver = LedcTimerDriver::new(peripherals.ledc.timer0, &TimerConfig::default().frequency(50.Hz().into())).unwrap();
let mut pwm_driver = LedcDriver::new(peripherals.ledc.channel0, timer_driver, peripherals.pins.gpio10).unwrap();
pwm_driver.set_duty(0).expect("Set duty failure");
// SPI Temperature MAX31855との接続SPIを初期化 sdo_not_usedは、gpio1の使用していないポートを指定
let spi = peripherals.spi2;
let sclk = peripherals.pins.gpio3;
let sdi = peripherals.pins.gpio4;
let sdo_not_used = peripherals.pins.gpio1;
let cs1 = peripherals.pins.gpio5;
let spi_config = spi::SpiConfig::new().baudrate(1.MHz().into()).data_mode(MODE_0);
let spi_driver = spi::SpiDriver::new(
spi,
sclk,
sdo_not_used,
Some(sdi),
spi::Dma::Disabled,
).unwrap();
// SPIデバイス2ch分の測定が可能なようにSPIデバイスを共有(今回は1CHのみ)
let spi_shared_device = spi::SpiSharedDeviceDriver::new(spi_driver, &spi_config).unwrap();
let mut spi1 = spi::SpiSoftCsDeviceDriver::new(&spi_shared_device, cs1, esp_idf_hal::gpio::Level::High).unwrap();
// Display SSD1306ディスプレイモジュールの接続はI2Cとする
let i2c = peripherals.i2c0;
let scl = peripherals.pins.gpio8;
let sda = peripherals.pins.gpio9;
let config = i2c::I2cConfig::new().baudrate(1.MHz().into());
let i2c = i2c::I2cDriver::new(i2c, sda, scl, &config)?;
let mut dp = DisplayPanel::new(); // Displayスレッド起動
dp.start(i2c); // 初期化したI2Cポートを渡す
// PushSW スイッチ類のGPIOポートの初期化
let startstop_pin = peripherals.pins.gpio20;
let send_pin = peripherals.pins.gpio21;
let startstop_sig = Box::new(PinDriver::input(startstop_pin)?);
let send_sig = Box::new(PinDriver::input(send_pin)?);
let mut psw = PushSwitch::new();
psw.start(startstop_sig, send_sig); //スイッチ監視スレッドの起動
let mut startstop_led = PinDriver::input_output(peripherals.pins.gpio6)?;
let mut sending_led = PinDriver::input_output(peripherals.pins.gpio7)?;
startstop_led.set_low()?; // START/STOP PUSHスイッチのLEDをOFF
sending_led.set_low()?; // SENDING PUSHスイッチのLEDをOFF
// Temperature Logs 測定データを保存する場所を初期化
let mut tlogs = TempRecord::new();
// WiFi Wi-Fi接続
let wifi_enable : bool;
let wifi = wifi::wifi_connect(peripherals.modem, CONFIG.wifi_ssid, CONFIG.wifi_psk);
match wifi {
Ok(_) => { wifi_enable = true; },
Err(e) => { info!("{:?}", e); wifi_enable = false }
}
let mut txd = Transfer::new(CONFIG.http_server.to_string()); // 送信スレッド初期化
txd.start()?; // 送信スレッド起動
// ADC バッテリ電圧測定用のADC初期化
let mut adc = AdcDriver::new(peripherals.adc1, &AdcConfig::new().calibration(true))?;
let mut adc_pin: esp_idf_hal::adc::AdcChannelDriver<'_, Gpio2, Atten11dB<_>> =
AdcChannelDriver::new(peripherals.pins.gpio2)?;
// loop 100ms毎の実行ループ
let mut count : u32 = 0;
let mut logging_start = false;
let mut sending_start = false;
let mut now = SystemTime::now();
loop {
thread::sleep(Duration::from_millis(100));
// START/STOPボタンの状態を読み、それに従いデータロガーを開始、ストップする。
let start_stop_btn = psw.get_gpio_state(20);
let sending_btn = psw.get_gpio_state(21);
if start_stop_btn == true {
if logging_start == true {
// to Stop
logging_start = false;
dp.set_current_status(LoggingStatus::Stop);
tlogs.dump();
tlogs.clear();
startstop_led.set_low()?;
}
else {
// to Start
logging_start = true;
info!("Logging Start..");
now = SystemTime::now();
dp.set_current_status(LoggingStatus::Start);
startstop_led.set_high()?;
}
}
// SENDボタンが押されたらデータ送信開始
if sending_btn == true {
if sending_start == true {
// Stop Sending
sending_start = false;
sending_led.set_low()?;
if logging_start == true {
dp.set_current_status(LoggingStatus::Start);
}
else {
dp.set_current_status(LoggingStatus::Stop);
}
}
else {
// Start Sending Data
sending_start = true;
sending_led.set_high()?;
}
}
// Wi-Fiの接続状態をディスプレイに表示指示する。
if wifi_enable == false{
dp.set_wifi_status(WifiStatus::Disconnected);
}
else {
dp.set_wifi_status(WifiStatus::Connected);
}
count += 1;
if count % 10 != 0 {
continue;
}
// 以下1秒毎に実行
// Read Power Voltage mV ADCから現在のバッテリ電圧を測定しディスプレイに表示 2倍して1000で割るとV値
let pvol = adc.read(&mut adc_pin).unwrap() as f32 * 2.0 / 1000.0;
dp.set_power_voltage(pvol);
// Read Temperature K点の温度を測定
let mut temp = [0u8; 4];
let mut data = TempLog::default();
data.vol = pvol;
match spi1.read(&mut temp) {
Ok(_v) => {
let temp1 = get_temp(&temp);
match temp1 {
Ok(v) => {
dp.set_panel_temp(v.tr);
data.pt = v.tr;
}
Err(e) => {
dp.set_err_message(1, e.msg);
data.pt = -99.99;
}
}
},
Err(e) => { info!("{:?}", e); }
}
// 測定開始からの時刻msを記録
data.clock = now.elapsed().unwrap().as_millis() as u32;
if logging_start {
tlogs.record(data); // メモリに記録
}
if wifi_enable == true && sending_start == true {
let logs = tlogs.get_all_data(); // Wi-Fiが有効でSENDボタンが押されたら すべての記録したデータを取り出し
let txcount = txd.set_transfer_data(logs); // HTTPで送信先IPアドレスに送信
if txcount > 0 {
tlogs.remove_data(txcount); // 送信が完了した分をメモリから削除
}
}
}
}
MAX31855KASA+からの4バイトのデータと温度の取り出しの方法です。0バイト目のデータを32ビットの変数に入れ、6ビットシフトし、残りのD23~D18のビットを入れられるようにします。1バイト目のD23~D18を取り出すために、2ビット右にシフトして、D23~D18の6bitのデータを先ほどの、変数の6bitにORしてセットします。これでD31~D18の符号付のデータにします。これに0.25倍することで熱電対の温度が求まります。また、MAX31855には、IC内部の温度も取れます。こちらは0.0625倍します。D2, D1, D0はエラービットです。プローブがショートしたり、接続されていない(断線)したときにビットが立ちます。
// 4バイトのデータから温度を取り出す
fn get_temp(temp: & [u8; 4]) -> Result<Temperature, Temperature>
{
let msg;
match temp[3] & 0x07 {
0x01 => { msg = "OC ERROR" }, // 3バイト目のBit0が1ならオープンエラー プローブが接続されていない
0x02 => { msg = "SCG ERROR" }, // 3バイト目のBit1が1ならGNDにショート プローブがGNDにショートしている
0x04 => { msg = "SCV ERROR" }, // 3バイト目のBit2が1ならVCCにショート プローブがVCCにショートしている
_ => {
// 正常時
// 0byte目を6bit左にシフト、1バイト目を2bit右にシフトしてORしたものに0.25倍するとK点の温度
let tempval : i32 = (((temp[0] as i8) as i32) << 6) | ((temp[1] >> 2) as i32); // 熱電対温度
let intempval : i32 = (((temp[2] as i8) as i32) << 4) | ((temp[3] >> 4) as i32); // IC内部温度 0.0625倍
let ta = (intempval as f32) * 0.0625;
let tr = (tempval as f32) * 0.25;
return Ok(Temperature { _ta: ta, tr: tr, msg: "OK".to_string() });
}
}
Err(Temperature { _ta: 0.0, tr: 0.0, msg: msg.to_string() })
}
起動時にスタックメモリが不足し再起動してしまう
ESP32-C3で上記コードを動かそうとすると、スレッドのスタックメモリサイズが不足し、再起動を繰り返してしましました。スレッド内のローカル変数やフォントのデータが多いためですが、メインタスクのスタック拡張だけではダメで、sdkconfig.defaults
にCONFIG_PTHREAD_TASK_STACK_SIZE_DEFAULT
でサイズを指定するとスレッドスタックメモリを拡張できます。デフォルトはメインタスクと同じ3KBのようですので、メインタスクと同じように24KBに拡張しています。
CONFIG_ESP_MAIN_TASK_STACK_SIZE=24000
CONFIG_PTHREAD_TASK_STACK_SIZE_DEFAULT=24000
CONFIG_RTC_CLK_SRC=RTC_CLK_SRC_EXT_CRYS
ESP_SYSTEM_RTC_EXT_XTAL=y
ちなみにsdkconfig.defaults
はどこでコンパイラに指定されているかというと、.cargo/config.toml
で指定します。
[env]
ESP_IDF_VERSION = { value = "tag:v4.4.1" }
ESP_IDF_SDKCONFIG_DEFAULTS = { value = "./sdkconfig.defaults", relative = true }
フラッシュメモリのパーティションを変更
また、コード量も大きくなり、デフォルトのフラッシュメモリのパーティションサイズでは入りません。Cargo.toml
に以下を追加し、パーティションテーブルのCSVファイルpartitions.csv
を作成し、パーティションを変更します。
[package.metadata.espflash]
partition_table = "partitions.csv"
# ESP-IDF Partition Table
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0x9000, 0x6000,
phy_init, data, phy, 0xf000, 0x1000,
factory, app, factory, 0x10000, 3M,
コードのビルド
Ubuntu 22.04.2 LTSでコンパイルしています。
- Rustコンパイラのインストール
$ sudo apt -y install git python3 python3-pip gcc build-essential curl pkg-config libudev-dev libtinfo5 clang libclang-dev llvm-dev udev
$ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
select No.1
$ source "$HOME/.cargo/env"
- RISC-Vツールチェインのインストール
$ cargo install ldproxy
$ cargo install espup
$ rustup toolchain install nightly --component rust-src
$ rustup target add riscv32imc-unknown-none-elf
$ cargo install cargo-espflash
- UDEVルールの追加
ESP32-C3には、USB経由でプログラムを転送、書込みをします。そのUSBデバイスがRoot権限がなくとも書けるようにUDEVルールを追加します。
$ sudo sh -c 'echo "SUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"303a\", ATTRS{idProduct}==\"1001\", MODE=\"0666\"" > /etc/udev/rules.d/99-esp32.rules'
$ sudo udevadm control --reload-rules
$ sudo udevadm trigger
- Temp-Loggerのコードのダウンロード
$ git clone https://github.com/hnz1102/temp-logger.git
$ cd temp-logger/src/temp-logger
- 接続するアクセスポイントのSSIDとパスワード、InfluxDBのエージェントが動作するPCのIPアドレスを設定ファイルに指定します。
src\temp-logger\cfg.toml
[templogger]
wifi_ssid = "<your-AP-ssid>" # Set your AP ssid. 例: wifiap-1111
wifi_psk = "<your-AP-Password>" # Set password for ssid 例: wifi-password
http_server = "<PC address>:3000" # Set IP address and port. port should be 3000. 例 192.168.2.100:3000
- Temp-loggerとUSBで接続し、通信するポートを指定します。ツールチェインにコンポーネントを追加します。
$ cargo espflash board-info
select /dev/ttyACM0
Chip type: esp32c3 (revision v0.4)
Crystal frequency: 40MHz
Flash size: 4MB
Features: WiFi, BLE
MAC address: xx:xx:xx:xx:xx:xx
$ rustup component add rust-src --toolchain nightly-2023-06-10-x86_64-unknown-linux-gnu
- ビルドして、Temp-LoggerのESP32-C3内にあるフラッシュメモリに書込みます。
$ cargo espflash flash --release --monitor
App/part. size: 950,864/3,145,728 bytes, 30.23%
[00:00:00] [========================================] 12/12 0x0
[00:00:00] [========================================] 1/1 0x8000
[00:00:11] [========================================] 535/535 0x10000 [2023-08-03T13:05:12Z INFO ] Flashing has completed!
ビルド後、フラッシュに書込みがされて、起動します。ディスプレイモジュールに表示されれば完了です。
Wi-Fiが接続成功すれば、WiFiマークが点灯します。また、バッテリが接続されているとバッテリの電圧も表示されます。
InfluxDBのインストールとダッシュボード設定
- InfluxDBをinfluxDBダウンロードし、インストールします。
$ wget https://dl.influxdata.com/influxdb/releases/influxdb2-2.7.0-amd64.deb
$ sudo dpkg -i influxdb2-2.7.0-amd64.deb
$ sudo service influxdb start
- インストール後、ブラウザで以下の
http://<influxDB installed PC Address>:8086
を指定すると設定画面が表示されます。
GET STARTED
をクリックして、 Username
, Password
, Initial Organization Name
, Initial Bucket Name
を設定します。
項目 | 設定値 |
---|---|
Username | InfluxDB管理者のユーザ名 |
Password | InfluxDB管理者のパスワード |
Initial Organization Name | 組織名 例ORG |
Initail Bucket Name | LOGGER (エージェントプログラムと一致させる) |
セットしたら CONTINUE
をクリックします。
- APIトークンをコピー
画面にAPIアクセスするためのトークンが表示されます。これは一度きりなので、画面を閉じると表示されません。ここで、トークンをコピーしおきます。
CONFIGURE LATER
をクリックします。
- ダッシュボードのテンプレートをインポートします。
Dashboard
のアイコンをクリックし、CREATE DASHBOARD
のメニューから Import Dashboard
をクリックします。
Drop a file here
のところに、src/server/temp-logger_dashboard.jsonのファイルを置きます。IMPORT JSON AS DASHBOARD
をクリックして、インポートします。
インポートしたTemp-Logger Dashboard
パネルが見えますので、それを選択すると、ダッシュボードが表示されます。
ダッシュボードの表示内容や色など、カスタマイズがいろいろできます。
- エージェントをインストール
現時点では、Temp-LoggerのESP32-C3からInfluxDBへ直接データを送ることができません。SSLが使えないためで、HTTPSでInfluxDBのAPIをアクセスできません。そのため、エージェントプログラムで一度、HTTPをTemp-Loggerから受信し、先ほどのAPIトークンを使ってInfluxDBへアクセスしています。HTTPでの通信のため、セキュアではありません。ルータで制限されたLANや、ローカルネットワーク内のみで使用してください。
インストールする前にsrc/server/main.jsの設定を変更しておきます。token
には先ほどコピーしたAPIのトークン文字列をセットします。urlはInfluxDBがインストールされているPCのIPアドレスです。ORGは設定した組織名、bucketは同じLOGGERにします。
src/server/main.js
const token = "<influxDB API Access Token>"
const url = 'http://<influxDB installed IP address>:8086'
let org = `<YOUR ORGANIZATION NAME: it has to be same the Initial Organization Name>`
let bucket = `LOGGER`
エージェントをインストールします。systemctlを使うので、Linuxの管理権限が必要です。
$ cd src/server/
$ ./install.sh
インストールされてエージェントが動作すれば以下ようなメッセージが出てActive:
がactive (running)
になれば動作しています。
● influxdb-agent.service - InfluxDB Agent
Loaded: loaded (/lib/systemd/system/influxdb-agent.service; enabled; vendor preset: enabled)
Active: active (running) since Sat 2023-08-05 02:24:18 UTC; 15ms ago
- データロギングし送信
START/STOP
ボタンを押し、データをロギング開始します。そしてSENDボタンを押すとデータが送信されます。InfluxDBのダッシュボードには送信されたデータが表示されます。STOPボタンでデータのロギングを停止します。
なぜか正しい温度が表示されないことがある
測定した温度が、4096℃とか、10℃ほど低い値になることがありました。いろいろ、調べたところ、原因はUSBケーブルからのノイズでした。USBケーブルのシールド部分が触れているだけで、PCからのノイズと思われるのものに影響を受けて、正しい温度になりませんでした。それも、隣に付けていたUSBの照明をONにすると発生しました。MAX31855でいくつか、ノイズに弱いと記事とかあったのですが、USBケーブルのシールド線で影響するとは思いませんでした。今回、プログラムは、フラッシュメモリに書き込み、またバッテリを使用したので、充電時のみだけUSBケーブル接続するので測定には問題ありません。
最後に
実際に自分で作ってみると、いろいろな事を知ることができます。ほとんど、すんなり動いてくれないのですが、それが解決できると面白いです。今回は、MAX31855のノイズの問題と、ESP32-C3のスタックオーバで再起動、RustでESP32-C3のペリフェラルのインタフェースをスレッド内で動作させることが大変でした。少しでも参考になれば幸いです。ここまで読んでくださり、ありがとうございました。
Discussion