以下の内容はhttps://negligible.hatenablog.com/entry/2025/11/19/014010より取得しました。


気圧計を作る ~ Seeed Studio XIAO ESP32C3編 ~

はじめに

前々回,前回と気圧計に関する記事を投稿して参りましたが,今回も同様の記事となります。ちょっとこれまでの主題と外れますが,「気圧計を作る」シリーズに入れてしまうことにします😅

本ブログに書いたことはありませんが,温湿度気圧センサBME280を用いた空気モニタからGoogle スプレッドシートに記録する装置(図1)を作り,ときどき稼働しておりました。秋月電子通商のキャラクタOLEDディスプレイを使って美しい文字を表示していましたが,残念なことに使用していたEPS32モジュール(互換基板)のmicroUSB端子の半田付けが劣化してしまい,動作が極めて不安定になってしまっておりました。修理または作り直しが必要だと思いながらも,しばらく放置しておりました。

図1: BME280とESP32マイコンを用いた空気モニタ(旧作)

そんな中,2020年頃から,Seeed Studio社による「XIAO」シリーズと呼ばれる各種の超小型マイコンボードが売り出されるようになりました(XIAOは中国語の「小 (xiǎo)」から来ているのでしょうね)。恐らく最初に発売されたSAMD21G18を搭載するもの(無印の「Seeed XIAO」または「Seeeduino XIAO」がコレでしょうか)をはじめとして,RP2040を搭載するもの,ESP32C3を搭載するものなど,ほぼピン互換,かつほぼ同じサイズで展開されており,秋葉原の電子部品ショップでも簡単かつ手頃*1に入手可能となっています。図2は本記事で用いたものと同じSeeed Studio XIAO ESP32C3です。10円硬貨と比べるとその小ささ(まさに「xiǎo」!)がお分かり頂けると思います。

図2: Seeed Studio XIAO ESP32C3

温湿度気圧をセンシングして表示し,Googleスプレッドシートに記録するだけであればピン数はそれほど必要ない…という訳で,超小型ながらWiFiにも接続可能なSeeed Studio XIAO ESP32C3(以下,単にXIAOとも呼びます)と,前回も使用したキャラクLCDを用いた空気モニタを新たに作ることにしました。

完成イメージ

図3に完成したSeeed Studio XIAO ESP32C3を用いた空気モニタを示します。

図3: Seeed Studio XIAO ESP32C3とBME280を用いた空気モニタ
ダイソーのディスプレイキューブLに全体が収まるように作っています。前面には16文字 × 2行を表示できるキャラクLCDと2つのタクトスイッチを設けました。左側のタクトスイッチを押すと:

  • 温湿度気圧モード
  • 時計モード
  • WiFiモード
  • 総合表示モード

の4つを切り替えることができます。図4にそれぞれのモードの表示例を示します。

図4: 4つの表示モード
なお,右側のタクトスイッチを押すとWiFi再接続を試みるようにしていますが,他に面白い使い方が思いついたら変えてみたいと思います。

ESP32C3はWiFiに接続できますので,測定した温度,湿度,気圧を1分毎にGoogle スプレッドシートに記録します。

図5: Google スプレッドシートに記録された温度・湿度・気圧

こんなに小さなマイコンWiFiを介してインターネットに繋がることは,一昔前では考えられませんでしたね。まさにIoT工作に最適なデバイスと言えるでしょう。

目次

ハードウェア構成

ケース実装状態

図3からも分かるかもしれませんが,基板は2枚構成となっています。図6に製作した2枚の基板を示します。1枚目(メイン基板)はXIAOとBME280を搭載したメイン基板で,秋月電子通商の45基板に実装しています。また,2枚目の基板(サブ基板)と接続するためのピンヘッダ(6ピン)を備えております。なお,XIAOから伸びているWiFi用アンテナがプラプラしているとケース実装が難しくなるので,後述のWiFi固定パーツを作りました。

図6: 2枚の基板による構成
2枚目の基板は秋月電子通商のD基板であり,バックライトつきキャラクタLCD (AQM1602Y-FLW-FBW)と2つのタクトスイッチを搭載しております。これはユーザーとのインターフェイスになりますね。

図7に示すように,45基板(一辺が45 mmの正方形であるためそう呼ばれる)はダイソーのディスプレイキューブLおよび同Mの底面にぴったりな大きさとなっています。アクリルのケースとしてもしっかりした作りになっており,これは電子工作に役立つと思い,何個かストックしてあります。

