2014年11月10日月曜日

Arduinoでエアコン制御 5-2 (送信編―タイマ割込み 成功?)

Arduinoでエアコン制御 5-1の続き。一応成功?
キャリア周波数について理解をしていなかった。
一旦失敗かと思われた555の出力で割込みを発生させるパターンもスケッチを書き直せばあるいは…?

ChaNさんのページでも他サイトでも38[kHz]云々とあるキャリア周波数に乗せなければエアコンは応えてくれない。
実際、エアコンのリモコンのLED A-K間電圧をキットオシロで計ってみると、160[us]間に約6周期…37.5[kHz]あたりになっている…。

スケッチ

       //---一般Const---
const byte pin_irout = 5;
const byte pin_led = 13;  //送信確認用LED

       //---通信データ---
const byte snd_dt_idct[3] = {8, 4, 31};  //bit個数 reader(1),reader(0),repeat(0)
const byte snd_dt_cstm[5] = {B00100011, B11001011, B00100110, B00000001, B00000000};

const byte snd_dt_C[12] = {B00100000, B00011000, B00000101, B00110110,
                         B01000000, B00000000, B00000000, B00000000,
                         B00000000, B00000000, B00000000, B00000000};

volatile byte itpt_tmr = 0;
volatile byte snd_sw = 0;  //送信トグル
volatile byte crr_sw = 0;

void setup() {
  pinMode(pin_irout, OUTPUT);
  pinMode(pin_led, OUTPUT);
}
//----------[2].

void loop() {
  digitalWrite(pin_led, HIGH);
  Ir_snd(snd_dt_C, sizeof(snd_dt_C));
  digitalWrite(pin_led, LOW);
  delay(3000);
}

//----------[3].各機能
      //---データ送信---
void Ir_snd(const byte dt[], byte s) {
  Reg_set();

  for (byte i = 0; i < 2; i++){  //2回繰り返す
    itpt_tmr = 0;
    Ir_ns(snd_dt_idct[0], 1);                 //--Reader code
    Ir_ns(snd_dt_idct[1], 0);
    Ir_cs(snd_dt_cstm, sizeof(snd_dt_cstm));  //--Customer code
    Ir_cs(dt, s);                             //--Data code
    const byte chksm[1] = {Mk_chksm(snd_dt_cstm, sizeof(snd_dt_cstm), dt, s)};
    Ir_cs(chksm, 1);                          //--Check sum
    Ir_ns(1,1);                               //--Stop bit
    Ir_ns(snd_dt_idct[2], 0);                 //--Repeat code
  }
  Reg_clr();
}
      //---回数送信---
void Ir_ns(const byte n, byte c) {  //回数 n, 1/0 c
  byte i = 0;
  while (i < n) {
    if (itpt_tmr == 33) {
      snd_sw = c;
      i += 1;
      itpt_tmr = 0;
    }
  }
  i = 0;
}
      //---変換送信---
void Ir_cs(const byte dt[], byte s) {
  byte lsb;
  byte i = 0;
  byte j = 0;

  while (i < s * 8) {  //ビットが1なら(1)(0)(0)(0)、0なら(1)(0)
    lsb = dt[i / 8] >> (i % 8) & 1;
    if (itpt_tmr == 33) {
      snd_sw = 1;
      i++;
      itpt_tmr = 0;
      while (j < (2 * lsb) + 1) {
        if (itpt_tmr == 33) {
          snd_sw = 0;
          j++;
          itpt_tmr = 0;
        }
      }
    }
    j = 0;
  }  //--while
}
       //---チェックサム生成---
byte Mk_chksm(const byte dt_c[], byte s_c, const byte dt[], byte s) {
  volatile byte chksm = 0;  //挙動がおかしいよくわからない

  for (int i; i < s_c; i++) { chksm += dt_c[i]; }
  for (int i; i < s; i++) { chksm += dt[i]; }
  return chksm;
}
       //---レジスタ設定---
void Reg_set() {
  TCCR2A = B00000010;  //CTCモード
  TCCR2B = B00000001;  //CTCモード,分周なし
  OCR2A = 211;  //TOP値(比較A) 37.9kHz
  TIMSK2 = B00000010;  //割込許可(比較A)
}
       //---レジスタ設定を戻す--- 回りくどいがとりあえず毎回デフォルト値に戻す事にする
void Reg_clr() {
  TCCR2A = B00000001;  //位相標準PWM(TOP値固定)
  TCCR2B = B00000100;  //64分周
  OCR2A = 0;  //TOP値
  TIMSK2 = 0;  //割込不許可
}

//----------[4].割込み

       //---タイマ2---
ISR(TIMER2_COMPA_vect) {
  crr_sw = (1 - crr_sw) * snd_sw;
  bitWrite(PORTD, pin_irout, crr_sw);
  itpt_tmr ++;
}

16[MHz]動作のATmega328Pで分周無し、TOP値を211としてCTCモードで割込みを発生させている。
つまり13.18[us]毎に割込みが発生する。((1/0.01318)/2=37.9[kHz])
その割込みで"crr_sw"を0と1でトグルさせてキャリア波とし、33回毎(0.43[ms]毎)に
"snd_sw"に0か1をセットする事でDigital 5pin(PD5)のHigh、Lowを決めている。

結果・考察

とりあえずエアコンは反応したものの、10回に1回程度(?)無反応な時がある。
"HandyOscillo"で見ながらだと毎回ではないが割と大きくぶれているのがわかる。
(ただし、明らかにそのRepeat codeは長すぎるだろうという信号であってもエアコンは反応していた)
そのぶれからもわかるように、おそらくは割込み間の時間が一気に短くなった事でメインのループが追いつかない事があるのではなかろうか。
また上での計算が違い、エアコンの受信機能がぎりぎり許容できるあたりのずれを含んで送信を行っているかもしれない。

受信――は短いコードで済んだが、その変換、評価、そして上の送信とくる為、コードが割と長くなるだろう事が予想される。
いずれにせよまずは上のスケッチを見直すところからだろう。
実際のエアコンのリモコン内でも村田製作所の4[MHz]のセラロックが入っているが、マイコンの動作電圧や消費電力の面から電池2本で動かそうと思うとより遅いシステムクロックでも動作するようにしなければならないだろうと思われる。

ATmega328だけの話なら、別のタイマもCTCに設定して38[kHz]のキャリア波を作れば正しいタイミングが作れるだろうが…最終的にATtiny85で完成させたい為その選択はできない。

もう少し製作を進めてから判断する話になろうが、外に水晶発振器を用意するのも手かもしれない。38[kHz]のキャリア波だけでも外で作ればソフトウェアにシビアにならずに済むのではなかろうか。

リモコンの分解

リモコンの中身はルネサスの赤外線リモコン専用マイコンらしい。
データシートもAVRで見たような内容でおもしろい。
メインクロックにセラミック、サブクロックに水晶を接続できるようだ。
データシートでは32.76[kHz]を接続するよう書いているが、キットオシロでみる限り38[kHz]により近いものにしていると思われる。

アプリケーションノートを見てみると「タイマ2でPWM信号を生成~タイマ1で出力を制御…」とある。
上で選択から除外したそれを行っている可能性が高い。
LCDの制御がある事から多ピンで高性能なマイコン(比tiny)を使っている結果なのだろう。
オリジナルのコピーが目的なわけではないが、模倣というのはある意味正解に遠くはない結果になりはしないだろうか――つまり38[kHz]の水晶発振子を使う旨。
とりあえずこのへんで一旦保留とする。

0 件のコメント :

コメントを投稿