Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

This article is a Private article. Only a writer and users who know the URL can access it.
Please change open range to public in publish setting if you want to share this article with other users.

# 位相制御調光制御設計

0
Last updated at Posted at 2026-01-12

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 カーブ比較グラフ

curves_near_linear.png

グラフの見方

  • 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 調光器 位相制御 電子工作 舞台照明

0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?