トドお父さん通信 -2ページ目

トドお父さん通信

北部九州在住 高BMI中高年のオタク趣味の活動記録

  完成したクリスマスツリーの動作です

 

前回の記事の続きです

今度は、120個のLEDストリップから6個のLEDを切り出した残り114個を光らせます。


ラジオペンチさんのこちらの記事、Arduino nanoのプログラムをSTM32F103C8に移植する作業になります。

 

 

今回はCDSを使って暗くなったら点灯して、タイマーで指定した時間デモを行った後、消灯する仕様を追加しました。

CDSの接続はコメントに書いている通りです。入力ポートはPA7を選びました。
 

// 回路構成:3.3V → CdS → 10kΩ → GND 

// ADC入力:CdSと10kΩの分圧点 
// ADC仕様:12bit(0~4095)

// AD値の意味: 

//   大きい → 明るい(CdS低抵抗) 

//   小さい → 暗い(CdS高抵抗)
#define CDS_PIN          PA7     // CdS接続ピン(有効時のみ必要)

このように半田付けした後、熱収縮チューブでまとめます。

 

なお、信号線にはトグルスイッチをつけました。
トグルスイッチを切ると、PA7がオープンで入力レベルが上がって強制ONになります。

生活の知恵ですね。


 

 

回路図と接続は前回書いた通りですね。

NEOPIXEL WS2813は、下記のようにつながっていますから、まず電源としてBLUEPILLの5V(VBUS)、
GNDを接続し、信号線はPA8から330Ωを介してDIに接続します。

 

多重化のBIはGNDに接続する様になっています。(私は間違って、DI同様 330ΩでPA8につなぎました)

 


CDSは秋月で買った500kΩくらいのものを使います。

3.3V電源につなぐと10kΩと直列にしているので、明るい時に3V近く、暗い時に0.2V程度になります。

STM32F103のADCは12bitなので、AD値で明るい時 3000以上、暗い時 250位になるわけです。
この辺は実験して決める必要があります。

 

最終のプログラムはここに置いておきます。
STM32_110Led_XmassTreeV230_add_three_effect5_20251227g.ino

実際のNEOPIXELのファンクション動作は、ラジオペンチさんのブログを参照してくださいね。

いつものように、移植はAIのChatGPTとGROK先生に手伝ってもらいました。

ChatGPTのコードレビューと修正提案

https://chatgpt.com/c/694d0c6e-4528-8320-bb08-acdb5aa8e484

GROKのSTM32F103 BLUE PILLプログラム TickerからHardwareTimerへ変更

https://x.com/i/grok/share/cxtIkN7zs8QsJXVA8aeNKCj1y

 

 

プログラムの最初の部分を説明しますね。

// 
STM32用 NeoPixel 110LEDクリスマスツリー
// ラジオペンチさんのプログラムをChatGPTで改造
// MsTimer2 を Ticker に置き換え、PROGMEM削除
// 2025/12/21 Todopapa 改造版
// 251222_add three effects
// 251223_180分で止まらないバグ修正(TickerからHardwareTimerに変更)→ 300分に変更
// 251223_CDSを使って、暗くなったら起動するように仕様変更 PA7に入力 3.3V → CDS → 10k → GND
// 251224_ PA7に入力にトグルスイッチを入れて、明るくても動作するモードを追加
// 251224_ 110個 → 114個に変更
// 251224_ CDSで起動して240分動作し停止後、明るくなっても再起動しないバグを修正
// 251225_ CDSで起動して240分動作し停止後、暗かったら再起動するバグを修正
// 251227_ GROK先生のアドバイスでプログラムのリファクタリング実施
#include <Arduino.h>
#include <Adafruit_NeoPixel.h>
// #include <Ticker.h>  // tickerはSTM32で安定して動かないので  timerを使う方式に変更

#define LED_PIN        PA8    // LED制御用のシリアル出力ピン
#define LED_COUNT      114 // LEDカウント数
#define STD_BRIGHTNESS 50  // 標準明るさ
#define OFF_TIMER_VAL  300  // 自動OFFタイマー(分単位)180→300(5時間)
//#define OFF_TIMER_VAL  3  // 自動OFFタイマー(分単位)3分でテスト(1ループ終わらないと止まらない)


