2026年11月8日日曜日

シリアル制御フルカラーテープLEDを使う(その4)

ここで少し横道にそれて、ArduinoでフルカラーテープLEDを扱ったらどんな具合か試してみた。秋月で Seeed Studio XIAO ESP32C3 とI2Cレベル変換モジュールを買ってテープLEDに繋げた。このESP32C3は160MHzのクロックで動く32ビットプロセッサなのでPICに比べて十分に高性能である。回路は誰が考えても同じようなものだろう。ESP32C3からの出力は3.3VレベルなのでI2Cレベル変換モジュールで5Vレベルに変換してLEDに与える。後で実際に試してみたら3.3Vレベルでも動いた。


回路は簡単なのでブレッドボード上に組み立てた。

Copilotに相談して作ったテストスケッチは次の通り。

#include <FastLED.h>

#define LED_PIN     10   // LEDのDINに接続したGPIOピン番号
#define NUM_LEDS    120  // LEDの総数
#define BRIGHTNESS  64   // 明るさ(0〜255)最初は電力消費を抑えるため低めに設定

CRGB leds[NUM_LEDS];

void setup() {
  Serial.begin(115200);
  // put your setup code here, to run once:
  // SK6812のRGBモデルは通常「GRB」の順序でデータを受け取ります
  // もし色が赤と緑で反転する場合は、GRBをRGBに変更してください
  FastLED.addLeds<SK6812, LED_PIN, GRB>(leds, NUM_LEDS);
 
  // 全体の明るさを制限
  FastLED.setBrightness(BRIGHTNESS);
 
  // 起動時に一度すべて消灯
  FastLED.clear();
  FastLED.show();
  Serial.println("*** Program Start");
}

void loop() {
  // put your main code here, to run repeatedly:
  // パターン1: 1つずつ順番に点灯(流れる光)
  for(int i = 0; i < NUM_LEDS; i++) {
    leds[i] = CRGB::Blue; // 青色に設定
      FastLED.show();
    delay(20);
    leds[i] = CRGB::Black; // 次に進む前に消灯
  }

  // パターン2: 全体をゆっくりレインボーに変化させる
  for (int j = 0; j < 255; j++) {
    fill_rainbow(leds, NUM_LEDS, j, 5);
    FastLED.show();
    delay(10);
  }
}
 

 これで手間も要らず簡単に動いた。 更にESP32C3をスタンドアロンのアクセスポイント & DNS とする次のスケッチも作成した。
 
#include <WiFi.h>
#include <WebServer.h>
#include <FastLED.h>
#include <ESPmDNS.h>

#define LED_PIN     10
#define NUM_LEDS    120
CRGB leds[NUM_LEDS];

// ★APモードのWi-Fi設定(好きな名前に変更できます)
const char *ssid = "ESP32-APmDNS";
const char *password = "12345"; // 8文字以上
const char *dnsname = "esp32";

WebServer server(80);

// スマホから「赤」ボタンが押されたときの処理
void handleRed() {
  fill_solid(leds, NUM_LEDS, CRGB::Red);
  FastLED.show();
  server.send(200, "text/plain", "Color changed to Red");
}

// スマホから「消灯」ボタンが押されたときの処理
void handleOff() {
  FastLED.clear();
  FastLED.show();
  server.send(200, "text/plain", "LED Off");
}

// 操作用の簡易ホームページを表示する処理
void handleRoot() {
  String html = "<html><body>";
  html += "<h1>ESP32 LED Controller2</h1>";
  html += "<p><button onclick=\"location.href='/red'\" 
        style='font-size:20px; padding:10px;'>RED</button></p>";
  html += "<p><button onclick=\"location.href='/off'\" 
        style='font-size:20px; padding:10px;'>OFF</button></p>";
  html += "</body></html>";
  server.send(200, "text/html", html);
}

void setup() {
  Serial.begin(115200);

  FastLED.addLeds<SK6812, LED_PIN, GRB>(leds, NUM_LEDS);
  FastLED.clear();
  FastLED.show();

Serial.println("*** Starting HTTP server.");
  // ★APモードの開始
  WiFi.softAP(ssid, password);
Serial.println("HTTP server started");

Serial.println("*** Starting mDNS.");
  if (!MDNS.begin(dnsname)) {
    Serial.println("Error setting up mDNS responder!");
    while(1) { delay(1000); }
  }
Serial.println("mDNS responder started. Hostname: esp32.local");

  // アクセス先URLの設定
  Serial.println("*** Allocating access dir.");
  server.on("/", handleRoot);
  server.on("/red", handleRed);
  server.on("/off", handleOff);
  server.begin();

// 5. mDNSに「HTTPサービス(ポート80)」を提供していることを登録(オプション)
  MDNS.addService("http", "tcp", 80);

  Serial.println("ESP32 Serial RGB-LED Driver & APmDNS Ready!");
}

