この記事は PICマイコン Advent Calendar 2025 10日目の記事です。
1. はじめに
前回の記事では、Lチカをしました。
今回は同じ回路構成のまま、タイマ割り込みを使ってLEDを周期的に点滅させます。
なお、クロックの設定やI/Oのピン設定などについては、前回の記事を参照してみてください。
2. 使用マイコン
本記事ではPIC24Fファミリに属するPIC24FJ64GB002を使用します。
LEDはRB10に接続しています。
3.タイマのセットアップ
今回は16ビットタイマを使用します。
まず、T1CON,TMR1レジスタを0x00で初期化します。
T1CONレジスタは、タイマ1の設定について保持するレジスタです。
TMR1レジスタは、タイマ1でカウントアップしていくうちの現在の値が入っているレジスタです。
次に、T1CONレジスタのTCKPSでプリスケーラーを1:256に設定します。
プリスケーラーは、タイマ1がカウントするクロックを分周するための設定です。
今回は、タイマがとれる範囲内で1000msの周期を扱えるように、分周比を大きくしています。
指定した分周比(1 : x)で設定可能なタイマ1の最長周期は、16ビットタイマの場合は次の式で求められます。
この式に出てくる65535はTMR1に入る最大値です。
T = \frac{65535 \times x}{FCY} \ \mathrm{(s)}
つぎにPR1レジスタで周期を設定します。
分周比(1 : x)のとき、周期を y msにするしたい場合のPR1は次の式でもとまります。
PR1 = \frac{FCY \times y}{1000 \times x}
タイマ1をスタートさせるにはT1CONレジスタのTONをHighにします。
これは、割り込みの設定が全て終わり、有効化されてから行うので、初期化関数とは分けました。
4.割り込み
割り込みをするには、次の三つのレジスタを設定する必要があります
- IPC : 割り込み優先度('P'riority)制御('C'ontroll)レジスタ
- IFS : 割り込みフラグ('F'lag)ステータス('S'tatus)レジスタ
- IEC : 割り込み有効化('E'nable)レジスタ
IPCレジスタ → IFSレジスタ → IECレジスタの順で設定していくという流れです。
ちなみに、IPCレジスタでは数が大きい順で優先度が決まります。
割り込みハンドラは、割り込みが起きたときに自動で呼ばれる関数です。
自分で関数を呼び出す必要はなく、割り込みフラグが立ち上がるとマイコンが勝手に実行してくれます。
割り込みハンドラの関数名はあらかじめ決められているため、自由に名前を付けることはできません。
どの名前を使えばよいかは、リファレンスマニュアルや XC コンパイラのユーザーガイドに記載されています。
XCコンパイラのユーザーガイドでは "7.4 WRITING THE INTERRUPT VECTOR" の章に書いてあります。
割り込みハンドラはタイマ1割り込みの場合、次のように定義します。
void __attribute__((__interrupt__, __shadow__)) _T1Interrupt(void);
少し長いので、_ISRFASTというマクロを使って書いてもいいと思います。
割り込みがかかったら、該当のIFSレジスタで、割り込みフラグを落とさなければなりません。
この処理を忘れると、割り込みが終わってもそのまま同じ割り込みが発生します。
割り込みハンドラ内では、NOT演算子を使ってLEDをトグルしています。
コード例
#include <stdio.h>
#include <stdlib.h>
#include "config.h"
#define FCY 4000000
void __attribute__((__interrupt__, __shadow__)) _T1Interrupt(void){
IFS0bits.T1IF = 0;
LATBbits.LATB10 = !LATBbits.LATB10;
}
void TMR1_init(double interval /* ms */){
T1CON = 0x00;
TMR1 = 0x00;
T1CONbits.TCKPS = 0b11; // 1:256
PR1 = (uint16_t)((interval/1000)*(FCY/256));
IPC0bits.T1IP = 1;
IFS0bits.T1IF = 0;
IEC0bits.T1IE = 1;
}
void TMR1_start(){
T1CONbits.TON = 1;
}
int main(int argc, char** argv){
OSCCON = 0x0000;
CLKDIV = 0x0000;
AD1PCFG = 0xffff;
TRISA = 0xffff;
TRISB = 0xffff;
TRISBbits.TRISB10 = 0;
TMR1_init(1000);
TMR1_start();
while(1){}
return (EXIT_SUCCESS);
}
※ config.h にはConfiguration Bitsの基本設定を入れています。
おわりに
今回は、割り込みの練習としてタイマ割り込みを使って L チカをしました。
今回はタイマ割り込みの例でしたが、割り込みの設定手順そのものは、他の割り込みでもほぼ共通です。
そのため、この流れはぜひ覚えておくとよいと思います。
特にタイマ割り込みは、
-
制御周期の生成
-
定期的なセンサ読み取り
-
モータ制御
などでよく使われます。
そのため、新しいマイコンを触り始めたら、早めに慣れておくことをおすすめします。
PICマイコンでレジスタを直接叩くと、「各ペリフェラルを使うために、何を設定する必要があるのか」というのが自然とわかるようになります。
この感覚は、他のマイコンを使うときにもかなり役に立つと思います。
そのため、この記事がどなたかのお役に立てれば嬉しいです。