// ===== CdS(光センサ)設定 =====
// CdSを使いたいときは以下の行のコメントを外す
#define USE_CDS          // CdS機能有効(コメントアウトするとCdS無効=常にデモ実行)

// 回路構成:3.3V → CdS → 10kΩ → GND
// ADC入力:CdSと10kΩの分圧点
// ADC仕様:12bit(0~4095)
//
// AD値の意味:
//   大きい → 明るい(CdS低抵抗)
//   小さい → 暗い(CdS高抵抗)
#define CDS_PIN          PA7     // CdS接続ピン(有効時のみ必要)
#define CDS_DARK_TH    400   // これ以下で「暗い」暗いと判断する閾値(0-4095、実測で調整。例: 明るい時3000、暗い時500)
#define CDS_BRIGHT_TH  800   // 550 → 800に変更 これ以上で「明るい」(ヒステリシス十分)

volatile bool demoRunning = false;  // デモ実行中フラグ

#define RAND_COL7  col[random(7) + 1]   // 7色からランダムに色を選択
#define RAND_COL8  col[random(8)]       // 黒を含む8色からランダムに色を選択
#define RAND_COL7H colH[random(7) + 1]  // 7色からランダムに色を選択
#define RAND_COL8H colH[random(8)]      // 黒を含む8色からランダムに色を選択

Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);
//timer 1秒周期
HardwareTimer timer(TIM2);        // TIM2を使用

Arduno NanoのArduino IDEに、STM32F103はSTM32dunoという基板ライブラリを使います。
そのため、MSTIMER2ライブラリは使えないので、HardwareTimerというライブラリを使います。


詳しい使い方はこちらにありますので、興味のあるかたは見てくださいね。

 

実際のタイマーの設定に関してはこちらになります。 前にPZEM-004Tを使った電力計を作った時と同じですね。

 

 

// -----------------------
// 割り込み1秒ごと
// -----------------------
void timer2IRQ() {                //割り込みハンドラ
  static bool led = false;
  led = !led;
  digitalWrite(PC13, led);        // PC13トグル(常に動作)

  if (demoRunning) {              // デモ実行中だけ時間を進める
    sec++;
    if (sec >= 60) {
      sec = 0;
      mmm++;
    }
  }
  t2Flag = true;                  // フラグを立てる(loopで待つ用)
}

// -----------------------
void setup() {
  Serial.begin(115200);
  pinMode(PC13, OUTPUT); //割り込みモニタ用
  strip.begin();
  strip.show();
  strip.setBrightness(STD_BRIGHTNESS);

  // ===== 1秒タイマーの設定 =====
  timer.pause();                   // 一旦停止
  timer.setPrescaleFactor(7200);   // プリスケーラ:72MHz / 7200 = 10kHz
  timer.setOverflow(10000);        // オーバーフロー:10kHzで10000カウント = 1秒
  timer.refresh();                 // リセット
  timer.attachInterrupt(timer2IRQ);// 割り込み関数設定
  timer.resume();   //タイマー開始!
    -------

void timer2IRQ() の割り込みハンドラは、demorunning中は sec,mmm という時間カウンタを1秒ずつ進める
ことと、モニタのためにPC13の緑LEDを点滅させます。
また、loop()での1秒待ちのために、  t2Flag = true;  というフラグを立てます。

loop()内では demoRunningが有効な間は下記Functionのデモを実施します。(1ループ 5分ほど)

if (demoRunning) { 

 demo1;

   demo2;

   -------

  }
 

デモを抜けると、タイマーUPの検出に続いて1秒待ちでCDSの状態を検知するルーチンに入ります。

 /* ===== OFFタイマー経過で停止処理 =====
     ※ demoRunning の外に置くのが重要 */
  if (mmm >= OFF_TIMER_VAL) {
    if (demoRunning) {
      demoRunning = false;
      todayDone = true;   // 今日の点灯は完了
    }

    strip.clear();
    strip.show();

    // 停止表示(PC13 ゆっくり点滅)
    digitalWrite(PC13, HIGH);
    delay(30);
    digitalWrite(PC13, LOW);
    delay(2000);
  }

#ifdef USE_CDS
  /* ===== CdS 読み取り ===== */
  int cdsValue = analogRead(CDS_PIN);

  /* ===== ヒステリシス付き明暗判定 ===== */
  // 暗くなった判定(AD値が小さくなる)
  if (!isDark && cdsValue < CDS_DARK_TH) {
    isDark = true;
  }
  // 明るくなった判定(AD値が大きくなる)
  else if (isDark && cdsValue > CDS_BRIGHT_TH) {
    isDark = false;
    todayDone = false;   // 翌日の点灯を許可
  }

  /* ===== 暗くなったら起動(1日1回) ===== */
  if (isDark) {
    if (!demoRunning && !todayDone) {
      demoRunning = true;
      mmm = 0;
      sec = 0;
    }
  }
  else {
    // 明るい間は必ず停止
    demoRunning = false;
  }
#endif


  /* ===== 1秒同期(必ず最後) ===== */
  while (!t2Flag) {
    // 割り込み待ち(実質ビジーループ)
  }
  t2Flag = false;

} // loop() 終了
// -----------------------