図7: ダイソーのディスプレイキューブLの底面と秋月電子通商の45基板

十字配線ユニバーサル基板

図8に十字配線ユニバーサル基板のカットパターンを示します。筆者は最近,電子工作をする際に回路図を描かず,最初からこのカットパターンの図で設計をするようになりました*2

なお,当初,メイン基板において,XIAOのD8, D9, D10ピンはGNDに直接接続し,ソフトウェアで入力に設定しておけば,広いGNDパターンとして使えると思っていたのですが,プログラムが書き込めない,シリアル通信ができないという問題が生じたため,図8の赤色で示したように修正しました。ピンヘッダに向かうGNDが0 Ω抵抗器を介すことになってしまったのは褒められた実装ではありませんね…💧

図8: 十字配線ユニバーサル基板のカットパターン
図8に示すように,XIAOに対してBME280もキャラクLCDもI2Cで接続されます。キャラクLCDは2枚目の基板に実装しているので,I2CのSDAとSCLはピンヘッダにも接続しています。また,2つのタクトスイッチからの信号線もピンヘッダに接続しております。

サブ基板では,キャラクLCDを基板からはみ出すように上方に実装することとし(そうしないとネジ穴に干渉してしまうため),タクトスイッチ2つを並べました。当初,普通の垂直型のピンヘッダを立てていたのですが,ケースに実装しようとしてみると,何とXIAOそのものに思いっきり干渉してしまうことが発覚したため,泣く泣く取り外して水平タイプを上向きに取り付けました。このとき,ユニバーサル基板のランドを破損したため,余っていた部品の足で電気的接続を取り直しました…。う~ん…残念…。3Dでの実装設計が必要ですね…。

WiFiアンテナ固定パーツ

前述のように,XIAOに付属のWiFiアンテナは数cmの細い同軸ケーブルの先に繋がっているシート状のものとなっており,XIAO上のIPEXコネクタに接続されます。このアンテナがプラプラしており,ケース実装の際に底面とキューブの間に挟まったりと破損の危険があるため,アンテナ固定パーツを作りました。

まず,図9に示すようにBlenderでアンテナ固定パーツを設計します。メイン基板を固定する四隅の3 mmネジの1つをつかって,シート状のアンテナを立てることを考えました。なお,アンテナには両面テープが付いているため,このパーツに貼り付けることができます。

図9: BlenderによるXIAOアンテナ固定パーツの設計
これを3Dプリンタで印刷し(図10),ダイソーのディスプレイキューブLの底面とメイン基板を固定するねじの1つを使って,図11のように立ててみました。
図10: 3Dプリンタで印刷したアンテナ固定パーツ
図11: アンテナ固定パーツ使用状態
これによってアンテナがプラプラすることがなくなり,誤って断線,破損してしまうリスクを低減できました。こういうちょっとしたパーツはうちにあるような安価な3Dプリンタの真骨頂と言ったところでしょうか。

メイン基板とサブ基板を接続してキューブに収める

メイン基板とサブ基板にはそれぞれ6ピンのピンヘッダを設けています。これをどこのご家庭にも1本はあるピンソケット付きケーブルで接続します。

図12: 両基板を収めたダイソーのディスプレイキューブLを上から

図13: 両基板を収めたダイソーのディスプレイキューブLを後ろから

実装状態は図12,13のようになりました。ピンソケット付きケーブルが長すぎたので束ねております。高速な信号ならば問題になったかもしれませんが,数100 kHz級であるI2Cでは問題なかったようです。

また,当たり前ですがXIAOに接続するためのUSBケーブルが通る孔と,BME280に外気をあてるための孔をあけました。

ソフトウェア構成

GitHubリポジトリ

GitHubリポジトリを設けましたので,コードの詳細についてはそちらをご覧ください。 github.com

全体構成

関数単位で見ると,下記のようになっております。

  • スタートアップ部: ライブラリのインクルードとオブジェクトやグローバル変数の定義
  • setup関数: 各種初期設定,SW1, 2が押された際の割り込みの設定,FeeeRTOSのタスクの作成
  • loop関数: 現在時刻の読み出し,気温・湿度・気圧の読み出し,LCDへの情報表示
  • connectWiFi関数: WiFiへの接続(配列として与えられたSSIDへの接続をトライ)
  • postGSS関数: Google スプレッドシートへのデータの送信
  • onSW1関数とonSW2関数: SW1, 2が押された場合の割り込みハンドラ

