So-net無料ブログ作成
検索選択

Clock_Start() メソッドでクロックが起動しない [PSoC]このエントリーを含むはてなブックマーク#

ボタンでブザーを操作する回路

PSoC 4200 を使って、ブザーをボタンにより操作しようとしているのだけど、うまく動かないと相談を受けました。 さて、何が原因でしょうね。

ソフトウェアでで Clock を制御する

使われた回路は、上にある通りです。 ソフトウェアで入力端子の状態を読み出し、それにしたがって、 Clock コンポーネントを動かしたり止めたりするというコンセプトです。 ソフトウェアでの判断は、以下のようになっています。

#include <project.h>

uint8   SW2_state;

int main() {
    CyGlobalIntEnable; /* Enable global interrupts. */

    /* Place your initialization/startup code here (e.g. MyInst_Start()) */

    for (;;) {
        /* Place your application code here. */
        SW2_state = Pin_SW2_Read();
        if (SW2_state) {
            // SW2 OFF
            Clock_880Hz_Stop();
        } else {
            // SW2 ON
            Clock_880Hz_Start();
        }
    }
}

メインループの中で入力端子の状態を読み取り、状態にしたがって Stop() メソッドまたは Start() メソッドを呼び出すという仕組みです。 ボタンを押し続けた場合、このループでは繰り返し Start() メソッドが呼び出されます。 「 Start() メソッドにより、 Clock コンポーネントが起動される」という目的で作られているのであれは、これでも問題ないのですが、どうも起動する以外の副作用が有りそうです。

実験開始

実験回路

そこで、実験回路を作成しました。

左半分の回路では、 Pwm_Start タイマにより周期的な割り込み int_Start を発生させて Pin_LED 端子に接続されている Clock コンポーネントの Start() メソッドを発行しています。 LED は、 Clock コンポーネントの周期 200ms で点滅を行います。 タイマに PWM コンポーネントを使用しているのは、出力を波形で見るためです。

一方、右側の回路は、左の回路で生成された信号を取りこむロジック・アナライザとして機能します。 信号を取りこむタイミングは、割り込み int_Sample で決定します。 Status Register で取りこんだ信号は、 UART コンポーネントで送り出します。 UART で送信されたデータは Bridge Control Panel で波形として表示します。 この動作は、 CY8CKIT-042 でロジアナを作った ~UART編~ で紹介した通りです。

// Re-start Clock component ISR
CY_ISR(int_Start_isr) {
    Clock_5Hz_Start();
}

// Logic sampling ISR
CYBIT  int_Sample_flag = 0;
uint8   probe = 0;

CY_ISR(int_Sample_isr) {
    probe = SR_Probe_Read();
    int_Sample_flag = 1;    
}

int main() {
    CyGlobalIntEnable; /* Enable global interrupts. */

    // Start method calling timing
    Pwm_Start_Start();
    Pwm_Start_WritePeriod(489);
    int_Start_StartEx(int_Start_isr);
    
    // Logic sampling timing
    int_Sample_StartEx(int_Sample_isr);
    
    // Logic analyzer output
    UART_Start();

    // Main loop
    for(;;) {
        // Sample logic level periodically        
        if (int_Sample_flag) {
            UART_UartPutChar(probe);
            int_Sample_flag = 0;
        }
    }
}

ソフトウェアは、上記のとおりです。 Start() メソッドを発行する周期を Pwm_Start タイマで規定しています。 この実験では、周期を変化させて動作を確認するために、周期をソフトウェアで決定しています。 こうすると、プロジェクトを Build した時に回路の配置配線を行う必要が無いため、実験に必要な時間を減らす事ができます。

実験の結果

490ms周期