void loop() {
  server.handleClient(); // スマホからのアクセスを常に監視
}
 

このスケッチでは、携帯でWiFiを”ESP32-APnDNS”というアクセスポイントに接続(パスワードは12345)した後ブラウザを立ち上げ "esp32.local" というホストにアクセスすると、テープLEDを赤点灯にするか消灯するかのメニュー(ボタン)が表示される。 ボタンを押すとテープLEDが反応する。

 

(続く) 
 
 

2026年11月5日木曜日

シリアル制御フルカラーテープLEDを使う(その3)

発注していた基板が届き、組み立てた。

以前、超音波距離計のために作ったソフトを改造して書き込んでみた。いくつかのバグを修正して動いたがLEDが端から8~10個くらいしか光らない。オシロでLEDの制御波形を見ると単純なデータを出力させても1-LED内でのバイトデータ間の間隔が25μsもありLED間の間隔は更に大きく、SPIへの書き込み処理が間に合っていなくて、途中でリセット信号と判断されてしまうようだ。手っ取り早くCPUクロックを3MHzに落としたのが問題のようなので32MHzまで上げたい。しかし3MHz以外では波形を作るためのペリフェラルの構成を見付けつことが出来るだろうか?

とりあえずクロックを単純に32MHzまで上げてみたところ1-テープ(30-LED)全体を光らせる事は出来たが、(規格通りの波形ではないため当然だが)色のコントロールが全くできない。そこで回路をあれやこれや検討してみて、次の様に行う事とした。

最終的に生成するLEDの制御信号は1μs/bitとする。とするとSPIに与えるのクロックは1Mhzであるが、SPIのクロック選択にTME2-match/2が選べるのでTMR2で2Mhzを生成すればよい。TMR2の入力クロックはFosc/4固定、即ち8MHzだからTMR2で4分周すればよい。うまい事に8MHzを4分周するときにPWM5を組み合わせてで250nsのパルスを作る事が可能で、上手く収まる。そして出来上がったのが次の波形である。上のトレースがSPI1の出力即ちデータ(code)を表し、下のトレースがそれをLEDに与える制御信号である。データが1の時デューティサイクルが50%、データが0の時デューティサイクルが25%になっている事が分かる。

 そしてデータを与えれば思い通りに光らせる事が出来るようになった。


 制御信号の生成には次のような論理演算を使った。

1-code = SCK1

0-code = SCK1 & (T2-match + PWM5)    

PWMパルス = (0-code & /SDO1) + (1-code & SDO1) 

 ここでSDO1はSPI1のデータ出力、SCK1はSPI1のクロック出力である。T2-matchはTMR2の出力で125nsの幅があり、PWM5はPWM5の出力で同じく125nsの幅がありこれら2つを合成して250nsとしている。最後のPWMパルスの合成にはDSMを使った。このための各ペリフェラルの初期化は次の様に行った。

// TMR2 - Fosc/4(8MHz)÷4 -> 2 MHz
// T2-match issued when PR2==TMR2; Pw is 125ns 
    T2CONbits.T2CKPS    = 0x0;      // prescaler div by 1
    PR2                 = 3;        // devide by 4
    TMR2                = 0;
    T2CONbits.TMR2ON    = 1;
    //
// PWM5 - delayed T2-match(Pw 125ns)
    PWMTMRSbits.P5TSEL  = 01;       // TMR2
    PWM5DCH             = 1;        //
    PWM5DCLbits.PWM5DCL = 0;        //
    PWM5CONbits.PWM5POL = 0;        // 
    PWM5CONbits.PWM5EN  = 1;
    //
// SPI1
    SSP1CON1bits.CKP    = 0;        // IDLE Clock is Low
    SSP1CON1bits.SSPM   = 0x03;     // Master; CLK=T2-match / 2 = 1MHz
    SSP1STATbits.CKE    = 0;        // transition occurs when clk idl->actv 
    SSP1CON1bits.SSPEN  = 1;
    //
// CLC1 for CARH = SCK1
    CLC1CONbits.LC1MODE = 2;        // 4-AND
    CLC1SEL0            = 0x12;     // SCK1
    CLC1GLS0            = 0x02;     // SEL0
    CLC1GLS1            = 0;        // T
    CLC1GLS2            = 0;        // T
    CLC1GLS3            = 0;        // T
    CLC1POL             = 0x0e;
    CLC1CONbits.EN      = 1;
    //
// CLC2- for CARL = SCK1 & (TMR2match + PWM5)
    CLC2CONbits.LC2MODE = 0x02;     // 4-AND
    CLC2SEL0            = 0x12;     // SCK1
    CLC2SEL2            = 0x1a;     // T2-match
    CLC2SEL3            = 0x10;     // PWM5
    CLC2GLS0            = 0x01;     // SEL0
    CLC2GLS1            = 0;        // T
    CLC2GLS2            = 0xA0;     // SEL2 + SEL3
    CLC2GLS3            = 0;        // T
    CLC2POL             = 0x0B;     // 
    CLC2CONbits.EN      = 1;       
    //
