読者です 読者をやめる 読者になる 読者になる

poipoiです。

技術的ななにかと、そうじゃないなにか。

無線制御調光器のこと 調光回路のソフトウェアのおはなし

こちらの続き。

poipoides.hatenablog.com

今回は、調光制御のソフトウェア部分のはなし。

前段

前回もちらっと解説していますが、制御の流れをざっくり説明すると

  1. AC電源のゼロクロスポイントでArduino pro mini の2pin(INT pin)にトリガが入る
  2. ↑の外部割込みで各フォトトライアックをOFFする。(4~7 pin を Lowに)
  3. 外部割込み後、一定時間経過後にフォトトライアックをONにする。

という流れになっています。

フォトトライアックをONにするタイミングを制御するためのデータは、親機から送られる調光制御データを無線経由でTWE-Lite子機で受け取って、そこからUART経由でArduinoで受けて、最終的にArduino内でタイミング設定のデータに変換して使用する感じになってます。

ここら辺詳しくは次回(以降?)の通信編で解説しようかと。

コード

今回、Arduinoのコードについてはこんな感じで組みました。

github.com

マジックナンバーばっかりだが急いでたんだ。見なかったことにしてくれ。。。

詳細はそれぞれ以下のように。

外部割り込み部

外部割込み部でやってるのは

  1. 前述のとおりINT2 pin の立ち下がりで割込みを受ける
  2. 割込みハンドラ内で、各種設定の初期化、各出力ピンをLOWに(トライアックOFF)。

をしている感じです。

コードにするとこんなかんじ。

void intZeroCross(void)
{
  for (int i = 0; i < PARAM_SIZE; i++) {
    param[i].nowTim = 0;
    param[i].isRun = true;
    digitalWrite(param[i].ctrlPin, LOW);
  }
}

タイマ割り込み部

タイマはus刻みで設定できるTimerOneライブラリを使用。

500usに1回割込みさせるTickとして使っています。

で、処理の概要は以下

  1. もし、各出力ポートに紐づいたカウンタがランニング中だった場合、時間カウント用変数を加算
  2. さらに加算後に設定値を超えた場合、出力をHIGHに(トライアックON)、ランニングフラグをfalse
  3. 最後にタイマを再スタートさせる

コードにするとこんなかんじ

void tick500us(void)
{
  digitalWrite(DEBUG_PIN_0, HIGH);

  for (int i = 0; i < PARAM_SIZE; i++) {
    if (param[i].isRun) {
      param[i].nowTim++;
      if (param[i].nowTim >= param[i].waitTim) {
        param[i].isRun = false;
        digitalWrite(param[i].ctrlPin, HIGH);
      }
    }
  }
  Timer1.restart();
  
  digitalWrite(DEBUG_PIN_0, LOW);
}

(デバッグ出力は気にしないでね!)

基本的に500usごとにカウントしているので、1 / 50Hz / 2(半波分) / 500us = 20 で最大20段階の光量調整になります。

親機からの調光制御のデータは0~255でくるので実はだいぶ丸めちゃっているのですが、まああんまり細かくても人間の目にはわからないんじゃないですかね。っていうアバウトな感じでやっています。

(ここらへん調光の仕組みをロジック回路でまるっと作ればもっと精度よくなると思うんだけど、今回はマイコンでの簡易制御だからまあこんなもんかなという感じです。機会あったらやるかも?)

ただし、実はこれだけではちゃんと動かないのです。。。

理由は以下。

TimerOneライブラリのフラグクリア部について

じつは上述のコードでうまく動かなくてずっと悩んでたんですが、TimerOneライブラリの中身を見て理由が判明。

void TimerOne::start()  // AR addition, renamed by Lex to reflect it's actual role
{

(中略)
 
//  TIFR1 = 0xff;                      // AR - Clear interrupt flags
//  TIMSK1 = _BV(TOIE1);              // sets the timer overflow interrupt enable bit
}

割り込みフラグのクリア処理がコメントアウトされてますけど!?

ちょっと理由は定かじゃないのですが、タイマをスタートさせる関数で割り込みフラグをクリアしてないんですよね。 というか、そのためのコードが意図的にコメントアウトされているのです。 そりゃ2回目以降のタイマ割り込みが入らないわけですよ。。。

(時間なくあんまり真面目にライブラリ全体を見てないのでもしかしたら何らかの理由があるのかもしれませんが。。。)

なので今回はそこのコメントアウトを外したライブラリを作って使用しています。

以下で一応公開。

github.com

皆様もTimerOneライブラリを使用するときはお気をつけください。。。

締め

ということで今回はここまで。 次回は通信編?

追記

続き書きました!

poipoides.hatenablog.com