それぞれを簡単に説明していきます。

スタートアップ部

スタートアップ部では,下記のようにライブラリをインクルードしています。

#include <Wire.h>
#include <Adafruit_BME280.h>
#include "ST7032.hpp"

#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>

温湿度気圧センサBME280の制御にはAdafruitのライブラリを利用させて頂きました(PICでは自分で作りましたが,やはりArduinoの便利さはここにありますね)。また,WiFiに接続するためwifi.hはもちろんのこと,Google スプレッドシートに記録するためにWiFiClientSecure.h,HTTPClient.h,ArduinoJson.hをインクルードしています。また,キャラクLCDを制御するため,自作ライブラリST7032.hppをインクルードしています。

次に,BME280とキャラクLCDインスタンスを下記のように生成しています。

Adafruit_BME280 bme;
ST7032 lcd;

さらに,グローバル変数を多数定義しています。プログラミングのスキルがもっと高ければ,グローバル変数はこんなに必要ないのかもしれません。もしくはWiFiへの接続状態やGoogle スプレッドシートへのPOSTの状態などそれ自体をクラス・オブジェクトとして定義すれば,グローバル変数の数は減らせるのかもしれませんね。いずれにしてもソフトウェアについて筆者はドシロートなのでこのような形になってしまいました。

// Pins and I2C device settings
const int GPIO_SW1              = 20;
const int GPIO_SW2              = 5;
const int BME280_ADDR           = 0x76;
const int CONTRAST              = 44;

// WiFi settings
const int N_SSID                = 3;
const char* SSID[N_SSID]        = {"Your SSID 1", "Your SSID 2", "Your SSID 3"};
const char* PASSWORD[N_SSID]    = {"Your password 1", "Your password 2", "Your password 3"};
const int T_DELAY               = 1500;
const uint32_t T_WIFI_TIMEOUT   = 15000;
bool online;

// Constants and variables for NTP servers, date-time structure, and string
const char *server1             = "ntp.nict.jp";
const char *server2             = "time.google.com";
const char *server3             = "ntp.jst.mfeed.ad.jp";
const long JST                  = 3600L * 9;
const int summertime            = 0;
struct tm tm;
int tm_min_old                  = 0;
const char *months[]            = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
const char *dayofweek[]         = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
const char *dayofweek_short[]   = {"Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"};
char datebuf[32];
int tm_sec_old = 0;
unsigned long t_millis;

// Global variables to store latest measurement results
float t, h, p;

// Global variables to store tactile switch conditions
volatile bool sw1Pushed         = false;
volatile bool sw2Pushed         = false;
int scrMode                     = 0;

// Constants and variables for Google Spreadsheet API constants and variables
TaskHandle_t taskHandle_GSS;
const char* apiURL              = "Your Google Spreadsheet API URL";
int httpCode;
HTTPClient http;
bool postingNow = false;

setup関数

setup関数では各種の初期化や設定を行います。本システムで重要なポイントは下記です。

まず,connectWiFi関数を呼んでWiFiに接続します。WiFiに関わる様々な情報をグローバル定数に入れてしまったため,connectWiFi関数に引数はありません。さらに,configTime関数を呼んでNTPサーバから時刻を取得します。これで,本システムはNTP時計としても機能します(Google スプレッドシートに記録する際の時刻を得るため)。また,attachInterrupt関数にてタクトスイッチSW1, 2がそれぞれ押された場合の割り込みハンドラを定義します(onSW1, onSW2関数については後述)。

続くxTaskCreateUniversal関数では,Google スプレッドシートに記録するためのタスクを作成します。もちろんタスクとしてpostGSS関数を割り当てます。ESP32-DevKit Cなどに搭載されているESP32-WROOM-32Eとは異なり,ESP32C3は1コアしか搭載されておりません。そこで,タスクを実行するPRO_CPU_NUM (= 0)を指定します。コアが1つしかないので,Google スプレッドシートへの記録と温湿度・気圧の読み取りが干渉してしまうかと心配しましたが,問題なかったようです。