// DSM
    MDSRCbits.MDMS      = 0x08;     // MOD source is SDO1
    MDCARHbits.MDCH     = 0x0C;     // source of CARH is CLC1
    MDCARHbits.MDCHPOL  = 0;
    MDCARHbits.MDCHSYNC = 0;
    MDCARLbits.MDCL     = 0x0D;     // source of CARL is CLC2
    MDCARLbits.MDCLPOL  = 0;
    MDCARLbits.MDCLSYNC = 0;
    MDCONbits.MDOPOL    = 0;        // output is idle low
    MDCONbits.MDEN      = 1;

このなかで分かりにくいのは (T2-match + PWM5)のロジックだと思う。T2-matchはTMR2のカウントアップ時点ではなくTMR2がフルカウント(即ちTMR2=PR2)の時にTMR2の1クロックの期間(即ち125μs)だけ発生する。またSPI1のシフトにはこれを2分周して使われる。即ちSPI1のクロック出力SCK1及びデータ出力SDO1が変化するのは T2-match の立ち上がりのタイミングだ。一方PWM5の出力はTMR2がゼロになる瞬間に始まりTMR2=PWMDCとなった時に終わる。これらはデータシートを読み込めば書いてあるかもしれないが英語を読むのは面倒なのでオシロスコープで観測して理解した。これらをタイミングチャートで書くと次の様になる。

今後は光の動きを作り込んでいく。

(続く) 

 

 

 

2026年10月24日土曜日

シリアル制御フルカラーテープLEDを使う(その2)

 さて、このSK6812にはどのような制御信号を与えれば良いのだろうか。仕様は次の様になっている。

 超音波距離計で使ったPL-9823と今回のSK6812の制御信号の違いは1を表すコードのデューティ比がPL-9823では75%(=3:1)だったのに対しSK6812では50%(=2:2)になっている点だ。この信号の生成には超音波距離計に準じて次の論理式で可能だろう。

    0 code = /SDO & SCK & Fosc/2

    1 code = SDO & SCK  

    PWMパルス = 0 code + 1 code 

ここでSDOはSPIの出力、SCKはSPIのクロック、そしてFosc/2はCLKRを使ってFoscを2分周して生成できる。 

このLEDを駆動する標準的なデータレートは800Kbpsだが、PIC16F18326で生成できるこれに近いデータレートは750Kbpsだ。1個のLEDに与えるデータは24bitなので1個駆動するのに32μsかかり、テープ1本即ち30個のLEDを駆動しようとすると1ms弱かかる。もしテープを10本繋げた場合でも(ソフトのオーバーヘッドを除けば)100回/秒の速度で書き換えが可能だ。

一方 ソフトを考えると1個のLEDに3バイト(=24bit)のデータバッファーが必要であり、30個なら90バイト、テープ10本なら900バイトが必要になる。PIC16F18326のスタティックメモリー(RAM)は2KBしかないのでこれくらいが限界と考えて良さそうだ。

 (続く)

 

シリアル制御フルカラーテープLEDを使う

知り合いから 店の前に置く看板を目立たせたいとの相談を受けた。色々考えたがシリアル制御のフルカラーテープLEDを使うのが応用範囲が広そうなので挑戦してみる事にした。要は前に作った「超音波距離計(その4)」に使ったフルカラーLEDの応用だ。

早速秋月に行って手頃なSK6812搭載の1mのテープを買ってみて超音波距離計に繋いでみた。

もちろん信号がLEDの仕様が合っていないので正常には動作しないがLEDの明るさや信号に応答する事は確認できた。

そこで早速回路を考えてみた。端子はそれほど必要ないので超音波距離計に使ったPIC16F18346 ではなく足の数の少ない PIC16F18326 を使う。この1mのテープの最大消費電力は6W/5Vなので最大1.2Aの電流が流れる。テープの両端には3端子のコネクタが接続されている。3端子の内訳は+/-の電源と制御用の信号だ。テープは直列に何本も繋げられるが、あまり長くすると最初のコネクタやテープに流れる電流が限界を超えるだろう。長く連結する場合は電源はテープごとに個別に与えるのが良さそうだ。

この回路で基板を起こした。大きさは5cm×5cm程度になった。
早速これを発注した。

(続く)

 

2026年9月17日木曜日

Arduino手習い(TFTディスプレイを使う)

 以前、PICに繋げるつもりで買ってデッドストックになっていたTFTディスプレイ(ILI9341)はESP32に繋げられそうなので試してみた。このTFTディスプレイにはタッチパネル(MSP2807)が付いている。次のWEBを参考にした。

