こんにちは!
前回お見せしたソースコードをこっそり書き換えちゃったゆってぃです(コラー!!)
本当に申し訳ありませぬ・・・


さて、今日は前回の続きをお話しましょう。
一応、前回使用したソースコード(修正後)を書いておきますね。


#include "pic.h"

__CONFIG( FOSC_EXTRC & WDTE_OFF & PWRTE_ON & CP_ON);

void main(void){

 //すべての割り込み許可
 GIE = 1;

 //タイマー割り込みを禁止
 T0IE = 0;

 //TIMER0モジュールをタイマーとして使用
 T0CS = 0;

 //プリスケーラをTIMER0モジュール用にセット。PSA = 1 でWDT用になる。
 PSA = 0;

 //CPUクロックを256分周
 OPTION_REG |= 0x07;

 //カウンタ値をリセット
 TMR0 = 0x00;

 //PORTBをすべて出力に。
 TRISA = 0x00;
 TRISB = 0x00;

 //タイマー割り込みを許可
 T0IE = 1;

 while(1);
}

void interrupt tc_int(void){

 //もし、タイマー割り込みなら…
 if(T0IF){
  T0IF = 0;
  PORTA ^= 0xff;
  PORTB ^= 0xff;
  return;
 }
}

今日は

PSA = 0;

から始めましょう。
これは、PIC16F84Aに内蔵されているプリスケーラをタイマーモジュールに使用するか(PSA=0)、ウォッチドックタイマ(以下、WDT)に使用するか(PSA = 1)を選択するレジスタです。
詳細はデータシートの19ページをご覧ください。

さて!ここで、新しい言葉が出てきましたね。
「プリスケーラ」です。

「プリスケーラ」とは、日本語に直すと分周器です。
分周とは、一言で言えば周波数を下げることです。(ちなみに、分周器を発明したのは日本人なんですって!)

ここで
「なんで周波数を下げる必要があるんけ?周波数は早い方がええんちゃうか?」
と思われる方もいらっしゃるでしょう。

まず、タイマー割り込みが発生するタイミングなのですが、TMR0レジスタはたったの8bitしかありません。
つまり、0からカウントを始めても、255までしかカウントアップできないのです。
TMR0レジスタが255の時にさらにタイマークロックが入ると、TMR0レジスタは溢れて0に戻り、それを合図にオーバーフローフラグ(T0IF)が立ち、割り込みハンドラが呼ばれます。
(レジスタの値が1111_1111の時にタイマークロックが入ると、溢れて0000_0000になります。TMR0レジスタが、もしも9bitだったら、1_0000_0000になるはずなんですけどね)

つまり、もしもタイマークロックが早すぎた場合、一瞬でTMR0がオーバーフローして、割り込みハンドラが呼ばれまくります。
これじゃあ、とても使いづらいですよね。(使おうと思えば使えますけど)

ですので、タイマークロックが最適な値になるよう、プリスケーラで最適な値に設定してあげる必要があるんですね。
因みに、ここで周波数を下げるのはタイマークロックのみで、CPUの動作周波数は下がりませんのでご安心ください。

そして、タイマークロックはCPUクロックを基準にしてどのくらい分周させるのか(それを分周比といいます)を決めるのがOPTION REGISTERの0~2ビット目です。
OPTION REGISTERとは、PIC16F84Aの各種機能を設定できるレジスタです。
ゲームが好きな人でしたらご存知かと思いますが、たいていのゲームでは、メニュー画面に「オプション」ってのがありますよね。
BGMや効果音の音量を決めたり、コントローラーのボタン配置を決めたり、画面の明るさを変えたり…。
あれと同じで、たとえば今回のようにタイマークロックの分周比を設定したり、プリスケーラをタイマーモジュールとウォッチドッグタイマのどちらに使うか決めたりするのが、このOPTION REGISTERなのです。
ここで勘の良い人は
「ん?じゃあ、T0CSやPSAもOPTION REGISTERの一部なんじゃないのか?」
とお考えになるでしょう。

正解(みのもんた)

そう、実はOPTION REGISTERは8bitのレジスタなんです。
詳細はデータシートの9ページに書かれていますが、
T0CSはOPTION REGISTERの5ビット目、PSAはOPTION REGISTERの3ビット目なんです。
ですので、今回のようにPSAを0にセットしたい場合は

OPTION_REG &= 0xf7;

と書いても同じです。慣れたプログラマの人だと、この様に書く人も少なくないですね。

今回は、このOPTION REGISTERの0~2ビット目を1で埋めています。

OPTION_REG |= 0x07;

こうすると、CPUクロックを256分周したものを、タイマークロックとして供給することが出来ます。
詳細はデーターシートの9ページをご覧ください。
また、先述の通り、PSA = 1 とした場合は、プリスケーラはタイマーモジュール用ではなくWDT用になります。
その場合、タイマーモジュールにはCPUの動作クロックが分周されずにそのまま入ります。

さて、次は

TMR0 = 0x00