これでCDSで暗くなったのを検出してデモ動作を開始して、時間が来たら消灯するようになります。
暗い間に再度起動しないように、   todayDone = false; というフラグが明るくならないとクリア
されないように制御します。

これで、毎日 暗くなると一定時間デモを行い、次の日も暗くなると同様にデモを行うことができるようになりました。

(クリスマス終わったんですが(笑))

 

ラジオペンチさんのクリスマスツリーは、アクリル板をカットして10段で n x (n+1)=110個のLEDを制御します。
トドお父さんは、そのような加工技術も根気もないので、そのまま小型のクリスマスツリーに巻きつけました。



これでも、十分きれいに光りますすね。さすが、ラジオペンチさん。

センスと技術力が違いますね。
 

これで、今回のNIOPIXEL114個でのクリスマスツリー作成の話は終わりです。

クリスマスには何とか間に合ってよかったです!


それでは、皆さんおやすみなさい

 

  完成したクリスマスツリーです

 

おもちゃ病院で必要な部品をAliExpressで購入しようと思いました。

Choice という仕組みがあって、1500円以上なら送料無料になるんですよ。

そういえばラジオペンチさんのブログで、NEOPIXELというRGB LEDをテープに多段接続

したテープLEDが安く売っていることを思い出しました。
 

これですね。ラジオペンチさんの記事で使っているのはWS2812Bですが、改良型のWS2813を使ったものを
買いました。電源電圧もつかいやすい5Vの物にしました。
 
WS2813 DC5V, White PCB, 2m 60 IP30  で1190円でした。
テープ色が白、1mに60個 LEDで2m、防水なしという意味ですね。

WS2812BとWS2813の違いですが、WS2813はデータ線が2系統になっているので、途中の1個が壊れても次のLEDから先は点灯する冗長性が特徴の様です。信号線が増えるのでテープの幅は若干太くなるようです。
またリフレッシュレートが500Hzから2kHzに上っていることも特徴のようです。

 

ラジオペンチさんのホームページに載っていた元記事はこれです。

 

 

まずは、120個のLEDストリップから6個のLEDを切り出します。
これをSTM32F103 BLUEPILLでテストしましょう。
 

下記はWS2813のテストプログラムです。

 

/*
  WS2813B LED テストプログラム(ビットバン方式)

  MCU        : STM32F103 (BluePill想定)
  IDE        : Arduino IDE (STM32duino)
  書き込み   : ST-LINK
  LED        : WS2813B × 6個
  出力ピン   : PA8
  ライブラリ : Adafruit NeoPixel

  ※ WS2813B は WS2812B 互換のため、
     NEO_KHZ800 を指定する
*/

#include <Adafruit_NeoPixel.h>

// ===== 設定 =====
#define LED_PIN    PA8     // LEDデータ出力ピン
#define LED_COUNT  6       // 接続しているLEDの数

// NeoPixel オブジェクト生成
// NEO_GRB  : 色データ順
// NEO_KHZ800 : 800kHz(WS2812/WS2813共通)
Adafruit_NeoPixel strip(
  LED_COUNT,
  LED_PIN,
  NEO_GRB + NEO_KHZ800
);

void setup() {
  // NeoPixel 初期化
  strip.begin();

  // 念のため全LED消灯
  strip.clear();
  strip.show();
}

