STM32 BluePillで作る10ch DMX位相制御調光器【完全解説】
はじめに
STM32F103C8(BluePill)を使用した10チャンネル DMX512 位相制御調光器の設計・実装について解説します。舞台照明、TV/放送スタジオ、建築照明など幅広い用途に対応できる本格的な調光器です。
本記事で扱う内容
- ハードウェア構成とピンアサイン
- 4種類の調光カーブ(リニア/S字/TVガンマ/Bカーブ)
- Bカーブ(実効値リニア補正)の数学的導出
- 2相AC電源対応(4+6チャンネル分離)
- 10ビットスムージング処理
- 温度保護機能
主な特徴
┌─────────────────────────────────────────────────────────────────┐
│ システム構成図 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ DMX512入力 STM32F103C8 トライアック AC負荷 │
│ ┌─────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │XLR5 │──────→│ BluePill │─────→│ SSR/ │───→│ ハロゲン │ │
│ │ │ │ │ │ トライアック│ │ LED │ │
│ └─────┘ │ 10ch │ │ 10ch │ │ 白熱灯 │ │
│ │ PWM出力 │ │ │ └──────────┘ │
│ AC同期 │ │ └──────────┘ │
│ ┌─────┐ │ │ │
│ │ゼロ │──────→│ │ │
│ │クロス│ └──────────┘ │
│ └─────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
1. ハードウェア構成
1.1 BluePill ピンアサイン
┌─────────────────┐
│ STM32F103C8 │
│ BluePill │
┌───────┤ ├───────┐
3.3V ─┤ 3V3 │ │ GND ├─ GND
RESET ─┤ RST │ │ GND ├─ GND
5V ──┤ 5V │ │ 3.3V ├─ 3.3V
AC同期1 ──┤ PA0 │ │ PB9 ├── SW1(DIP bit0)
AC同期2 ──┤ PA1 │ │ PB8 ├── CH8 PWM
温度入力 ─┤ PA2 │ │ PB7 ├── CH10 PWM
DMX RX ───┤ PA3 │ │ PB6 ├── CH9 PWM
SW3 ──────┤ PA4 │ │ PB5 ├── SW6
SW4 ──────┤ PA5 │ │ PB4 ├── SW5
CH1 PWM ──┤ PA6 │ │ PB3 ├── (SWO)
CH2 PWM ──┤ PA7 │ │ PA15 ├── SW2
CH5 PWM ──┤ PA8 │ │ PA14 ├── (SWCLK)
CH6 PWM ──┤ PA9 │ │ PA13 ├── (SWDIO)
CH7 PWM ──┤ PA10 │ │ PA12 ├── (USB D+)
│ │ │ PA11 ├── (USB D-)
CH3 PWM ──┤ PB0 │ ┌───┐ │ PB15 ├── SW10
CH4 PWM ──┤ PB1 │ │USB│ │ PB14 ├── SW9
SW7 ──────┤ PB12 │ └───┘ │ PB13 ├── SW8
│ │ [LED] │ PB11 ├── I2C SDA
│ │ PC13 │ PB10 ├── I2C SCL
└───────┤ LED TMP R_LED├───────┘
└─────────────────┘
1.2 PWM出力ピン配置
| チャンネル | ピン | タイマー | 系列 |
|---|---|---|---|
| CH1 | PA6 | TIM3_CH1 | 系列1 |
| CH2 | PA7 | TIM3_CH2 | 系列1 |
| CH3 | PB0 | TIM3_CH3 | 系列1 |
| CH4 | PB1 | TIM3_CH4 | 系列1 |
| CH5 | PA8 | TIM1_CH1 | 系列2 |
| CH6 | PA9 | TIM1_CH2 | 系列2 |
| CH7 | PA10 | TIM1_CH3 | 系列2 |
| CH8 | PB8 | TIM4_CH3 | 系列2 |
| CH9 | PB6 | TIM4_CH1 | 系列2 |
| CH10 | PB7 | TIM4_CH2 | 系列2 |
1.3 入力ピン
| 機能 | ピン | 説明 |
|---|---|---|
| AC同期1 | PA0 | ゼロクロス検出(系列1)EXTI0 |
| AC同期2 | PA1 | ゼロクロス検出(系列2)EXTI1 |
| DMX RX | PA3 | USART2 RX(DMX512入力) |
| 温度入力 | PA2 | サーモスタット接点(プルアップ) |
2. 調光カーブ
2.1 5種類のカーブ
| 値 | カーブ名 | 数式 | DMX128→PWM | 推奨用途 |
|---|---|---|---|---|
| 0 | Linear | RMS補正 | 378 | テスター基準、測定用 |
| 1 | Upper | Linear +オフセット | 406 | 低域明るめ、舞台 |
| 2 | Lower | Linear -オフセット | 360 | 低域暗め、微光重視 |
| 3 | S字カーブ | $3x^2 - 2x^3$ | 514 | ハロゲン、滑らかな変化 |
| 4 | TVガンマ | $x^{2.2}$ (γ2.2) | 224 | 放送、カメラ撮影 |
Linearベースの3カーブ体制(2026/1/13):
- 0:Linear - テスターで直線(RMS実効値がDMXに正比例)
- 1:Upper - 低域でLinearより明るい(DMX26で+68)
- 2:Lower - 低域でLinearより暗い(DMX26で-43)
2.2 カーブ比較グラフ
グラフの見方:
- Full Range: 全域(DMX 0-255)の出力特性、5カーブすべて表示
- Low Range (0-50): 低レベル域の立ち上がり比較(リニアも理想直線との差が見える)
- Mid Range (100-180): 中間域の変化、DMX 128付近に注目
- High Range (200-255): 高レベル域の飽和特性
注意: リニアカーブも DMX 255 で PWM=1023 にクリップしているため、DMX 254付近でわずかに非直線となります。
2.3 カーブ特性詳細
PWM出力
1023 ┤ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ 0:Linear
│ ▓▓▓▓▓▓▓▓█████████████████ 1:BCurve
800 ┤ ▓▓▓▓▓▓▓▓████████
│ ▓▓▓▓▓▓▓▓████████ ........ 2:BCurve×0.75
600 ┤ ▓▓▓▓▓▓▓▓████████........
│ ▓▓▓▓▓▓▓▓████████........ ------- 3:S-Curve
400 ┤▓▓▓▓████████........-------
│████........------- _______ 4:TV Gamma(暗)
200 ┤....-------_____
│---____
0 ┼──────────────────────────────────────────────────────────────→ DMX
0 32 64 96 128 160 192 224 255
各カーブの特徴:
- 0:Linear(▓): RMS補正済み。テスターで直線表示
- 1:Upper(█): 低域明るめ。Linearより+オフセット
- 2:Lower(.): 低域暗め。Linearより-オフセット
- 3:S-Curve(-): 中間域が滑らか。ハロゲン向け
- 4:TV Gamma(_): 低レベル最暗。TV/放送カメラ用
2.4 カーブ選択フローチャート
開始
│
▼
┌────────────────┐
│ 負荷・用途は? │
└───────┬────────┘
│
┌────────┬────────┼────────┬────────┐
▼ ▼ ▼ ▼ ▼
┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐
│ LED │ │ 舞台 │ │ 汎用 │ │ハロゲン│ │TV/放送│
└──┬──┘ └──┬──┘ └──┬──┘ └──┬──┘ └──┬──┘
│ │ │ │ │
▼ ▼ ▼ ▼ ▼
┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐
│Linear│ │Upper │ │Lower │ │S-Curve│ │TV │
│ (0) │ │ (1) │ │ (2) │ │ (3) │ │Gamma │
│基準 │ │明るめ│ │暗め │ │滑らか│ │ (4) │
└──────┘ └──────┘ └──────┘ └──────┘ └──────┘
2.5 各カーブの数学的背景
Linear(RMS補正)
位相制御の非線形性を補正し、テスターで直線になるカーブ:
$$V_{rms} = V_{max} \sqrt{\frac{\pi - \theta + \frac{\sin(2\theta)}{2}}{\pi}}$$
目標実効値から位相角θを逆算し、PWM値に変換。
Upper/Lower(オフセット)
Linearを基準に±オフセットを加算:
- Upper: $PWM = Linear + offset \times (1-x)^{1.5}$
- Lower: $PWM = Linear - offset \times (1-x)^{1.5}$
低域でオフセット最大、高域で収束。
S字カーブ(3次補間)
Hermite補間による滑らかなS字特性:
$$PWM = 1023 \times (3x^2 - 2x^3), \quad x = \frac{DMX}{255}$$
TVガンマ(γ2.2)
放送規格のガンマ補正:
$$PWM = 1023 \times \left(\frac{DMX}{255}\right)^{2.2}$$
3. Linearカーブ(RMS実効値補正)の数学的導出
3.1 課題:位相制御の非線形性
位相制御では、正弦波の一部をカットして出力を制御します。しかし、位相角と実効値の関係は非線形です。
電圧
↑
Vmax ┤ ╭──╮ ╭──╮
│ ╱ ╲ ╱ ╲
│ ╱ ╲ ╱ ╲
0 ├─╱────────╲──╱────────╲──→ 時間
│ ████ ╲╱
│ ↑カット部分
単純にPWM値を線形にすると:
- 低レベル域: 実効値が急激に変化(敏感すぎる)
- 高レベル域: 実効値がほとんど変化しない(鈍い)
3.2 位相制御の実効値公式
位相角 $\theta$ (0〜π)で点弧する場合の実効値比:
$$V_{rms} = V_{max} \sqrt{\frac{\pi - \theta + \frac{\sin(2\theta)}{2}}{\pi}}$$
3.3 逆算アルゴリズム
目標実効値比 $R_{target} = \frac{DMX}{255}$ に対して、必要な位相角 $\theta$ を二分探索で求め、PWM値に変換:
$$PWM = 1023 \times \frac{\pi - \theta}{\pi}$$
3.4 Python実装
import math
def calc_rms_ratio(theta):
"""位相角θでの実効値比を計算"""
if theta >= math.pi:
return 0
if theta <= 0:
return 1
return math.sqrt((math.pi - theta + math.sin(2*theta)/2) / math.pi)
def find_theta_for_rms(target_rms):
"""目標実効値比に対する位相角を二分探索で求める"""
if target_rms >= 1:
return 0
if target_rms <= 0:
return math.pi
low, high = 0, math.pi
for _ in range(50):
mid = (low + high) / 2
rms = calc_rms_ratio(mid)
if rms > target_rms:
low = mid
else:
high = mid
return (low + high) / 2
# Linearカーブテーブル生成
print("const uint16_t Dim_Linear[] = {")
for dmx in range(256):
target_rms = dmx / 255.0
theta = find_theta_for_rms(target_rms)
pwm = int(round(1023 * (math.pi - theta) / math.pi))
print(f"{pwm:4d},", end="" if (dmx+1) % 16 else "\n")
print("};")
3.5 目標テーブル(テスターリニア)
DMX値に対してAC実効値が正比例(直線)になる理想PWM値:
| DMX値 | PWM値 | 理論AC実効値 | 備考 |
|---|---|---|---|
| 0 | 0 | 0V | OFF |
| 26 | 120 | 10V | 10% |
| 51 | 191 | 20V | 20% |
| 76 | 254 | 30V | 30% |
| 102 | 316 | 40V | 40% |
| 128 | 377 | 50V | 50% |
| 153 | 439 | 60V | 60% |
| 178 | 505 | 70V | 70% |
| 204 | 584 | 80V | 80% |
| 230 | 688 | 90V | 90% |
| 255 | 1023 | 100V | FULL |
この表が0:Linearカーブの目標です。
3.6 実装値テーブル
| DMX値 | PWM値 | 理論AC実効値 | 備考 |
|---|---|---|---|
| 0 | 0 | 0V | OFF |
| 26 | 121 | 10V | 10% |
| 51 | 192 | 20V | 20% |
| 76 | 254 | 30V | 30% |
| 102 | 316 | 40V | 40% |
| 128 | 378 | 50V | 50% |
| 153 | 439 | 60V | 60% |
| 178 | 505 | 70V | 70% |
| 204 | 585 | 80V | 80% |
| 230 | 688 | 90V | 90% |
| 255 | 1023 | 100V | FULL |
3.7 単純PWM vs Linearカーブ 比較
実効値(V)
100 ┤ ████████████████ Linearカーブ
│ ████████ (直線)
80 ┤ ████████
│ ████████
60 ┤ ████████........................ 単純PWM
│ ████████ ....... (非線形)
40 ┤██████ .......
│ .......
20 ┤....
│.
0 ┼──────────────────────────────────────────────────────────────→ DMX
0 32 64 96 128 160 192 224 255
4. 2相AC電源対応(4+6構成)
4.1 なぜ2相対応が必要か
3相電源(R-S-T)を使用する場合、各相の位相が120°ずれています。単一のゼロクロスで全チャンネルを同期すると、他の相では位相がずれて正しく制御できません。
4.2 タイマー構成と制約
STM32のタイマーは「タイマー単位」でしかリセットできないため、チャンネル分割に制約があります。
┌─────────────────────────────────────────────────────────────────┐
│ タイマー別チャンネル配置 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ TIM3 (4ch) TIM1 (3ch) TIM4 (3ch) │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ CH1: PA6 │──CH1 │ CH1: PA8 │──CH5 │ CH1: PB6 │──CH9│
│ │ CH2: PA7 │──CH2 │ CH2: PA9 │──CH6 │ CH2: PB7 │──CH10│
│ │ CH3: PB0 │──CH3 │ CH3: PA10│──CH7 │ CH3: PB8 │──CH8│
│ │ CH4: PB1 │──CH4 │ CH4: 未使用│ │ CH4: 未使用│ │
│ └──────────┘ └──────────┘ └──────────┘ │
│ ↓ ↓ ↓ │
│ 系列1 系列2 系列2 │
│ (4ch) (3ch) (3ch) │
└─────────────────────────────────────────────────────────────────┘
4.3 分割パターン比較
| 分割案 | 可否 | 理由 |
|---|---|---|
| 5+5 | ⚠️ | TIM1がまたがる(CH5=系列1, CH6-7=系列2)。CH5が不安定 |
| 4+6 | ✅ | TIM3=系列1、TIM1+TIM4=系列2。タイマー境界で分離可能 |
| 6+4 | ❌ | TIM1を分割できない |
| 3+7 | ❌ | TIM3を分割する必要があり不可 |
4.4 4+6構成の実装
┌────────────────────────────────────────────────┐
│ 4+6 構成(現行実装) │
├────────────────────────────────────────────────┤
│ 系列1: TIM3 (4ch) = CH1-4 ✅ │
│ 系列2: TIM1 (3ch) + TIM4 (3ch) = CH5-10 ✅ │
├────────────────────────────────────────────────┤
│ EXTI0 (PA0) → TIM3リセット │
│ EXTI1 (PA1) → TIM1+TIM4リセット │
│ タイマー境界で完全分離 │
└────────────────────────────────────────────────┘
4.5 割り込みハンドラ
// EXTI0: 系列1 AC同期(4ch: TIM3のみ)
void EXTI0_IRQHandler(void) {
EXTI_ClearITPendingBit(EXTI_Line0);
if(cou0 > 50) {
cou0 = 0;
// 系列1: TIM3 (CH1-4)
TIM_SetCompare1(TIM3, TmD[1]);
TIM_SetCompare2(TIM3, TmD[2]);
TIM_SetCompare3(TIM3, TmD[3]);
TIM_SetCompare4(TIM3, TmD[4]);
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
#if (DUAL_AC_SYNC == 0)
// 単相モード:系列2も同時にリセット
TIM_SetCompare1(TIM1, TmD[5]);
TIM_SetCompare2(TIM1, TmD[6]);
TIM_SetCompare3(TIM1, TmD[7]);
TIM_SetCompare3(TIM4, TmD[8]);
TIM_SetCompare1(TIM4, TmD[9]);
TIM_SetCompare2(TIM4, TmD[10]);
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);
#endif
}
}
// EXTI1: 系列2 AC同期(6ch: TIM1+TIM4)
void EXTI1_IRQHandler(void) {
EXTI_ClearITPendingBit(EXTI_Line1);
#if (DUAL_AC_SYNC == 1)
if(cou1 > 50) {
cou1 = 0;
// 系列2: TIM1 (CH5-7) + TIM4 (CH8-10)
TIM_SetCompare1(TIM1, TmD[5]);
TIM_SetCompare2(TIM1, TmD[6]);
TIM_SetCompare3(TIM1, TmD[7]);
TIM_SetCompare3(TIM4, TmD[8]);
TIM_SetCompare1(TIM4, TmD[9]);
TIM_SetCompare2(TIM4, TmD[10]);
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);
}
#endif
}
5. 10ビットスムージング処理
5.1 なぜ10ビット分解能か
DMX512は8ビット(256段階)ですが、内部処理を10ビット(1024段階)に拡張しています。
┌─────────────────────────────────────────────────────────────────┐
│ 8bit vs 10bit 比較 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 【8ビット処理の問題】 │
│ - 分解能: 256段階 │
│ - 最小変化: 0.39% │
│ - フェードがカクカク │
│ - 低輝度で段差が目立つ │
│ │
│ 【10ビット処理のメリット】 │
│ - 分解能: 1024段階(4倍) │
│ - 最小変化: 0.098% │
│ - フェードが滑らか │
│ - 低輝度でも自然な表現 │
│ │
└─────────────────────────────────────────────────────────────────┘
5.2 データフロー
┌─────────────────────────────────────────────────────────────────┐
│ 完全なデータフロー │
├─────────────────────────────────────────────────────────────────┤
│ │
│ DMX受信 温度制限 カーブ変換 目標値設定 │
│ Rx2D[] → Tdata制限 → DimCurve[] → RmD[i] │
│ (8bit) (8bit) (8→10bit) (10bit) │
│ │
│ 目標値 フェード処理 PWM出力 │
│ RmD[i] → inc_dec() → TmD[i] → TIMx_CHx │
│ (10bit) TmD++/-- (10bit) (10bit) │
│ 【スムージング】 │
│ │
└─────────────────────────────────────────────────────────────────┘
5.3 inc_dec() スムージング関数
void inc_dec(void) {
int i;
for(i = 1; i <= 10; i++) {
if(TmD[i] > RmD[i]) {
TmD[i]--; // 目標より大きい → 1減らす
} else if(TmD[i] < RmD[i]) {
TmD[i]++; // 目標より小さい → 1増やす
}
}
Set_TIM_d();
}
動作原理:1次ローパスフィルタ(積分器)として機能し、急激な変化を滑らかな変化に変換します。
6. 温度保護機能
6.1 システム構成
┌─────────────────────────────────────────────────────────────────┐
│ 温度保護システム │
├─────────────────────────────────────────────────────────────────┤
│ │
│ サーモスタット STM32F103C8 │
│ ┌─────────────┐ ┌──────────────────────────────┐ │
│ │ (常開接点) │ │ PA2 ← 温度接点入力 │ │
│ │ 高温でCLOSE │─────────→│ ↓ │ │
│ └─────────────┘ │ 温度判定 → 出力制限 │ │
│ │ ↓ │ │
│ 状態LED │ PC14 → LED点滅表示 │ │
│ ┌─────────────┐ │ │ │
│ │ 高温時点滅 │←────────│ PWM出力 CH1-CH10 制限 │ │
│ └─────────────┘ └──────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
6.2 config.h 設定
#define T_DEC 200 // 減光速度(数値小=速い)
#define T_INC 0 // 増光速度(0=電源再投入まで復帰しない)
#define T_MIN 127 // 最小輝度(0-255, 127=50%)
6.3 LED点滅パターン
| 状態 | LED動作 | 意味 |
|---|---|---|
| 常温 | 消灯 | 正常動作 |
| 高温検出 | 高速点滅 | 減光中 |
| 減光完了 | 低速点滅 | 出力制限中 |
7. 設定リファレンス(config.h)
7.1 基本設定
// AC周波数
#define AC_HZ_DEFAULT 50 // 50Hz(東日本) or 60Hz(西日本)
// フェードスピード
#define Fspeed 5 // 0=即時, 1=最速, 5=標準, 50=超スロー
// 2相モード
#define DUAL_AC_SYNC 1 // 0=単相, 1=2相(4+6)
// 調光カーブ(Linearベース)
#define CURVE_DEFAULT_1 0 // 系列1: Linear(テスター基準)
#define CURVE_DEFAULT_2 0 // 系列2: Linear
// カーブ番号: 0=Linear, 1=Upper, 2=Lower, 3=S-Curve, 4=TV Gamma
// PWM校正
#define PWM_OFFSET 0 // オフセット(最小出力調整)
#define PWM_GAIN 250 // ゲイン(255=1.0倍、250=約0.98倍)
// DMXオフセット
#define CH2_OFFSET 4 // 系列2 = 系列1アドレス + 4
7.2 パッチ設定
// チャンネルパッチ(DMXアドレス割り当て)
const uint16_t Ch[] = {1,2,3,4,5,6,7,8,9,10}; // ストレート
// 出力モード(0=調光, 1-254=スイッチ閾値)
const uint8_t Sw[] = {0,0,0,0,0,0,0,0,0,0}; // 全調光
8. まとめ
構成まとめ
| 項目 | 仕様 |
|---|---|
| MCU | STM32F103C8 (BluePill) |
| チャンネル数 | 10ch(4+6構成で2相対応) |
| 入力 | DMX512 (USART2) |
| 内部分解能 | 10ビット (1024段階) |
| カーブ | 5種類(リニア/BCurve/BCurve×0.75/S-Curve/TV Gamma) |
| AC同期 | 2系列独立(EXTI0/EXTI1) |
| 保護機能 | 温度センサー接点入力 |
用途別推奨設定
| 用途 | カーブ | DUAL_AC_SYNC |
|---|---|---|
| テスター測定・基準 | Linear(0) | 0 |
| 舞台照明(低域明るめ) | Upper(1) | 0 |
| 舞台照明(低域暗め) | Lower(2) | 0 |
| 舞台照明(ハロゲン) | S-Curve(3) | 0 |
| TV/放送スタジオ | TV Gamma(4) | 0 |
| 3相電源(2相使用) | 任意 | 1 |
参考リンク
作成日: 2026年1月12日
更新日: 2026年1月13日(5種カーブ対応、グラフ追加)
プロジェクト: 103AC10 DMX位相制御調光器
ライセンス: MIT
タグ
STM32 BluePill DMX512 調光器 位相制御 電子工作 舞台照明