まず、 Start() メソッドの周期を 490 とした場合、このような波形になりました。 Start() メソッドを発行してから、ちょうど 100ms 後に LED 出力が立ち下がり、さらに 100ms 後に立ちあがっているのがわかります。 100ms は、 LED を駆動する Clock コンポーネントの周期の半分です。 この様子から、 Start() メソッドの発行により、 Clock コンポーネントの内部カウンタがリセットされたと考えられます。 内部カウンタがリセットされたのに Clock 出力そのものがリセットされないのは妙です。 そこで、 Start() メソッドの周期を 390ms としてみました。


390ms周期

すると、 Start() メソッド発行後 100ms の位置にあった立ち下がりエッジが無くなりました。 さらに 100ms あと、つまり Start() メソッド発行後 200ms には立ち上がりエッジがあります。 これらの実験から以下の推論が導き出されます。

  1. Start() メソッドを発行すると Clock の内部カウンタがリセットされるが、クロック出力は以前の状態を保持する。
  2. Start() メソッドの発行からクロック半周期分の時間が経過すると、クロック出力が "0" に設定される。
  3. さらに半周期分の時間が経過するとクロック出力は "1" に設定される。
  4. 以降、クロック出力を "0" と "1" で交互に設定するとクロック出力が変化する。

以上の推測から、 Start() メソッドの発行周期を 200ms よりも短くすると、クロック出力は "0" に設定されたままで、クロックとしては機能しなくなると考えられます。


199ms周期

そこで、 Start() メソッドの周期を 199ms にしました。 すると、みごとに LED が点滅しなくなりました。 ブザーの音が出なくなったのは、 Start() メソッドの周期が短すぎて、クロック出力が出なくなってしまったものと推測されます。

解決策

ここからは、どうやったらブザー出力が出てくるかという解決策を探ります。 実験の結果から、 Start() メッソドの呼び出し周期が 1.2ms (880Hz) よりも短ければ、クロックは出力されます。 そこで、ボタンの判定の後、20ms ほど遅延を入れて Start() メッソドの呼び出しが頻繁に発生しないようにします。

    for (;;) {
        /* Place your application code here. */
        SW2_state = Pin_SW2_Read();
        if (SW2_state) {
            // SW2 OFF
            Clock_880Hz_Stop();
        } else {
            // SW2 ON
            Clock_880Hz_Start();
        }
        CyDelay(20);
    }

これで、ボタンに連動してブザーが鳴るようになります。 しかし、音が「にごる」ようになってしまいました。 これは、追加した遅延時間が短すぎて、クロック出力が歪んでしまったのが原因です。

遅延時間を長くすると、音の濁りが少なくなりますが、ボタンを押してから音が出る・止まるまでの遅延も大きくなり、ボタンに対する反応が遅くなったように感じます。

#include <project.h>

uint8   SW2_state;
uint8   SW2_last_state = 1u;    // OFF as default

int main() {
    CyGlobalIntEnable; /* Enable global interrupts. */

    /* Place your initialization/startup code here (e.g. MyInst_Start()) */

    for (;;) {
        /* Place your application code here. */
        SW2_state = Pin_SW2_Read();
        if (SW2_state && !SW2_last_state) {
            // SW2 ON to OFF
            Clock_880Hz_Stop();
        } else if (!SW2_state && SW2_last_state) {
            // SW2 OFF to ON
            Clock_880Hz_Start();
        }
        SW2_last_state = SW2_state;
    }
}

根本的な解決法として、以前のボタンの状態を記憶しておいて、状態が変化したら Clock コンポーネントの制御を行うようにしました。 ボタンの状態が変化した時だけ Start()/Stop() メソッドを呼び出すので、頻繁にメソッドの呼び出しが起こる事も無くなりました。 また、ボタンに対する反応も良くなりました。

参考商品

PSoC 4200 Prototyping Kit

PSoC 4200 Prototyping Kit

  • 出版社/メーカー: スイッチサイエンス
  • メディア: エレクトロニクス

nice!(0)  コメント(0)  トラックバック(0)  このエントリーを含むはてなブックマーク#

nice! 0

コメント 0

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

トラックバック 0

この記事のトラックバックURL:
※言及リンクのないトラックバックは受信されません。

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。