さて、今回、このタイマ、ちょっと調べて見たら「32kHz」を入力できるようです。また、「32kHz」は内臓しているとのこと。
精度は、内臓24MHzのクロックが±2.5%とのことから、たぶん、これも±2.5%かな。内部低速発振器(ILO)を使っているとのことなので、
きっとそうでしょう。
この32kHzというクロック、時計などではよく使われるクロックで、正確には「32.768kHz」だったと思います。
PSoCの内臓32kHzの場合は、32000、32768、どっちなんだろう?ま、一般的と言う事で、32768ということで進めてみます。
またアプリケーションノートあたりを探してみます。
クリックで拡大します。
|
まずはプロジェクトを作ります。今回は、「LedFlicker」としました。
|
クリックで拡大します。
|
それではさっそく「Timer16」を選択します。今回、32768をカウントして1秒を作り出すため、16ビットカウンタを選択します。
8ビットカウンタの場合、「0〜255」までしかカウントできませんが、16ビットカウンタならば「0〜65535」までカウントでき、
ばっちりです。
|
クリックで拡大します。
|
「Device Editor」の「Selection」画面から「Interconnect」画面に切り替えます。そして「Timer16_1」を「Place」します。
|
クリックで拡大します。
|
それでは、「Timer16_1」の設定をします。今回、「Global Resources」の設定は、すべてデフォルトで問題ありません。
まずは「Clock」を「CPU_32_KHz」にします。そして「Caputure」は「Low」(なんか、有効/無効をHigh/Lowで表現しているみたいです)。
「Period」は、タイマの期間ですので「32768」から「-1」した値である「32767」を設定します。
他のサンプルとかみると、こう「-1」して書いて「Compare Type」を「Less than Or Equal」にしていたので、
同じようにしています。
あと大事なのが「ClockSync」です。必ず「Use SysClk Direct」以外を選択してください。これ、厳密にどんな機能か、
まだ理解していないのですが、「Use SysClk Direct」を選択すると、さっきの32kHzの設定が無視されて、
SysClkが使用されるようなことがマニュアルに書いてありました。実は、最初、「なんでLEDが点滅しないんだろ〜!?」と、
はまりました。
というわけで、「Generate Application」しましょう。
|
クリックで拡大します。
|
さってと、いよいよ割り込み処理です。まずは「Application Editor」に切り替えます。サンプルを見てみると…
モジュール起動や割り込み許可の処理は書いてあっても、なんと、肝心な割り込み処理のサンプルがありません〜。
ひょ〜。というわけで、ごにょごにょと調べると…(って、本に書いてありますね)、自動生成されたソースコード、
「boot.asm」に割り込みベクタテーブルが書いてあり(割り込みが発生した時に参照されて、
必要な処理に移るためのテーブル)、ジャンプ先は、これまた自動生成されたソースコードの「timer16_1int.asm」
の中に定義されていました。「Library Source」の中にあります。
どうやらここに直接コードを書くか、C言語の関数を作っておいて、割り込み関数の宣言をしておけばよさそうです。
|
クリックで拡大します。
|
せっかくC言語が使えるし、そんなにスピードも気になりませんから、今回はC言語で割り込みを記述します。
まずは、いつものメイン処理を記述します。これはマニュアルを読むと載っているので、ほとんどそのまま使います。
まずは「Timer16_1」の割り込み用初期化をし、その後、CPU全体の割り込み許可をして、最後にモジュールをスタートかけるようです。
で、プログラムが終わると、そのままPSoCもとまってしまいますので、最後に、永久ループ(って言うのかな?)として、
ぐるぐる回りの一行を入れておきます。
Timer16_1_EnableInt();
M8C_EnableGInt;
Timer16_1_Start();
while( 1 );
本題の割り込み処理ですが、C言語で割り込み処理を記述する場合、あるおまじないをします。
というわけでいきなりでてきたのが「#pragma」。これは…よくわからないので、お作法とて覚えておくことにします。
この行の一番最後は関数名で、次の行(次の行である必要はありませんが)に関数の本体が定義してあります。
こうやって記述すると、割り込み処理として認識してくれるようです。関数名は好きなものをつけて頂けばOKです。
中身は、単にPORT2の[0]〜[3]をひっくり返す、というものです。
#pragma interrupt_handler int_timer16_1
void int_timer16_1()
{
PRT2DR ^= 0x0F;
}
|
クリックで拡大します。
|
それでは、Application Editor上から「Library Source」フォルダを開いて、「timer16_1int.asm」の編集をします。
「asm」と拡張子がついているだけあって、アセンブラです。え?アセンブラ、わかりません?大丈夫です。
SISOもわかりません。「boot.asm」の方を見て、ごくごく簡単に書きました。
書いたのは、先ほど作った割り込み処理の「int_timer16_1_TC()」を呼び出す処理です。
「ljmp」っていうのはきっと「ジャンプする命令」だろうと。で、あと、割と定番なんですが、
アセンブラからC言語を呼び出す時には、関数名の頭に「_」(アンダーバー)をつけるようです。
というわけでできたのが、次の一行。
ljmp _int_timer16_1
|
クリックで拡大します。
|
ビルドしてみると…何やら警告がでてきてしまいました。あらら。ま、よくわからないので、とりあえず無視しておきます。
後は「PSoC Programmer」を起動してPSoCに書き込めばおしまいです。「PSoC Programmer」から、MiniProg1の電源をONしてやれば、
見事にチカチカとLEDが4つ同時に点滅すると思います。1秒に一度、点灯と消灯を切り替えていますので、
点滅周期は2秒になります。
|
クリックで再生します。
|
それでは、動作中のPSoCの動画をお楽しみください(動画だけ見ても楽しくないかもしれませんが、
自分でプログラムしたものが、思ったとおりに動作するのは楽しいですよ!)。
う〜ん、心なしか1秒よりちょっと遅い感じ。
ここで疑問なんですが、「割り込み処理の呼び出しは、boot.asmの方に呼び出しを書いたほうが速いんじゃないの?」
って思っちゃいますよね〜。というわけで試してみました。「ljmp _int_timer16_1_ISR」と書いてあるところを、
「_int_timer16_1」としたら、ちゃんと動作しました。ところが、ちょっと困った事が。
「Generate Application」を再度したら、コードが初期化されました。やっぱり、
ちゃんと「ここにコード書いてね〜」とあるところに書かないとダメですね〜。
|