ですね。
これは、タイマークロックが入ってくるとカウントアップ(加算)される8ビットのレジスタです。
こいつが1111_1111の時にさらにタイマークロックが入ると、割り込みハンドラが呼ばれます。
初期値は何もしないと不定なので、0000_0000を入れてあげましょう。

TRISA と TRISB は前にお話したので割愛します。

そして、全てのセッティングが完了したら

T0IE = 1

としてタイマー割り込みを許可してあげましょう。
main関数は、そのあと無限ループに入れてあげます。


いやぁ、今回はボリュームがあって読むのも大変でしょう。
でも、あと少しですから頑張ってくださいね!!


さて、いよいよ割り込みハンドラの記述です。

void interrupt tc_int(void){

 if(T0IF){
  T0IF = 0;
  PORTA ^= 0xff;
  PORTB ^= 0xff;
  return;
 }
}

割り込みハンドラは、コンパイラがわかるようにinterruptというキーワードを付けてあげます。
これを付けないと、割り込みハンドラだと認識してもらえません。
なお、関数名は適当です(笑)
では、さっそく中身を見てみましょう。

まず、

if(T0IF)

です。
PIC16F84Aでは、割り込みが入ると、その割り込み内容によらず、割り込みハンドラ関数が呼ばれます。
ですから、タイマー割り込み以外の割り込みが入っても、(今回の場合は)tc_int()関数が呼ばれてしまうのです。
ですので、この関数内で、一体何の割り込みが発生したのかを判断しなければなりません。
それは、割り込みフラグというフラグを見ればわかります。

たとえば、TMR0がオーバーフローした場合は、T0IFが1になります。
ですので、if(T0IF)というように書き、もしTMR0のオーバーフローで割り込みハンドラが呼ばれたなら、以下の処理をしますのように、if文で制御してあげます。

まず、

T0IF = 0

として、割り込みフラグをクリアしてあげます。
これは割り込みハンドラ内で忘れずに行ってください。
データシートの20ページにも記載があります。(なお、データシートでは、割り込みハンドラをInterrupt Service Routineと記載していますね)

次に、行いたい処理を記述します。
今回は

PORTA ^= 0xff;
PORTB ^= 0xff;

として、出力ポートの出力信号を反転させています。
こうすることで、LEDをペコペコさせているのです。

なお、このマイコンでは、割り込み要因に関わらず割り込みハンドラはひとつしかありません
、他のマイコンでは要因ごとに割り込みハンドラを定義する場合がほとんどです。
ですので、PIC16F84Aではこういう感じで書くんだなぁ、と認識しておいてください。

さて

ざっとこんな感じですが

なんとなく割り込み制御に関して理解できましたでしょうか?

もしもこのつたない説明で理解できたのであれば

あなたは組み込みセンス抜群です!

おそらく、組み込みを始めたばかりの僕がこのサイトを見たとしても

何ひとつ理解できなかったでしょう!(ぉぃ…)

それどころかクソブログと罵っていた可能性すらあります(笑)

最後までお読みいただき、ありがとうございました^^

関連記事
スポンサーサイト
コメント
もう二年前の記事ですが・・
とても参考になりました。ありがとうございます。
Re: タイトルなし
> ishida さん

こちらこそ、2年も前の記事をご覧頂き、ありがとうございます^^
PICが使えるようになれば、他のマイコンも容易に扱うことが出来ると思います。
頑張ってくださいね!
初めまして
初めまして。
私は、部活で、PICマイコンをC言語で
制御している高校生ですが、
タイマ0を利用した、時間測定をしようと悩んでいるときに、
この記事を拝見させていただきました。

割り込みのことなどとてもわかりました。ありがとうございます。
コメントの投稿
トラックバック URL
トラックバック
ご訪問者様
プロフィール

ゆってぃ

Author:ゆってぃ
経歴7年の組み込み系・制御系エンジニアです。
("ど素人"という文言は取りました…笑)
ソフトウェア開発経験ゼロの状態から、なんとか実務がこなせるようになってきた現在に至るまでの経験を、備忘録代わりに綴っていきたいと思います。
入門者の方、大歓迎!
(上級者の方、ごめんなさい…)

あと、ブログには全然関係ないですが、Bumpy Headというバンドのギターをやっています。
ライブ情報なんかも書いたりすることがあるので、その時に「行ってもいいよ~」といった感じのコメントを戴けると、泣いて喜びます(泣)
ブログ読んでくださってる方なら、チケット代サービスしちゃいます!

最後に…滅多に流用することは無いでしょうが、このブログに書かれているソースは、特に指定の無い限りMITライセンスとします。ただし、一部それ以外のものもございますのでご注意下さい。
※ブログのリンク先にあるコードに関しては、リンク先のポリシーに従ってください。

最新記事
最新コメント
カテゴリ
RSSリンクの表示
メールフォーム

名前:
メール:
件名:
本文:

twitter
リンク
ブロとも申請フォーム
スポンサードリンク