■課題6のCソース・ファイルとHEXファイルはこちらです【LZH】
■ 課題7
RIGHT,UP,LEFTのlEDでは1秒間隔で●●●●と○○○○の点滅を行います。
一方、割り込み処理を使って、DOWN_LEDは0.1秒間隔で○○○●と○○○○の点滅を行います。
DOWN_LEDとほかのLEDでは点滅間隔が違う、割り込み処理の課題です。
// ex7-7_warikomi.c
// PIC16F84A用
#include<16f84a.h>
#fuses HS,NOWDT,NOPROTECT
#use delay(clock=20000000)
#byte RA=5
#byte RB=6
#bit IRSIG=RA.2
#bit TACTSW=RA.3
#bit DOWN_LED=RB.0
#bit UP_LED=RB.2
#bit RIGHT_LED=RB.1
#bit LEFT_LED=RB.3
int led_data,wcount;
// 1/20(MHz)*4*256*195=9.8304ms
// 9.8304ms*10=0.09830s=0.1s
#INT_RTCC
timer0_led_flash(){
set_timer0(61); //255-61+1=195
wcount--;
if(wcount==0){
led_data=0x01-led_data;
DOWN_LED=led_data;
wcount=10;
}
}
main()
{
set_tris_a(0x1f);
set_tris_b(0x00);
setup_timer_0(RTCC_INTERNAL | RTCC_DIV_256);
set_timer0(61);
wcount=10;
led_data=0;
enable_interrupts(INT_RTCC);
enable_interrupts(GLOBAL);
while(1){
RIGHT_LED=UP_LED=LEFT_LED=1;
delay_ms(1000);
RIGHT_LED=UP_LED=LEFT_LED=0;
delay_ms(1000);
}
}
■割り込みとは・・・
読書に没頭しているとします。読み進み、山場を迎えた頃に、「りりーん」と電話がかかってきてしまいました・・・。無視もできないので、仕方なく出ると「プルトニウムがお買い得ですよ。」(^^;)
メインに動いているプログラムに対してなんらかのタイミングで別の処理を行うことを「割り込み」といいます。割り込み要求が入るとメイン・プログラムに優先して実行されます。この割り込み処理があることで、PICの能力は飛躍的に向上していますが、一番わかりにくい部分であると思います。
PICでもいくつかの割り込みが用意されています。ここではよく使うタイマ割り込みを使います。
■割り込み間隔
setup_timer_0(RTCC_INTERNAL | RTCC_DIV_256);//timer0初期化
RTCC_INTERNAL:クロックは内部クロックを使う指定です。
RTCC_DIV_256:プリスケーラ値を256にします。
PIC赤外線受信ボードでは20MHzのセラロックを接続していますが、これを内部クロックとしてそのまま使います。20MHzで駆動すると、
1/20MHz=0.05μs:1パルスの時間
内部ではこの4倍の時間(式の×4倍)がかかるので、
0.05μs×4=0.2μs:
PIC内部にあるプリスケーラ=分周器はパルス・カウントを指定の回数積算してから出力する働きがあります。プリスケーラが256とすると、256回パルスをカウントして「1回」とすることになります。したがって、
0.2μs×256=51.2μs
これをtimer0でカウントして10msにするには、
10ms/51.2μs=195回
となるので、timer0で195回カウントして割り込みをかければ10msを得ることができます。timer0が逆算カウンタなので、
255-195+1=61
がtimer0にセットする初期値となります。+1するのは0の分があるからです。
■割り込みのまとめ
10msを得るための割り込み間隔の計算方法は・・・・
1/クロック周波数×4倍×プリスケーラの値×(255-タイマ初期値+1)の場合は、
クロック周波数:20MHz
プリスケーラ値:256
タイマ初期値:61
1/20(MHz)*4*256*195=9.8304ms
となり、9.83msごとに割り込みがかかります。
■割り込みを利用したプログラミング
#INT_RTCC //timer0割り込み処理を使うときはまずこれを書きます
timer0_led_flash(){ //この部分の関数名はなんでもよいのでつけます
set_timer0(61); //タイマー初期値です:255-61+1=195
wcount--;
if(wcount==0){ //カウンターを減らして、10回の時にledの点灯消灯します
led_data=0x01-led_data; //0x01と0x00を繰り返します。
DOWN_LED=led_data; //DOWN_LEDの点灯処理
wcount=10; //9.8304ms*10=0.1sを作るためのカウンタです
}
}
上のINT_led_flash()関数は、先ほど計算した9.83msごとに割り込みがかかり、呼び出されます。これを10回呼び出されると、0.1秒になります。
9.8304ms*10=0.09830s=0.1s=約0.1秒
となります。
led_data=0x01-led_data;//0x01と0x00
を繰り返します。
0.1sごとにこの式を実行することになり、LEDが0.1sごとに点灯・消灯を繰り返すことができます。
■割り込みの許可
実際のプログラミングでは、割り込みを許可しないと割り込みは発生しません。
enable_interrupts(INT_RTCC);//割り込み許可
enable_interrupts(GLOBAL);//全ての割り込みを許可
以上を記述すると割り込み動作を開始します。
なお、割り込みは停止することもできます。
disable_interrupts(INT_RTCC);
割り込みが発生するとメイン・プログラムは動作を一時停止して、割り込み処理を優先します。割り込み処理が長くかかるとメイン・プログラムの動作に支障がきたす場合は、割り込みを停止することも必要になります。
プリスケーラの倍率とタイマ初期値を組み合わせて時間を設定するため、割り込み処理はなかなかやっかいですが、理解すると応用範囲は無限大です。頭の体操と考えて取り組んでください。
今回は穴埋め★マークはなしですが、次回にのCソース・ファイルとHEXファイルを掲載します。
■ 訂正
割り込み処理の注釈文の中で、
// 9.8304ms*25=0.09830s=0.1sとありますが、
// 9.8304ms*10=0.09830s=0.1sの間違いです。訂正させていただきます。

インドアプレーンで学ぶマイコンのハードとソフト
赤外線制御で学ぶPICとC言語
PICマイコンでつくるインドア・プレーン
みんなで作ろうインドア・プレーン