void setup() {

(中略)

  // Connect to WiFi
  connectWiFi();

  // Synchronize real-time cllock to NTP servers
  if (online) {
    configTime(JST, summertime, server1, server2, server3);
  }

  // Attach ISR for push switches
  attachInterrupt(GPIO_SW1, onSW1, FALLING);    
  attachInterrupt(GPIO_SW2, onSW2, FALLING);

  // Create task to post to Google Spreadsheet
  if (online) {    
    xTaskCreateUniversal(
      postGSS,              // Function to be run as a task
      "postGSS",            // Task name
      8192,                 // Stack memory
      NULL,                 // Parameter
      1,                    // Priority
      &taskHandle_GSS,      // Task handler
      PRO_CPU_NUM           // Core to run the task
    );
}

loop関数

ご存じのようにloop関数はsetup関数を抜けた後に繰り返し呼ばれます。この中での主な処理として,現在時刻の取得,SW1, 2の状態変化に対応する処理の記述,温湿度・気圧の読み取り,キャラクLCDへの表示,1分毎のGoogle スプレッドシートへの記録(タスクに通知を送信)を順に行います。

現在時刻の取得

WiFiに接続されていれば,setup関数内でconfigTime関数にてNTPサーバと同期しているはずです。loop関数内ではgetLocalTime関数にて現在時刻を取得することができます。

  // Get current time, if online
  if (online) {
    if (getLocalTime(&tm)) {
      // Store millis when second changes
      if (tm.tm_sec != tm_sec_old) {
        t_millis = millis();
      }
      tm_sec_old = tm.tm_sec;

      // Create string to post to Google Spreadsheet
      sprintf(datebuf, "%d-%02d-%02d %02d:%02d:%02d", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
    }
  }
SW1, 2の状態変化に対応する処理の記述

タクトスイッチSW1, 2がそれぞれ押されると後述の割り込みハンドラが呼ばれ,その中でbool型変数sw1Pushedとsw2Pushedがそれぞれtrueになります。loop関数内ではsw1Pushedとsw2Pushedを確認し,もしtrueであり,かつ,現在,SW1, 2が押されていなければ,それぞれの処理を実行します。SW1が押された場合,表示モードを1つ進めます(前述のようにモード1 ~ 4があります)。SW2が押された場合はWiFiへの再接続を試みるため,connectWiFi関数を呼びます。

  // Toggle display mode if switch pushed, clear LCD
  if (sw1Pushed) {
    // Toggle only if current GPIO_SW1 status is HIGH
    if (digitalRead(GPIO_SW1) == HIGH) {
      sw1Pushed = false;
      lcd.clear();
      scrMode = (scrMode + 1) % 4;
    }
  }

  if (sw2Pushed) {
    // Toggle only if current GPIO_SW1 status is HIGH
    // Reconnect to WiFi
    if (digitalRead(GPIO_SW2) == HIGH) {
      sw2Pushed = false;
      lcd.clear();
      connectWiFi();
    }
  }

それぞれの処理の後,sw1Pushedとsw2Pushedをfalseに戻します。このような処理にすれば,タクトスイッチのチャタリングを気にしなくて済みますね。

温湿度・気圧の読み取り

Adafruitのライブラリがあるためこれは非常に簡単であり,下記のみの記述となります。なお,前記事ではボタン電池の消費電力を削減するため,BME280をForced Modeで使用しましたが(0.5秒に1回だけ測定),Adafruitのライブラリにそのような機能があるのか分からなかったため,Normal Modeで使用しています(調べてみるとForced Modeも可能なようです)。

  // Read from BME280, recording into global variables
  t = bme.readTemperature();
  h = bme.readHumidity();
  p = bme.readPressure() / 100.0;
キャラクLCDへの表示

読み取った温度,湿度,気圧や現在時刻,IPアドレスなどを表示モードにしたがってキャラクLCDに表示します。ここでは自作ライブラリST7032.hppを使用しています。switch-case文で表示モードを判定して,表示内容を変えています。ここでは表示モード1 (scrMode = 0)の場合のみを例として以下に示します。

  // Show on LCD
  switch (scrMode) {

    // Show air conditions
    case 0:
    // Show on LCD, temperature
      lcd.setCursor(0x00);
      lcd.putString(String(t, 2));
      lcd.putChar((char) 0xdf);
      lcd.putString("C ");

      // Show in LCD, humidity
      lcd.setCursor(0x0a);
      lcd.putString(String(h, 2) + "% ");

      // Show in LCD, pressure
      lcd.setCursor(0x40);
      lcd.putString(String(p, 2) + " hPa ");

      break;

    // Show clock
    case 1:
      (中略)
      break;

    // Show IP address
    case 2:
      (中略)

      break;
    
    // Show date, time, and air conditions
    case 3:
      (中略)
  }
1分毎のGoogle スプレッドシートへの記録

現在時刻の分に相当するtm.tm_minを監視し,前回のloop関数実行時から変化があった場合,Google スプレッドシートに記録するためのタスクにxTaskNotify関数にて通知を送ります。

  // Post to Google Spreadsheet every minute
  if (online) {
    if (tm.tm_min != tm_min_old) {
      // Notify task to post to GSS
      xTaskNotify(taskHandle_GSS, 0, eIncrement);

      // Preserve minute value
      tm_min_old = tm.tm_min;
    }
  }

  // Show mark on LCD when posting to Google Spreadsheet
  if (scrMode != 3) {
    lcd.setCursor(0x4f);
    if (postingNow) {
      lcd.putChar('G');
    }
    else {
      lcd.putChar(' ');   // Space
    }
  }

また,Google スプレッドシートへの記録がそのタスクで進行中であるか否かをpostingNowという変数でやり取りします。もし進行中であれば,キャラクLCDのもっとも右下(カーソル位置0x4f)に「G」を表示します。

ウェイト

loop関数の最後で25 msのウェイトを入れております。loop関数内の各処理が何msを要するのか実測しておりませんが,時計の「秒」を表示するにあたって,loop関数の実行開始のタイミングが毎正秒(時刻の秒が変化したタイミング)で始まるように設定するのが困難でした。このため,力技ですがこのように1秒に対して十分に高速なloop関数の繰り返しになるようにして,毎度キャラクLCDへの表示を更新するようにしています。

将来的には(前々回の記事のように)温度,湿度,気圧の測定やキャラクLCDへの表示もFreeRTOSのタスクとし,正確なインターバルで実行するように変更しようかと考えているところです。

  // Wait
  delay(25);

connectWiFi関数

connectWiFi関数では,SSIDとPASSWORDという配列(char型の配列の配列)にそれぞれ格納されたSSIDとパスワードを使用してWiFiへの接続を試みます。また,接続を試行している過程をキャラクLCDに表示します。スタートアップ部にSSIDとPASSWORDをグローバル定数として定義・初期化していますが,将来的には(KiCadでプリント基板として再設計する?)microSDカードに格納されたSSIDとパスワードを使うように変更したいですね。

void connectWiFi() {
  for (int i = 0; i < N_SSID; i++) {
    // Wait for connection
    uint32_t tWiFi = millis();
    WiFi.begin(SSID[i], PASSWORD[i]);
    lcd.setCursor(0x00);
    lcd.putString("WiFi:");
    lcd.putString(SSID[i]);
    lcd.setCursor(0x40);
    lcd.putString("Connecting");

    while (WiFi.status() != WL_CONNECTED) {
      delay(T_DELAY * 2);
      lcd.putString(".");
      if (millis() - tWiFi > T_WIFI_TIMEOUT) {
        lcd.setCursor(0x40);
        lcd.putString("Failed!         ");
        delay(T_DELAY);
        lcd.clear();
        break;
      }
    }
    
    // Confirm connectionm, exit loop if connected
    if (WiFi.status() == WL_CONNECTED) {
      online = true;
      lcd.putString("OK!");
      delay(T_DELAY);
      
      // Show IP address
      uint32_t ip = WiFi.localIP();        
      int ip_octet_1 = (ip & 0x000000ff);        
      int ip_octet_2 = (ip & 0x0000ff00) >> 8;
      int ip_octet_3 = (ip & 0x00ff0000) >> 16;        
      int ip_octet_4 = (ip & 0xff000000) >> 24;
      char buf[32];
      sprintf(buf, "%d.%d.%d.%d", ip_octet_1, ip_octet_2, ip_octet_3, ip_octet_4);
      lcd.clear();
      lcd.setCursor(0x00);
      lcd.putString("IP:");
      lcd.putString(buf);
      lcd.setCursor(0x40);
      lcd.putString("RSSI:");
      lcd.putString(String(WiFi.RSSI()) + " dBm");
      delay(T_DELAY);
      lcd.clear();
      break;
    }
  }     
}

postGSS関数

postGSS関数は,時刻,温度,湿度,気圧をGoogleスプレッドシートに記録する関数です。また,前述のようにこの関数はsetup関数の中でFreeRTOSのタスクとして設定されております。変数を宣言した後,while (true)で無限ループを作り,その冒頭でxTaskNotifyWait関数を呼んで,通知が送られてくるのを待ちます。

通知を受けると,タスクが進行中であることを表す変数postingNowをtrueとし,Google スプレッドシートAPIにPOSTするためのJSONを生成します。時刻,温度,湿度,気圧はグローバル変数なので,それらを単にJSONのデータとしてセットし,シリアライズします。シリアライズ結果を文字列(char型配列)であるpubMessageに格納し,それをGoogle スプレッドシートAPIのURLにPOSTします。

void postGSS(void *pvParameters) {
  uint32_t ulNotifiedValue;
  char pubMessage[128];
  while (true) {
    // Wait for notification
    xTaskNotifyWait(0, 0, &ulNotifiedValue, portMAX_DELAY);

    // Flag up
    postingNow = true;
 
    // Create JSON message
    StaticJsonDocument<500> doc;
    JsonObject object = doc.to<JsonObject>();

    // Stuff data to JSON message and serialize it
    object["datetime"] = datebuf;
    object["temp"] = t;
    object["humid"] = h;
    object["press"] = p;
    serializeJson(doc, pubMessage);

    // Post to Google Spreadsheet API
    http.begin(apiURL);
    httpCode = http.POST(pubMessage);

    // Flag down
    postingNow = false;

    // Wait
    delay(100);
  }
}

Google スプレッドシート側ではGoogle App Scriptを準備しておき,POSTされてきたJSONから時刻,温度,湿度,気圧のデータを取り出してスプレッドシートの新しい行として追加したり,グラフを更新したりする処理を行います。Google App Script側については,本ブログの過去の記事で述べておりますので割愛させて頂きます。

negligible.hatenablog.com

onSW1関数とonSW2関数

これら2つの関数は,タクトスイッチが接続されているGPIOへの入力が立ち下がった場合(つまり,タクトスイッチが押された場合)の割り込みハンドラとしてsetup関数内で設定しています。当該部分を再掲します。

  // Attach ISR for push switches
  attachInterrupt(GPIO_SW1, onSW1, FALLING);    
  attachInterrupt(GPIO_SW2, onSW2, FALLING);

onSW1関数とonSW2関数は割り込みで呼ばれるので,その中での処理は極力短くしています。それぞれグローバル変数であるsw1Pushedとsw2Pushedというbool型の変数にtrueをセットしているのみです。sw1Pushedとsw2Pushedは前述のようにloop関数内でチェックされ,trueになっていればそれぞれに相当する処理を実行して,falseに戻すようにしています。

void IRAM_ATTR onSW1() {
  sw1Pushed = true;
}

void IRAM_ATTR onSW2() {
  sw2Pushed = true;
}

まとめ

以上,Seeed Studio XIAO ESP32C3とBosch Sensortec BME280を用いた空気モニタのハードウェアとソフトウェアについて述べました。ダイソーのディスプレイキューブLと同Mは秋月電子通商の45基板にピッタリですので,他の工作にも活かせそうですね。また,Blender3DプリンタにてXIAOのプラプラしているシート状のアンテナを固定するパーツを作りました。

ソフトウェアとしては以前から使用している関数や処理の寄せ集めではあるのですが,本ブログに記載したことがないものが多かったため,まとめて説明することにしました。Google スプレッドシートは1分毎の頻度であれば,うまくデータとグラフの更新ができるようです*3

さて,筆者は最近になってようやくKiCadの使い方を学び,JLCPCBに基板発注する経験を得たので,十字配線ユニバーサル基板を使う機会が減るかもしれません。次回は,前回ご紹介したPIC16F18326とBME280による気圧計の基板をKiCadで設計し,JLCPCBに発注した経緯を書きたいと思います。

*1:2025年11月現在,千石電商では990円でした。WiFiに繋がるマイコンがこの価格とは,隔世の感がありますね。

*2:ごく最近,KiCadを使うようになりましたので,その場合はもちろん回路図を描きます…。

*3:以前に本ブログに書いた商用電源監視装置は10秒毎の更新ですが,かなりの頻度でグラフが壊れてしまいます。要対策ですね。




以上の内容はhttps://negligible.hatenablog.com/entry/2025/11/19/014010より取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14