void loop() {
  // 赤 → 緑 → 青 を順番に表示
  colorAll(255, 0, 0);   // 赤
  delay(500);

  colorAll(0, 255, 0);   // 緑
  delay(500);

  colorAll(0, 0, 255);   // 青
  delay(500);
}

/*
  全LEDを同じ色で点灯させる関数
  r, g, b : 0~255
*/
void colorAll(uint8_t r, uint8_t g, uint8_t b) {
  for (int i = 0; i < LED_COUNT; i++) {
    strip.setPixelColor(i, strip.Color(r, g, b));
  }
  strip.show();   // ここで実際にLEDへデータ送信
}


これで、6個のLEDにr=g=b=255のデータを流し込みましたから、6個が白に光ったら接続確認はOKです。

接続は下記のデータシートに示すように、先頭のLEDにUSB 5VとGND、それから信号線のDIに330Ωを介してSTM32F103 BLUEPILLのPA8を接続します。

 データシート接続図


 回路図です(実体配線図)

 

 

このとおりにブレッドボードで組んで、STLINKでスケッチをダウンロードすると

あっけなく動作しました。 USB経由の書き込みは何度かトライしましたが地雷があってうまくいきませんでした。

あっさり光りました!

 

次に光がダイナミックに動いて動作するデモプログラムを作りました。
この時はNEOPIXELの動作を理解してなかったので、GROK先生に相談しました。

https://x.com/i/grok/share/raiTG4ZqQ6bDDPPBPhTkunrzJ


ChatGPT先生にも、プログラムの添削とエフェクトの追加をお願いしました。

https://x.com/i/grok/share/raiTG4ZqQ6bDDPPBPhTkunrzJ

*   - WS2813BのDIとBIは両方接続推奨 は間違いで、

実際は、DIを330Ωを介してPA8に接続し、BIはGNDに落とします。
 

エフェクトを追加した、最終のテストプログラムは下記です。
NeoPixel_xmas_demo2_25dec21c.ino

容量が大きいので、頭の部分だけ貼り付けますね。

/*********************************************
******
 *  NeoPixel クリスマスエフェクト サンプルプログラム (WS2813B 6個用)
 *  
 *  対象ボード   : STM32F103 (Blue Pill) + Arduino IDE
 *  使用ライブラリ: Adafruit NeoPixel (STM32対応版 ANDnXORフォーク)
 *  LED種類      : WS2813B (6個直列接続)
 *  データピン    : PA8 (動作確認済み!)
 *  
 *  主な機能:
 *   - colorWipe     : 順番に単色で塗りつぶし(赤→緑→青)
 *   - theaterChase : シアター風追いかけ点灯
 *   - rainbow      : 全体でゆっくり虹色サイクル
 *   - candyCane    : 赤白キャンディケイン風ストライプ(回転)
 *   - christmasTwinkle : ランダムきらきら点滅(白/金)
 *   - christmasAlternate : 赤緑交互点灯(クラシッククリスマス)
 *  
 *  注意事項:
 *   - WS2813BのDIとBIは両方接続推奨
 *   - データ線に330-470Ω抵抗 + レベルシフタ推奨
 *   - 明るさ50でUSB電源でも安全
 *  
 *  作成日: 2025/12/21
 *  動作確認環境: Blue Pill + WS2813B 6個 (PA8)
 ***************************************************/

#include <Adafruit_NeoPixel.h>

#define NUM_LEDS 6
#define DATA_PIN PA8
#define LED_TYPE NEO_GRB + NEO_KHZ800

Adafruit_NeoPixel pixels(NUM_LEDS, DATA_PIN, LED_TYPE);

void setup() {
  pixels.begin();
  pixels.setBrightness(50);  // 明るさ調整(クリスマスは少し明るめにしてもOK)
  pixels.clear();
  pixels.show();
}

void loop() {
  // 既存のエフェクト
  colorWipe(pixels.Color(255, 0, 0), 200);   // 赤
  colorWipe(pixels.Color(0, 255, 0), 200);   // 緑
  colorWipe(pixels.Color(0, 0, 255), 200);   // 青
  theaterChase(pixels.Color(127, 127, 127), 100);  // 白追跡
  rainbow(10);
}

 

X(旧Twitter)の投稿も参考まで

 

6個のNEOPIXELデモ動作中の画像はこれです。
 

 