ESP32 TFT with LVGL: Display Temperature on Line Chart (BME280)

プログラムをコンパイルしESP32に書込むとプログラムは何事も無く動いた。コンパイルにあたり1つ注意が必要なのはlvglライブラリーが最新バージョンの9.6.0ではなく9.2.xを選ぶ必要がある事だ。そうでないとコンパイルエラーで先へ進めない。

 上の写真を撮った時点ではタッチパネルは未配線であるが問題なく動いた。タッチパネルを配線してみたらタッチした反応が得られようになったが座標が正常には認識されていなかった。これはプログラム中305行目付近にある次の行のパラメータを2から0に変更したら正常になった(この事はプログラム中のコメントに記載されている)。

    touchscreen.setRotation(2);

 

TFTディスプレイが動いたことに気をよくしてプログラム(ウェザーステーション)にも挑戦した。

  ESP32 TFT with LVGL: Weather Station

これはインターネットから気象データを取得し気温や天気をグラフィックに表示するものだが、こちらは 、

最大1310720バイトのフラッシュメモリのうち、スケッチが1853116バイト(141%)を使っています。

 というフラッシュメモリーが足りないというエラーが出て実行できなかった。

最後に、TFTディスプレイに画像を表示させてみた。元ネタは次のWebだ。

    ESP32 with TFT: Display Image using LVGL – 2.8 inch ILI9341 240×320 

 指示に従って外部サイトを使って自分の画像データをプログラムで使える形に変換し image.h のファイル中に挿入、さらにimage.hの最後の方にある次の行に解像度を設定し、

        .w = 320,
        .h = 240,

プログラムと共にコンパイル・実行すると画像がTFTに表示された。


 参考までにESP32-DevKitC-32E、TFT(ILI9341)、BME280の接続関係は次図の通り。


 

 

 

2026年9月16日水曜日

フォノイコライザーを作る(その3)

 そうこうしている内に基板(PCB)の配達された。これまでの経験から、羽田で国内配送業者へ渡された翌日くらいには届く。

 早速、届いたPCBを組み立てた。

やはり220uFの電解コンデンサの大きさが際立っている。270Ωや270KΩはそのままの値が無かったので手持ちの抵抗を組み合わせて近い値を作った。

電源を入れ入力端子を解放したままで出力のレベルを測ると5mV程度出力がある。入力付近に指を近づけると出力が大きく増える。 一方入力端子を短絡すると出力は1mV以下まで下がる。入力回路にハムが乗っているようだ。

じっさい出力をオーディオアンプのAUX端子に入れ、入力側の10uFの無極性電解コンデンサの缶に触るとブーとハム音が出る。低周波のゲインが60dB近くあるので仕方ないが何とかしたい。シールドが必要だ。そこで0.2mm厚の銅板及び銅テープでシールドを作って入力部を覆うように組み付けた。


これにより無入力時のノイズ出力レベルは0.2mV以下まで下がった。60dBあるDCゲインを0dBに落とすための220uFのコンデンサを外してもDCのオフセットは0.1V程度だったので不要として取り外した。

とりえずこれで評価してもらおう。

 

 

 


 

 

 

 

 

 

2026年9月15日火曜日

Arduino手習い(WiFi WEBサーバ、気象データ(BME280)のグラフ表示)

 前回はBME280で測定した気象データ(気温、湿度、気圧)を数値で表示させたが、それらをグラフで表示させる事に挑戦した。参考にしたのは次のWEBページだ。

 ESP32/ESP8266 Plot Sensor Readings in Real Time Charts

 WEBページの指示通り予め表示用htmlファイルを作成し、ESP32 LittleFSファイルシステムアップローダ(ダウンロード&IDEへの追加が必要)を使ってESP32のフラッシュメモリーに書き込んだ。次にプログラム中にあるWiFiアクセスポイントのSSIDとパスワードを設定し、コンパイルすればそのまま動いた。 

ESP32に割り振られたIPアドレス(IDEのシリアルモニターに表示される)にPCや携帯のブラウザからアクセスすれば次のようなグラフが見られる。 



 グラフはサーバ側ではなくアクセスしたクライアント側で作成されるのでアクセスした時点ではスケールしか描画されておらず30秒~1分程度待たなければグラフにならないが、その後は30秒毎にデータが更新され3つのグラフが更新されていく。

データは小数点下2桁まで表示され、実用上はそのような分解能は必要ないが描画する上ではグラフに動きが出て面白い。 カーソルをプロット上に持っていくとそのデータ値と時刻が表示される。

とても面倒だと思っていたグラフ描画を簡単に実行できたので拍子抜けした。今回のプログラムを解析すれば今後のプログラミングに役立つだろう。今のところ時刻がUTCなのは良しとしよう。