それでは、次は前にも紹介したSTM32F103C8T6を搭載したBluePill基板の紹介です。

 

AliExpressで200円前後で買えるので、やすいですね。

自分はおもちゃ修理にSTM32を使うアイデアがあるので、勉強用に3枚買いました。

 

その場合は、開発環境はSTM32CubeIDEかKEILというものを使う必要があるのですが、

今回はArduinoベースなので、Arduino STM32Coreというものを使います。

これだと、STM32でArduinoのライブラリが使えるので、非常にラクですね。

 

ArduinoのボードマネージャでSTM32Coreというものを組み込むのですが、この辺の情報は

巷にあふれていますので、割愛します。ただし、Arduinoは最新のVerを使ってくださいね。

 

もうひとつ、BluePillを使うためには、Amazonで中華製のST-LINK/V2というプログラマを

買うことをお勧めします。 自分の場合は、500円くらいで十分使えました。

 

 

ST-LINKが必要なのは、中華製の廉価BluePillはプログラムが書き込まれてないまっさらの状態のためです。 例えばArduinoに接続する場合、BootLoader(USBのCDC)が書き込まれていれば、BOOT1のJumperを”1”に切り替えてUSB経由で書き込みができますが、まっさらではお手上げです。

 

そこでSTLINKで接続すれば、BootLoaderの書き込みをを行うことができるので、Arduinoから書き込み

ができるようになります。

 

ここでも、細かい話はネットの情報で確認下さい。

ST-LINKで接続すると細かい話はおいといて、プログラムの書き込みができるようになりました。

 

さて、ラジオペンチさんのシリアルテープLEDを使った110LEDクリスマスツリーのプログラムをArduino Nanoから、STM32F103C8T6 BluePillに移植したプログラムですが、こちらにおいています。

 

説明が長くなってきたので、移植したプログラムでNEOPIXELを6個→ 114個に拡張し、クリスマスツリーに巻き付けてNEOPIXELのデモをした話は次回にしますね~。

こうご期待 !


それでは、皆さんおやすみなさい

さあ、いよいよ今回の旅の目的、兵馬俑訪問です。

鐘塔酒店に集合して、朝九時に出発。

いよいよです😊
昨日でなく、平日に正解。
9名の参加です。mu busのテラコッタウォリアー ツアー(兵馬俑ツアー)で現地に向かいます!
兵馬俑ツアーは400元 (約8800円)で兵馬俑までの送り迎えと、ガイドが付きます(英語ですが)
 
混む日曜日から、平日の日曜日にずらしてもらったおかげで、参加者は9人。
ちょうどいい規模でした。
 

ネイティブでないから、なんとか聞き取れました。
ところどころ分からないワードは。得意の80%理解で乗り切る。
日本語ツアーだと、多分2万円くらいになります。
 
1時間ちょっとで、兵馬俑に到着しました。
シーズンオフなので、入場料は無料のようです。

さすがに、すごいです。
第一抗だけで、6000体。
将軍は六体見つかっているそうです。
胸に、□があるのが。司令官。
第三抗、第二抗を見学して、秦の始皇帝博物館へ向かいます。
2時間半ほどのツアーになります。
 
 
 
 
 
 
 
 
 
 
 
 
連れていかれたおみやげ物屋さんです。
万国共通、ツアーの最後はおもやげ屋さんに連れていかれるのですね。
 
 
お土産屋さんの後に、ようやく昼食です。
軽い昼食が付くとのことでしたが以外と豪華、私はアルコールが入らないと話せないので、青島ビールを頼みました(笑)。

参加者は、シンガポールから親子連れ2組、スイス🇨🇭から、高校卒業旅行の2人組、それとオーストラリアから一人と、国際交流になりました。
 
写真の左はシンガポールの親子、右はスイスからの若い2人組です。
高校卒業後にGap Year(1年休学)という制度を使って、旅行をしているそうです。
 

 
食事が終わってバスまでの帰り道のお土産店で、いまJKに人気のなラブブもあも買いました。
10元だから、きっと偽物でしようが、思い出になりますよね 😙


 
ツアーが終わり、ベルタワーホテルのある鐘塔の前で解散です。
 
今日は、気合いが入っていたので
少々疲れました。早めにホテルに帰って休みます。
それでは