【
MPC17-03-B
】
PIC12F1822
マイコンライトのハードとファームウェア作成
1
<MISSION> 次の仕様を満たすマイコンライトのハードウェアとファームウェアを完成せよ
(1)
作成したいマイコンライトの仕様
(a)
ハードウェアの仕様
回路図に示したように、マイコン
(PIC12F1822P)に
LED
とフォト
トランジスタを接続したものであ
る
(b)
ファームウェアの仕様
①電源投入時には、
LED
が数回点滅
し、待機状態に入る。
②待機状態では、光センサの出力を監視し続ける無限ループにする。
③光センサの出力を「暗い」と判断した場合、指定した秒数だけ
LED
を規則的に点滅する。
④指定した秒数が経過すると、LED
は消灯する。
⑤光センサの出力が「暗い」と判断されている間は、LED
は消灯し続ける。
⑥光センサの出力が「明るい」と判断されたときは、②に戻る。
(2)
拡張仕様(できれば挑戦してみよう)
LED
の明るさが徐々に変わり点灯したり消えたりする関数
pwmLed()の利用
void pwmLed(void) {
int32_t led_blink_interval = 200; // 徐々に明るさを変えるための上限値 int32_t pwm, dpwm; // LED の明るさを PWM 制御するためのカウンタとカウンタの増分 //タイマのカウンタが決まった時間になるまで繰り返し実行
if (pwm > led_blink_interval) { // pwm カウンタが最大値を超えたら pwm = led_blink_interval; // pwm カウンタを最大値にセット dpwm = -1; // pwm カウンタの増分をマイナス(減) } else if (pwm < 0) { // pwm カウンタがマイナスになったら pwm = 0; // pwm カウンタを 0 にリセット
dpwm = +1; // pwm の増分をプラスに設定 }
ledOn(); // LED 点灯
wait(pwm); // pwm の間点灯し続ける ledOff(); // LED 消灯
wait(led_blink_interval - pwm); // ちょっとの間 LED を消灯し続ける pwm += dpwm; // pwm カウンタを増やす }
ledOff(); // LED を消灯する }
pwmLed()
を使って、指定時間だけ光らせるには、
2
ハードウェアの製作
(1)
回路図
(2)
部品と実体配線図
電源は単3電池2本または3本。
A
【
Electronics DIY
】
PIC12F1822 LED MARKER
PIC 12F1822
A
凹
黒
Firmware
Code
(Universal Circuit Board Sunhayato ICB-91)
PIC 12F1822
E
凹
E
104
Opt-Transistor
NJL-7502
LED
(3)
関連知識:マイコンのピン配置
マイコンに限らず
IC
の端子(ピン)には番号があり、凹部を
左に置いたときに、左下から反時計回りに
1, 2, 3, …
と振られて
いる。(図)
このテキストで使用するワンチップマイコ
ン
PIC12F1822
のピンには、複数の機能が割
り当てられているが、この後の説明で使用す
る機能は、右図のとおりである。
(4) PICkit3
の接続
図のように、PICkit3
を接続する。
PICkit3
PIC
12F1822 VSS Ground
VDD MCLR/VPP
ICSPDAT ICSPCLK
PIC 12F1822
PINの機能
1
2
3
4
5
6
7
8
VDD +電源
RA5
入出力 アナログ入力RA4/AN3 ポート
RA3 入力 RA2 入出力
RA1 入出力 RA0/CPS0
入出力/タッチセンサ VSS -電源
PIC 12F1822
1
2
3
4
5
6
7
8
3
プログラミングの前の準備
(1)
プログラムの開発環境の準備とプロジェクトの作成
別添資料「
PIC
マイコンにプログラムを書き込む方法」を参
照のこと。
今回は、学習用プロジェクトファイル
mpc17-03
を作成すると
ころから始める。
(2)
統合開発環境
MPLAB XIDE
でプロジェクトを開く。
(a) MPLAB XIDE
を起動する。
(b)
新しいプロジェクトを作成
[File]-[New Project ...]
をクリック
(c) [Choose Project]
初期のプロジェクト
[Microchip embedded]-[Standard project]
のま
ま、
[Next]
をクリック。
(d) [Select Device]
マイコンの種類を選択する。
[Family] は[Mid-Range-8-bit-MCUs]を選択、
[Device]
は
[PIC12F1822]
を選択、
[Next]
をクリック。
(e) [Select Header]
デバッグ用のヘッダを選択する。
今回は、簡単なプログラムなのでヘッダをつけない。[None]のま
ま、[Next]をクリック。
(f) [Selet Tool]
プログラムの書き込み用のツールを選択する。
[PICkit3]
をクリックして、
[Next]
をクリック。
(g) [Select Compiler]
ソースプログラムをマイコンの機械語に変換するためのコンパイ
ラを選択。[XC8...]の最新のものをクリックして、[Next]をクリッ
ク。
(h) [Select Project Name and Folder]
プロジェクト名とフォルダ名の設定。
[Project Name]
を
[mpc17-03]
と入力
[Encoding]
は、
[UTF-8]
とする。これは、ソースプログラム中に日
本語を使うために設定する。
[Finish]
をクリック。
(i) Main Project
確認
(3)
ソースプログラムの作成
(a)
プロジェクトの展開
画面左側の
Projects
ウィンドウにある
[
▶
︎
mpc17-03]
の︎をクリックし、展開する。
(b)
ソースファイルの追加
[
▶
︎
Source Files]
を右クリック。
[New
▶
︎
]-[main.c…]
(c)
ソースファイル名の入力
ファイル名として
[main-mpc17-03]
と入力。
[Finish]
をクリック。
(d)
作者名の変更
ソースファイルの先頭3行目にある、Author (作者)の欄に、作者名を記入。
/*
* File: main-mpc17-03.c
* Author: *****
*
* Created on August 11, 2017, 3:12 PM
*/
7行目以降を削除して、後で示されるサンプルソースファイルをコピー&ペーストする。
4
ファームウェア製作のための関数の用意とプログラムの動作確認
関数は、複雑なプログラムを作成するための部品のようなもの。次の関数を使うために、プログ
ラムをコピーする。
(1)
関数の一覧
関数名
機能
戻り値
引数
initIo()
I/O
ポートの初期化
なし
なし
initAdc()
A/D
コンバータの初期化
なし
なし
ledOn()
LED
を点灯する
なし
なし
ledOff()
LED
を消去する
なし
なし
ledBlink()
LED
が点灯していたら消
灯、消灯していたら点灯す
る。
なし
なし
isDark()
光センサの出力から「暗
い」かどうか判定
暗い
-1,
明るい 0
なし
startTimer(uint32_t time)
Timer0
を初期化して計時を
開始する
なし
time
タイマを設定する
時間(秒数)
(2)
関数の定義などのコピー&ペーストと実行確認
(a) MPLAB XIDE
の画面で、”
MPC17-03”-”Source Files”-”main-mpc17-03.c”
を開く。
(b) 7
行目以降に、次のコードをコピー&ペーストする
/
*
* LED1 : PIN 7 (RA0) : 0-OFF, 1-ON
* ANALOG PORT : PIN 3 (AN3/RA4)
*
*/
#include <xc.h> // XC8
コンパイラ用のヘッダ(レジスタ名などのキーワードの定義を含む)
#include <stdint.h> // 整数型のビット数を明示して宣言するためのヘッダファイル
#define TIME_LIMIT 5 // LED
が点灯している時間(秒数)
// PIC
マイコンの動作設定その1
// PIC micro controller Configuration 1
#pragma config FOSC = INTOSC // 内部クロック使用。
#pragma config WDTE = OFF // ウォッチドッグタイマなし。
#pragma config PWRTE = ON // 64ms
後にプログラム開始。
#pragma config MCLRE = OFF // 外部リセットなし。RA3 は入力ピン。
#pragma config CP = OFF // コード保護なし。
#pragma config CPD = OFF // データ保護なし。
#pragma config BOREN = ON // 電源電圧低下時のリセットあり。
#pragma config CLKOUTEN = OFF // クロック出力不可。
#pragma config IESO = OFF // 内部外部クロックなし。
#pragma config FCMEN = OFF // FCM
なし。
// 動作設定その2
// Configuration 2
#pragma config WRT = OFF // 書き込み保護なし。
#pragma config PLLEN = OFF // PLL
なし。
#pragma config STVREN = ON // スタックオーバー/アンダーフローでリセット。
#pragma config BORV = LO // 電源電圧低下監視閾値は Low モード
#pragma config LVP = OFF // 低電圧プログラムなし。
// I/O
ポートの初期化
void initIo(void)
{
OSCCON = 0b01110010; // 内部クロック 8MHz。
OPTION_REG = 0b00000000; // ウィークプルアップ使用可。
ANSELA = 0b00000000; // 全 I/O ポートがディジタルポート。
TRISA = 0b00001000; // 入力ポートは RA3, 他は出力ポート。
WPUA = 0b00001000; // RA3 ポートはウィークプルアップ。
PORTA = 0b00000000; // PORTA を 0 で初期化。
}
// I/O
ポートの設定定義 (LED を接続するポートが変わった時はここを変更する)
#define PORT_LED RA0
#define TRISA_LED TRISA0
// A/D
変換用 I/O ポートの設定定義
#define PORT_ADC ANSA4
#define TRISA_ADC TRISA4
#define PORT_NO_ADC 3
// LED
制御用関数
inline static void ledOn(void)
{ PORT_LED = 1;
}
inline static void ledOff(void)
{ PORT_LED = 0;
}
inline static void ledBlink(void)
{ PORT_LED ^= 1;
}
// ちょっと待つ処理を簡
単
に書
く
ための関数
void wait(volatile uint32_t i)
{
// A/D
変換関数
void initAdc(void)
{
PORT_ADC = 1; // PORT_ADC で定義されたポートをアナログポートにする。
TRISA_ADC = 1; // A/D 変換
端子
を入力モードにする。
ADCON0 = 0b00000001
|
(PORT_NO_ADC << 2); //AD
変換を
有効
化。
ADCON1 = 0b01000000; // 0:(ADFM=0)
精度
10bit, 100:Fosc/4 ,0:Reserved, 00:AVDD=VREF
CM1CON0 = 0x00; //コンパレータを
無効
化。
}
uint16_t getAdc(void)
// A/D
変換した値を
得
る。
//
戻
り値
:
A/D 変換されたアナログ
信号
の大きさ(0
〜
1023)
{
uint16_t adcvalue;
//ADC
wait(10);
GO_nDONE = 1;
while (GO_nDONE);
adcvalue = ADRESH<<2
|
ADRESL>>6 ;
return adcvalue;
}
int8_t isDark(void)
//
光
センサの出力
か
ら
、「暗
い
」か
どう
か判断
する。
//
戻
り値
;
「暗
い
」
と
判断
したとき -1
// それ
以
外 0
{
uint16_t photo; //
光
センサの出力値
int8_t result; //
戻
り値
uint16_t darkness_threshold = 500; //
「暗
い
」
と
判断
する閾値
photo = getAdc(); //
光
センサの出力を A/D 変換
if ( photo > darkness_threshold ) { //
「暗
い
」
とき
result = -1;
} else { //
「
明るい
」
とき
result = 0;
}
return result;
}
void initTimer0(void)
// Timer0
{
TMR0 = 0x00; // Initialize TIMER0
TMR0CS = 0; //Internal instruction c
y
cle clock (FOSC/4)
PSA = 0; //Prescaler is assigned to the Timer0 module
PS2 = 1; PS1=1; PS0 = 1; // Prescaler Rate Select bits set 1:256
TMR0IE = 1; // Timer0 Intterupt Enable
PEIE = 1;
GIE =1;
}
volatile uint32_t T0Counter; // Timer0 overflow Counter
void interrupt isr(void)
//
割
り込みが
発生
する
ご
とに
、
この関数が呼ばれる。
{
if (TMR0IF) {
// Timer0 Interruption
TMR0IF = 0; // Clear Timer0 Interrupt Flag
TMR0 = 0; // Clear Timer1 counter
void startTimer(uint32_t time)
// Timer
を初期化して
計
時を開始する
//
引
数
:
time タイマを設定する時間(秒数)
{
uint32_t T0UNIT = 31; // Timer0Counter about 1sec ( 1 / (1 / ((Clock 8MHz / 4) / prescaler
256) * 256)
initTimer0(); // TIMER0 の初期化
T0Counter = time * T0UNIT; // TIMER0 のカウンタを設定値にする
}
void pwmLed(void) {
int32_t led_blink_interval = 200; // 徐々に明るさを変えるための上限値
int32_t pwm, dpwm; // LED の明るさを PWM 制御するためのカウンタとカウンタの増分
//タイマのカウンタが決まった時間になるまで繰り返し実行
if (pwm > led_blink_interval) { // pwm カウンタが最大値を超えたら
pwm = led_blink_interval; // pwm カウンタを最大値にセット
dpwm = -1; // pwm カウンタの増分をマイナス(減)
} else if (pwm < 0) { // pwm カウンタがマイナスになったら
pwm = 0; // pwm カウンタを 0 にリセット
dpwm = +1; // pwm の増分をプラスに設定
}
ledOn(); // LED 点灯
wait(pwm); // pwm の間点灯し続ける
ledOff(); // LED 消灯
wait(led_blink_interval - pwm); // ちょっとの間 LED を消灯し続ける
pwm += dpwm; // pwm カウンタを増やす }
ledOff(); // LED を消灯する
}
void main(void)
//
メ
イン関数。この関数
か
ら動作開始
{
int i; //
汎
用カウンタ
initIo(); // I/O ポートの初期化
initAdc(); // A/D 変換ポートの初期化
//
起
動時に LED を 3
回
点
滅
する
for ( i = 0; i < 3; i++ ) {
ledOn(); wait(10000);
ledOff(); wait(10000);
}
while (1) {
// この後にコードを
追加
}
}
(3)
ビルドと書き込み、動作確認
[Make and Program Device Main Project]
のアイコンをクリック
[CAUTION]
警告のダイアログボックスが表
示されたら、
電源が正しく接続されていることを確認し
て、
[OK]
をクリック。
(標準では、
PICkit3
から電源供給をしないので、問題はな
い)
※書き込みの段階で、赤い字でエラーメッセージが出る場合、
電源が接続されていなかったり、電線の接続に不具合があっ
たりすることが多い。
X IDE
の下側の
[Output]
に
[Programming/Verify complete]
と表示されたら、書き込み完了。
5
MISSION
のプログラムの作成手順
(1)
ファームウェアの仕様の
確認
①電源投入時には、
LED
が数回点滅し、待機状態に入る。
②待機状態では、光センサの出力を監視し続ける無限ループにする。
③光センサの出力を「暗い」と判断した場合、指定した秒数だけ
LED
を規則的に点滅する。
④指定した秒数が経過すると、
LED
は消灯する。
⑤光センサの出力が「暗い」と判断されている間は、
LED
は消灯し続ける。
⑥光センサの出力が「明るい」と判断されたときは、②に戻る。
(2)
設
計
書の
記
入
項目
数値
電源投入時の
LED
の点滅回数[回]
「暗い」と検出されたときの
LED
点灯時間[秒]
(3) main-mpc17-03.c
ファイルに仕様をコメントで記入する
main()
関数の中に、仕様の順序でコメント(
//
で始まる文)を記入していく。
void main(void)
//
メ
イン関数。この関数
か
ら動作開始
{
// 繰り返し用カウンタの宣言
// I/O ポートの初期化
// A/D 変換ポートの初期化
//
起
動時に LED を 3
回
点
滅
する
//
無
限ループ
…以
下
略…
※表 コメントとプログラム(関数)の対応
コメント
プログラム(関数)
// 制限時間を変数 time_limit に設定
uint32_t time_limit = 3;
// 繰り返し用カウンタの宣言
uint32_t i;
//
…
の処理を
3回
繰り返す
for (i = 0; i < 3; i++) {
…
}
// I/O
ポートの初期化
initIo();
// A/D
変換ポートの初期化
initAdc();
// LED
を消灯する。
ledOff();
// LED
を点灯する。
ledOn();
// LED
を点
滅
する。(点灯時は消灯
、
消灯時は点灯)
ledBlink();
//
「暗
い
」
と
判断
したら
//そうでなければ
if ( isDark() ) {
} else {
}
//タイマを time_limit 秒(変数の値で変わる)に設定し
て
計
時開始
startTimer( time_limit );
// タイマの設定時間が
経過
するまで
…
する
while ( T0Counter > 0 ) {
…
}
//
無
限ループ
while (1) {
…
}
// ちょっと待つ(10000 カウントの間)
wait(10000);
// ジワ
〜
っと LED を点
滅
する
pwmLed();
(4) C
言語でコーディング
これまでの説明を参考にして、コメントの内容を実行するための処理を書く。(コピー&ペー
ストでもよい)
void main(void)
//
メ
イン関数。この関数
か
ら動作開始
{
uint32_t i;// 繰り返し用カウンタの宣言
initIo();// I/O ポートの初期化
※これまでの説明では納得できない場合は、次のサンプルプログラムをお試しあれ。
6
(ファームウェアのヒント)マイコンで
LED
を点滅する基本的なプログラム(関数なし)
(1)
プログラムの編集
(a) MPLAB XIDE
の画面で、”
MPC17-03”-”Source Files”-”main-mpc17-03.c”
を開く。
(b) 7
行目以降に、次のコードをコピー&ペーストする
/*
* LED1 : PIN 7 (RA0) : 0-OFF, 1-ON
* ANALOG PORT : PIN 3 (AN3/RA4)
*
*/
#include <xc.h> // XC8
コンパイラ用のヘッダ(レジスタ名などのキーワードの定義を含む)
#include <stdint.h> // 整数型のビット数を明示して宣言するためのヘッダファイル
// PIC
マイコンの動作設定その1
// PIC micro controller Configuration 1
#pragma config FOSC = INTOSC // 内部クロック使用。
#pragma config WDTE = OFF // ウォッチドッグタイマなし。
#pragma config PWRTE = ON // 64ms
後にプログラム開始。
#pragma config MCLRE = OFF // 外部リセットなし。RA3 は入力ピン。
#pragma config CP = OFF // コード保護なし。
#pragma config CPD = OFF // データ保護なし。
#pragma config BOREN = ON // 電源電圧低下時のリセットあり。
#pragma config CLKOUTEN = OFF // クロック出力不可。
#pragma config IESO = OFF // 内部外部クロックなし。
#pragma config FCMEN = OFF // FCM
なし。
// 動作設定その2
// Configuration 2
#pragma config WRT = OFF // 書き込み保護なし。
#pragma config PLLEN = OFF // PLL
なし。
#pragma config STVREN = ON // スタックオーバー/アンダーフローでリセット。
#pragma config BORV = LO // 電源電圧低下監視閾値は Low モード
#pragma config LVP = OFF // 低電圧プログラムなし。
void main(void)
//
メ
イン関数。この関数
か
ら動作開始
{
uint32_t i; // LED 点
滅
間
隔
のカウンタ
// I/O ポートの初期化
OSCCON = 0b01110010; // 内部クロック 8MHz。
OPTION_REG = 0b00000000; // ウィークプルアップ使用可。
ANSELA = 0b00000000; // 全 I/O ポートがディジタルポート。
TRISA = 0b00001000; // 入力ポートは RA3, 他は出力ポート。
WPUA = 0b00001000; // RA3 ポートはウィークプルアップ。
PORTA = 0b00000000; // PORTA を 0 で初期化。
RA0 = 0; // LED を点灯する。
for (i = 0; i < 20000; i++);//ちょっと待つ
RA0 = 1; // LED を消灯する。
for (i = 0; i < 20000; i++);//ちょっと待つ
while(1);//
無
限ループ
(2)
ビルドと書き込み、動作確認
[Make and Program Device Main Project]
のアイコンをクリック
[CAUTION]
警告のダイアログボックスが表示されたら、
電源が正しく接続されていることを確認して、
[OK]
をクリック。
(標準では、
PICkit3
から電源供給をしないので、問題はない)
※書き込みの段階で、赤い字でエラーメッセージが出る場合、電源が接続
されていなかったり、電線の接続に不具合があったりすることが多い。
X IDE
の下側の
[Output]
に
[Programming/Verify complete]
と表示されたら、書き込み完了。
(3)
関連知識:
I/O
ポートとは
マイコンと外部の回路を接続する出入り口のこと
を
I/O
ポート(
Input / Output Port)
と呼ぶ(
port
とは
「港」の意味)。
出力ポートには、
LED
やブザーなどの回路がつな
がり、マイコンのプログラムで、それらに制御信号
を送る。
入力ポートには、光、音、温度や衝撃などを検出
するセンサや押しボタンスイッチが接続される。マ
イコンは、これらのセンサの情報を元に、プログラ
ムの流れを変える。
(4)
関連知識:出力ポートの働き
出力ポート(正確にはディジタル出力ポート)は、プログラ
ムによって、マイコンのピンに現れる電圧を0
[V]
または電源電
圧(
VDD[V]
)に変更できる。(図)
ワンチップマイコン
PIC12F1822
では、出力ポートには
RA0,
RA1, RA2, RA4, RA5
という名前がついている。このテキストの
回路では、
RA0
だけを使う。
出力ポート
RA0
に
LED
を接続し、点
灯及び消灯の制御をすることを考えてみ
る(図)。
出力ポート
RA0
の値(正確にはレジスタ
PORTA
レジスタの
RA0
ビット。さらに
正確にいうと、そのラッチレジスタ)を
1
にすれば、マイコンの
RA0
のピンには
電源電圧と同じ電圧が出力される。この
ため、LED
が点灯する。
逆に、RA0
の値を
0
にすれば、マイコ
ンの
RA0
ピンには
0V
が出力される。こ
の場合は、
LED
が消灯する。
マイコン
Output
出力ポート
Input
入力ポート
信号の流れ
信号の流れ
LED
ブザ
ー
モータ
センサ
スイッチ
VDD
[
V
]
1
0
RA0 出力ポート RA=1で VDD[V]を出力
RA=0で 0Vを出力
VDD
[
V
]
1
0
RA0 出力ポート RA=1で VDD[V]を出力
LEDが
光
る
VDD
[
V
]
1
0
RA0 出力ポート
RA=0で 0Vを出力
7
(ファームウェアのヒント)関数を利用した
LED
点滅プログラム
(1)
読みやすいソースプログラムに変更
前述のプログラムでは、コメント(
//
で始まる文は、改行までの間はコメントとなり、プログラム
としては無視される)がないと
LED
が点灯・消灯していることがわかりにくい。
RA0 = 0;
for (i = 0; i < 20000; i++);
RA0 = 1;
for (i = 0; i < 20000; i++);
そこで、次のようなプログラムに書き換える。
ledOn();
wait(20000);
ledOff(); //
wait(20000);
また、
IO
ポートの初期化は、どんなプログラムでも実行するため、関数にしてまとめておくと、
ソースプログラムの見通しがよくなる。別のマイコンでプログラムを再利用するときも楽になる。
initIO(); // I/O ポートの初期化
(2)
追加する関数の定義と使い方
C
言語の「関数」は、「LED
を点灯する」「LED
を消灯する」などの処理を、ledOn()や
ledOff()というわかりやすい名前で表すことができる。複数の文で書かれた処理を繰り返し使うと
きに便利である。関数を使うには、関数で処理すべき処理を書いておく部分(定義)と実際に使
う部分に分けられる。
(a) I/O
ポートの初期化関数の定義
と I/O ポートの設定定義
void initIo(void)
{
OSCCON = 0b01110010; // 内部クロック 8MHz。
OPTION_REG = 0b00000000; // ウィークプルアップ使用可。
ANSELA = 0b00000000; // 全 I/O ポートがディジタルポート。
TRISA = 0b00001000; // 入力ポートは RA3, 他は出力ポート。
WPUA = 0b00001000; // RA3 ポートはウィークプルアップ。
PORTA = 0b00000000; // PORTA を 0 で初期化。
}
// I/O
ポートの設定定義 (LED を接続するポートが変わった時はここを変更する)
#define PORT_LED RA0
#define TRISA_LED TRISA0
(b) LED
の点灯と消灯を制御する関数の定義
// LED
制御用関数
inline static void ledOn(void)
{ PORT_LED = 1;
}
inline static void ledOff(void)
{ PORT_LED = 0;
}
inline static void ledBlink(void) { PORT_LED ^= 1;
}
(c)
ちょっとの間、何もせずに待つ関数の定義
// ちょっと待つ処理を簡
単
に書
く
ための関数
void wait(volatile uint32_t i)
{
(d)
関数の使い方
動作を試すために、コピー&ペーストするプログラムは次のようになる。前のプログラムと同じ
ところは小さな文字になっている。どこが変わったか、比べてみよう。
/*
* LED1 : PIN 7 (RA0) : 0-OFF, 1-ON * ANALOG PORT : PIN 3 (AN3/RA4) *
*/
#include <xc.h> // XC8 コンパイラ用のヘッダ(レジスタ名などのキーワードの定義を含む) #include <stdint.h> // 整数型のビット数を明示して宣言するためのヘッダファイル // PIC マイコンの動作設定その1
// PIC micro controller Configuration 1
#pragma config FOSC = INTOSC // 内部クロック使用。 #pragma config WDTE = OFF // ウォッチドッグタイマなし。 #pragma config PWRTE = ON // 64ms 後にプログラム開始。 #pragma config MCLRE = OFF // 外部リセットなし。RA3 は入力ピン。 #pragma config CP = OFF // コード保護なし。
#pragma config CPD = OFF // データ保護なし。
#pragma config BOREN = ON // 電源電圧低下時のリセットあり。 #pragma config CLKOUTEN = OFF // クロック出力不可。
#pragma config IESO = OFF // 内部外部クロックなし。 #pragma config FCMEN = OFF // FCM なし。
// 動作設定その2 // Configuration 2
#pragma config WRT = OFF // 書き込み保護なし。 #pragma config PLLEN = OFF // PLL なし。
#pragma config STVREN = ON // スタックオーバー/アンダーフローでリセット。 #pragma config BORV = LO // 電源電圧低下監視閾値は Low モード
#pragma config LVP = OFF // 低電圧プログラムなし。
// I/O
ポートの初期化(定義)
void initIo(void)
{
OSCCON = 0b01110010; // 内部クロック 8MHz。
OPTION_REG = 0b00000000; // ウィークプルアップ使用可。
ANSELA = 0b00000000; // 全 I/O ポートがディジタルポート。
TRISA = 0b00001000; // 入力ポートは RA3, 他は出力ポート。
WPUA = 0b00001000; // RA3 ポートはウィークプルアップ。
PORTA = 0b00000000; // PORTA を 0 で初期化。
}
// I/O
ポートの設定定義 (LED を接続するポートが変わった時はここを変更する)
#define PORT_LED RA0
#define TRISA_LED TRISA0
// LED
制御用関数の定義
inline static void ledOn(void)
{ PORT_LED = 1;
}
inline static void ledOff(void) { PORT_LED = 0;
}
inline static void ledBlink(void)
{ PORT_LED ^= 1;
}
// ちょっと待つ処理を簡
単
に書
く
ための関数の定義
void wait(volatile uint32_t i)
{
while (i-- > 0);
}
void main(void)
// メイン関数。この関数から動作開始 {
initIo(); // I/O ポートの初期化
ledOn(); // LED
を点灯する。
wait(10000);//ちょっと待つ
ledOff(); // LED を消灯する。
wait(10000);//ちょっと待つ
while(1);//
無
限ループ
(3)
ビルドと書き込み、動作確認
[Make and Program Device Main Project]
のアイコンをクリック
[CAUTION]
警告のダイアログボックスが表示されたら、
電源が正しく接続さ
れていることを確認
して、
[OK]
をクリッ
ク。
(標準では、
PICkit3
から電源供給をしない
ので、問題はない)
※書き込みの段階で、赤い字でエラーメッ
セージが出る場合、電源が接続されていな
かったり、電線の接続に不具合があったり
することが多い。
X IDE
の下側の
[Output]
に
[Programming/Verify complete]
と表示されたら、書き込み完了。
8
(ファームウェアのヒント)決められた回数だけ
LED
を点滅するプログラム(for
文の活用)
(1) for
文による繰り返し
LED
を3回点滅させるプログラムを2種類書いてみた。どちらが読みやすいだろうか。
LED
を
10
回点滅させるプログラムに変更するときは、どちらが変更しやすいだろうか。
for
文なし
for
文あり
ledOn(); wait(10000);
ledOff(); wait(10000);
ledOn(); wait(10000);
ledOff(); wait(10000);
ledOn(); wait(10000);
ledOff(); wait(10000);
for ( i = 0; i < 3; i++ ) {
ledOn(); wait(10000);
ledOff(); wait(10000);
}
(2)
関連知識:
for
文
決められた条件を満たしている間、
{}
で囲まれた処理を繰り返すには、
for
文が使える。
決まった回数だけ繰り返す処理を書くときの基本的な書式は以下のとおり。
uint32_t i; // カウンタ変数 i の宣言
for ( i = 0; i < (繰り返し
回
数); i++ ) {
(繰り返す処理);
}
uint32_t
は、符号なし(
u
nsigned)
32
ビットの整数
(
int
eger)
型変数を表す。
i++
は、変数
i
が繰り返しのたびに1ずつ増加することを表す。
(3) for
文の使い方のサンプルプログラム
動作を試すために、コピー&ペーストするプログラムは次のようになる。前のプログラムと同じ
ところは小さな文字になっている。どこが変わったか、比べてみよう。
/*
* LED1 : PIN 7 (RA0) : 0-OFF, 1-ON * ANALOG PORT : PIN 3 (AN3/RA4) *
*/
#include <xc.h> // XC8 コンパイラ用のヘッダ(レジスタ名などのキーワードの定義を含む) #include <stdint.h> // 整数型のビット数を明示して宣言するためのヘッダファイル // PIC マイコンの動作設定その1
// PIC micro controller Configuration 1
#pragma config FOSC = INTOSC // 内部クロック使用。 #pragma config WDTE = OFF // ウォッチドッグタイマなし。 #pragma config PWRTE = ON // 64ms 後にプログラム開始。 #pragma config MCLRE = OFF // 外部リセットなし。RA3 は入力ピン。 #pragma config CP = OFF // コード保護なし。
#pragma config CPD = OFF // データ保護なし。
#pragma config BOREN = ON // 電源電圧低下時のリセットあり。 #pragma config CLKOUTEN = OFF // クロック出力不可。
#pragma config IESO = OFF // 内部外部クロックなし。 #pragma config FCMEN = OFF // FCM なし。
// 動作設定その2 // Configuration 2
#pragma config WRT = OFF // 書き込み保護なし。 #pragma config PLLEN = OFF // PLL なし。
#pragma config STVREN = ON // スタックオーバー/アンダーフローでリセット。 #pragma config BORV = LO // 電源電圧低下監視閾値は Low モード
#pragma config LVP = OFF // 低電圧プログラムなし。 // I/O ポートの初期化(定義)
void initIo(void) {
inline static void ledOff(void) { PORT_LED = 0; } inline static void ledBlink(void) { PORT_LED ^= 1; } // ちょっと待つ処理を簡単に書くための関数の定義
void wait(volatile uint32_t i) {
while (i-- > 0); }
void main(void)
// メイン関数。この関数から動作開始 {
uint32_t i; // 繰り返し
回
数のカウンタ変数
initIo(); // I/O ポートの初期化
//
起
動時に LED を 3
回
点
滅
する
for ( i = 0; i < 3; i++ ) {
ledOn(); wait(10000);// LED を点灯する。
ledOff(); wait(10000);// LED を消灯する。
}
while(1);//無限ループ return;
}
(4)
ビルドと書き込み、動作確認
[Make and Program Device Main Project]
のアイコンをクリック
[CAUTION]
警告のダイアログボックスが表示されたら、
電源が正しく接続さ
れていることを確認
して、
[OK]
をクリッ
ク。
(標準では、PICkit3
から電源供給をしない
ので、問題はない)
※書き込みの段階で、赤い字でエラーメッ
セージが出る場合、電源が接続されていな
かったり、電線の接続に不具合があったり
することが多い。
X IDE
の下側の
[Output]
に
[Programming/Verify complete]
と表示されたら、書き込み完了。
9
(ファームウェアのヒント)無限ループで、LED
を永久に繰り返し点滅するプログラム
(1) while
文による無限ループ
マイコンのファームウェアは、電源が投入されてから切られるまで、同じ動作を繰り返し行う
場合が多い。そこで、次のように書くと、無限ループとなり、
{}
で囲まれた処理を永久に繰り返
して実行する。
while (1) { //
無
限ループ
(繰り返す処理);
}
(2)
無限ループのサンプルプログラム
動作を試すために、コピー&ペーストするプログラムは次のようになる。前のプログラムと同じ
ところは小さな文字になっている。どこが変わったか、比べてみよう。
/*
* LED1 : PIN 7 (RA0) : 0-OFF, 1-ON * ANALOG PORT : PIN 3 (AN3/RA4) *
*/
#include <xc.h> // XC8 コンパイラ用のヘッダ(レジスタ名などのキーワードの定義を含む) #include <stdint.h> // 整数型のビット数を明示して宣言するためのヘッダファイル // PIC マイコンの動作設定その1
// PIC micro controller Configuration 1
#pragma config FOSC = INTOSC // 内部クロック使用。 #pragma config WDTE = OFF // ウォッチドッグタイマなし。 #pragma config PWRTE = ON // 64ms 後にプログラム開始。 #pragma config MCLRE = OFF // 外部リセットなし。RA3 は入力ピン。 #pragma config CP = OFF // コード保護なし。
#pragma config CPD = OFF // データ保護なし。
#pragma config BOREN = ON // 電源電圧低下時のリセットあり。 #pragma config CLKOUTEN = OFF // クロック出力不可。
#pragma config IESO = OFF // 内部外部クロックなし。 #pragma config FCMEN = OFF // FCM なし。
// 動作設定その2 // Configuration 2
#pragma config WRT = OFF // 書き込み保護なし。 #pragma config PLLEN = OFF // PLL なし。
#pragma config STVREN = ON // スタックオーバー/アンダーフローでリセット。 #pragma config BORV = LO // 電源電圧低下監視閾値は Low モード
#pragma config LVP = OFF // 低電圧プログラムなし。 // I/O ポートの初期化(定義)
void initIo(void) {
OSCCON = 0b01110010; // 内部クロック 8MHz。 OPTION_REG = 0b00000000; // ウィークプルアップ使用可。 ANSELA = 0b00000000; // 全 I/O ポートがディジタルポート。 TRISA = 0b00001000; // 入力ポートは RA3, 他は出力ポート。 WPUA = 0b00001000; // RA3 ポートはウィークプルアップ。 PORTA = 0b00000000; // PORTA を 0 で初期化。 }
// I/O ポートの設定定義 (LED を接続するポートが変わった時はここを変更する) #define PORT_LED RA0
#define TRISA_LED TRISA0 // LED 制御用関数の定義
inline static void ledOn(void) { PORT_LED = 1; } inline static void ledOff(void) { PORT_LED = 0; } inline static void ledBlink(void) { PORT_LED ^= 1; } // ちょっと待つ処理を簡単に書くための関数の定義
void wait(volatile uint32_t i) {
while (i-- > 0); }
void main(void)
// メイン関数。この関数から動作開始 {
initIo(); // I/O ポートの初期化
//
永久
に LED が点
滅
する
while ( 1 ) {
ledBlink(); wait(10000);// LED を点
滅
する。
(
前
に点灯のときは消灯
、前
に消灯のときは点灯)
}
10
(ファームウェアのヒント)光センサの出力で「暗い」「明るい」を判断する。
(1)
光センサで
LED
をスイッチする
本章で使用している光センサ(図)は、フォトトランジスタに抵抗を
接続したものだ。フォトトランジスタの出力電圧をアナログ入力ポート
AN3
に入力している。
フォトトランジスタの周囲が明るいときには、フォトトランジスタの
抵抗は非常に小さくなり、出力電圧はほぼ
0V
になる(図(a))。このた
め、ADRESH
レジスタには0またはそれに近い小さな値が入る。逆に、
暗いときには、フォトトランジスタの抵抗は大きくなり、出力電圧は高
くなる(図(b))。このとき、ADRESH
レジスタには、255
に近い大きな
値が入る。
(2)
関連知識:
A/D
変換とは
スイッチの
ON/OFF
のような信号は、基準値よ
りも電圧が高いときは
1、低いときは
0
の二つの値
しかとらないディジタル信号である。一方、光セ
ンサの出力は
0V
と電源電圧
VDD[V]
の間の値とな
り、アナログ信号である。このアナログ信号をマ
イコンに入力するには、アナログ入力ポートを使
用する。
アナログ入力ポートから入力されたアナログ信
号は、A/D
変換器(A/D converter) により、何段階
かの数値に変換される(図)。PIC12F1822
の場合
には、
ADRESH
レジスタに
0
から
255
までの数値として入力される(正確には、
ADRESL
レジ
スタにも、一部のビットが入る)。
本章では、ポート
RA1
をアナログ入力ポートとして使う。
これを設定するには、
TRISA
レジスタ
の
TRISA1
ビットを
1(
入力モード
)
にして
から、
ANSELA
レジスタの
ANSA1
ビットを
1
にする。
(3)
関連知識:アナログ入力ポートへの切り替え
本章では、ポート
RA4
をアナログ入力
ポートとして使う。
これを設定するには、TRISA
レジスタ
の
TRISA4
ビットを
1
にしてから、
ANSELA
レジスタの
ANSA4
ビットを
1
に
する。
本章では、この処理は初期化関数
initIO
と
initAdc8
の中で、他のポートの
設定と同時に行っている。
AN3 アナログ入力
ポート
ADRESH
レジスタ
0
から255
の値A/D
変換
器
VDD
[
V
]
アナログ 入力電圧
0
[
V
]
VDD/2[V]
1 2 3
ADRESH=255
ADRESH=128
ADRESH=0
VDD
[
V
]
フォト
トランジスタ
R=
100k
AN3 アナログ入力
ポート
(a)明るいとき
VDD
[
V
]
フォトトランジスタ
=
導通状態
R=
100k
AN3 アナログ入力
ポート
0V
ADRESH = 0
(b)
暗
いとき
VDD
[
V
]
フォトトランジスタ
=
高
い
抵抗
値
R=
100k
AN3 アナログ入力
ポート
0.8VDD
以
上
ADRESH > 220
RA4 アナログ
ポート
ANSELAレジスタ
ANSA0
ANSA1
ANSA2
-ANSA4
-1
RA4は アナログポート(AN3)と
なる ANSA4の値を
1にする
RA4 入力ポート
TRISAレジスタ
TRISA0
TRISA1
TRISA2
TRISA3
TRISA4
TRISA5
1
(4)
A/D
変換の関数の定義
(a) A/D
変換用
I/O
ポートの設定定義
#define PORT_ADC ANSA4
#define TRISA_ADC TRISA4
#define PORT_NO_ADC 3
(b) A/D
変換の初期化関数
// A/D
変換の初期化関数
void initAdc(void)
{
PORT_ADC = 1; // PORT_ADC で定義されたポートをアナログポートにする。
TRISA_ADC = 1; // A/D 変換
端子
を入力モードにする。
ADCON0 = 0b00000001
|
(PORT_NO_ADC << 2); //AD
変換を
有効
化。
ADCON1 = 0b01000000; // 0:(ADFM=0)
精度
10bit, 100:Fosc/4 ,0:Reserved, 00:AVDD=VREF
CM1CON0 = 0x00; //コンパレータを
無効
化。
}
(c) A/D
変換を実行する関数
uint16_t getAdc(void)
// A/D
変換した値を
得
る。
//
戻
り値
:
A/D 変換されたアナログ
信号
の大きさ(0
〜
1023)
{
uint16_t adcvalue;
//AD 変換
wait(10);
GO_nDONE = 1;
while (GO_nDONE);
adcvalue = ADRESH<<2
|
ADRESL>>6 ;
return adcvalue;
}
AD
変換された値は、上位8ビットが
ADRESH
に、下位2ビットが
ADRESL
の上位2ビッ
トに格納される。したがって、
10
ビットの
A/D
変換された値を得るには、次のようなシフト
演算をする。
ADRESH<<2
|
ADRESL>>6
なお、
<<2
は2ビット左(上位)シフト、
>>6
は6ビット右(下位)シフトの演算、
|
は論
理和
(OR)
演算である。
(d)
光センサの検出値を
A/D
変換した値から、「暗い」かどうかを判定する関数。
この関数は、暗いときには
-1
を返し、明るいときには
0
を返す。
int8_t isDark(void)
//
光
センサの出力
か
ら
、「暗
い
」か
どう
か判断
する。
//
戻
り値
:
「暗
い
」
と
判断
したとき -1
// それ
以
外 0
{
uint16_t photo; //
光
センサの出力値
int8_t result; //
戻
り値
uint16_t darkness_threshold = 500; //
「暗
い
」
と
判断
する閾値
photo = getAdc(); //
光
センサの出力を A/D 変換
if ( photo > darkness_threshold ) { //
「暗
い
」
とき
result = -1;
} else { //
「
明るい
」
とき
result = 0;
}
(5)
コピー&ペーストするサンプル・ソースプログラム
動作を試すために、コピー&ペーストするプログラムは次のようになる。前のプログラムと同じと
ころは小さな文字になっている。どこが変わったか、比べてみよう。
/*
* LED1 : PIN 7 (RA0) : 0-OFF, 1-ON * ANALOG PORT : PIN 3 (AN3/RA4) *
*/
#include <xc.h> // XC8 コンパイラ用のヘッダ(レジスタ名などのキーワードの定義を含む) #include <stdint.h> // 整数型のビット数を明示して宣言するためのヘッダファイル
// PIC マイコンの動作設定その1 // PIC micro controller Configuration 1
#pragma config FOSC = INTOSC // 内部クロック使用。 #pragma config WDTE = OFF // ウォッチドッグタイマなし。 #pragma config PWRTE = ON // 64ms 後にプログラム開始。 #pragma config MCLRE = OFF // 外部リセットなし。RA3 は入力ピン。 #pragma config CP = OFF // コード保護なし。
#pragma config CPD = OFF // データ保護なし。
#pragma config BOREN = ON // 電源電圧低下時のリセットあり。 #pragma config CLKOUTEN = OFF // クロック出力不可。
#pragma config IESO = OFF // 内部外部クロックなし。 #pragma config FCMEN = OFF // FCM なし。
// 動作設定その2 // Configuration 2
#pragma config WRT = OFF // 書き込み保護なし。 #pragma config PLLEN = OFF // PLL なし。
#pragma config STVREN = ON // スタックオーバー/アンダーフローでリセット。 #pragma config BORV = LO // 電源電圧低下監視閾値は Low モード
#pragma config LVP = OFF // 低電圧プログラムなし。 // I/O ポートの初期化
void initIo(void) {
OSCCON = 0b01110010; // 内部クロック 8MHz。 OPTION_REG = 0b00000000; // ウィークプルアップ使用可。 ANSELA = 0b00000000; // 全 I/O ポートがディジタルポート。 TRISA = 0b00001000; // 入力ポートは RA3, 他は出力ポート。 WPUA = 0b00001000; // RA3 ポートはウィークプルアップ。 PORTA = 0b00000000; // PORTA を 0 で初期化。 }
// I/O ポートの定義 (LED を接続するポートが変わった時はここを変更する) #define PORT_LED RA0
#define TRISA_LED TRISA0
#define PORT_ADC ANSA4
#define TRISA_ADC TRISA4
#define PORT_NO_ADC 3
// LED 制御用関数
inline static void ledOn(void) { PORT_LED = 1; } inline static void ledOff(void) { PORT_LED = 0; } inline static void ledBlink(void) { PORT_LED ^= 1; } // ちょっと待つ処理を簡単に書くための関数
void wait(volatile uint32_t i) {
while (i-- > 0); }
// A/D
変換初期化関数
void initAdc(void)
{
PORT_ADC = 1; // PORT_ADC で定義されたポートをアナログポートにする。
TRISA_ADC = 1; // A/D 変換
端子
を入力モードにする。
ADCON0 = 0b00000001
|
(PORT_NO_ADC << 2); //AD
変換を
有効
化。
ADCON1 = 0b01000000; // 0:(ADFM=0)
精度
10bit, 100:Fosc/4 ,0:Reserved, 00:AVDD=VREF
CM1CON0 = 0x00; //コンパレータを
無効
化。
}
// A/D
変換関数
uint16_t getAdc(void)
// A/D
変換した値を
得
る。
//
戻
り値
:
A/D 変換されたアナログ
信号
の大きさ(0
〜
1023)
{
uint16_t adcvalue;
//ADC
wait(10);
GO_nDONE = 1;
while (GO_nDONE);
adcvalue = ADRESH<<2
|
ADRESL>>6 ;
return adcvalue;
int8_t isDark(void)
//
光
センサの出力
か
ら
、「暗
い
」か
どう
か判断
する。
//
戻
り値
:
「暗
い
」
と
判断
したとき -1
// それ
以
外 0
{
uint16_t photo; //
光
センサの出力値
int8_t result; //
戻
り値
uint16_t darkness_threshold = 500; //
「暗
い
」
と
判断
する閾値
photo = getAdc(); //
光
センサの出力を A/D 変換
if ( photo > darkness_threshold ) { //
「暗
い
」
とき
result = -1;
} else { //
「
明るい
」
とき
result = 0;
}
return result;
}
void main(void)
// メイン関数。この関数から動作開始 {
initIo(); // I/O ポートの初期化
initAdc(); // A/D
変換ポートの初期化
while (1) {
if ( isDark() ) { // 明るさが閾値を超えたとき
ledOn(); // LED を点灯する。
} else { // そうでなければ
、
ledOff(); // LED を消灯する。
}
} return; }
(6)
ビルドと書き込み、動作確認
[Make and Program Device Main Project]
のアイコンをクリック
[CAUTION]
警告のダイアログボックスが表示されたら、
電源が正しく接続されていることを確認して、
[OK]
をクリック。
(標準では、
PICkit3
から電源供給をしないので、問題はない)
※書き込みの段階
で、赤い字でエラーメッセージが出る
場合、電源が接続されていなかったり、
電線の接続に不具合があったりするこ
とが多い。
X IDE
の下側の
[Output]
に
[Programming/Verify complete]
と表示
されたら、書き込み完了。
11
(ファームウェアのヒント)タイマで正確な時間だけ
LED
を点灯する
(1)
タイマ
(Timer0)
による時間の計測
LED
が点灯している時間を秒単位で正確に設定するためには、タイマ割り込みを使用する。
タイマ(TIMER0)を初期化する関数を以下に示す。この関数により、次の式で計算される
t
[s]経過するごとにタイマ割り込みが発生する。
t
=
1
f
osc4
×
256
×
256
=
1
8
×
10
64
×
256
×
256
=
0.032768
なお、fosc[Hz]は、マイコンのクロック周波数である。
void initTimer0(void)
{
TMR0 = 0x00; // Initialize TIMER0
TMR0CS = 0; //Internal instruction c
y
cle clock (FOSC/4)
PSA = 0; //Prescaler is assigned to the Timer0 module
PS2 = 1; PS1=1; PS0 = 1; // Prescaler Rate Select bits set 1:256
TMR0IE = 1; // Timer0 Intterupt Enable
PEIE = 1;
GIE =1;
}
タイマ割り込み処理の関数は、下記のように書く。このコードでは、大域変数
T0Counter
が、割
り込みの発生した回数だけ減少するため、
T0Counter
の値が
0
になったかどうかで、設定した秒数
が経過したかどうか判断できる。
volatile uint32_t T0Counter; // Timer0 overflow Counter
void interrupt isr(void)
//
割
り込みが
発生
する
ご
とに
、
この関数が呼ばれる。
{
if (TMR0IF) {
// Timer0 Interruption
TMR0IF = 0; // Clear Timer0 Interrupt Flag
TMR0 = 0; // Clear Timer1 counter
if (T0Counter > 0) T0Counter--;
}
}
設定した時間(秒数)が経過したかどうかを処理するために、次のような関数を用意する。
(a)
タイマに時間を設定し、計時を開始する関数
この関数で使われている
T0UNIT
(計算式は
1
t
=
1
0.032768
=30.518
≒31)は、1秒間に発生
する割り込みの回数を表している。
void startTimer(uint32_t time)
// Timer
を初期化して
計
時を開始する
//
引
数
:
time タイマを設定する時間(秒数)
{
uint32_t T0UNIT = 31; // Timer0Counter about 1sec
( 1 / (1 / ((Clock 8MHz / 4) / prescaler 256) * 256)initTimer0(); // TIMER0 の初期化
(b)
タイマに設定した時間だけ、
LED
を点灯するサンプルコード
設定した秒数の間だけ何もしないで待つには、次のコードを使う。
while( T0Counter );
また、設定した秒数の間、
LED
を点滅させるには、次のように書ける。
while ( T0Counter ) { blinkLed(); wait(5000) } ;
(2)
関連知識:タイマ
マイコンで、決まった時間だけ
LED
を点灯したり、決まった時間が経過すると
LED
が消灯す
るような動作をさせるには、タイマを使う。
図
Timer0
カウンタ (
8-bit
タイマ・カウンタ)で1秒を計時するまでの動き
タイマの動作は、上図のようになっている。
マイコンは「クロックパルス」という信号のタイミングに合わせてプログラムを動かしている。
クロックの周波数は、プログラムで設定できる。上のプログラムでは、クロックパルスの周波数
は
7.8kHz
で、
128μs
ごとに信号を発するように設定されている。
クロックパルス1つごとに、
TMR0
レジスタが1だけ増加する。クロックパルスが
256
個入る
と、
TMR0
レジスタの値は
0
に戻る。このとき、「タイマ割り込み」が発生する。
「タイマ割り込み」が検出されると、
TMR0IF
レジスタが
1
になり、割り込み処理関数が
interrupt InterFunction
が呼び出される。上のプログラムでは、タイマ割り込み処理関数では、
変数
T0count
を
1
増やす処理をしている。
タイマ割り込みが
31
回検出されると
T0count
は
31
になり、最初から
1
秒たっていることがわ
かる。
時間
t
クロック
TMR0
00000000 00000001 00000010 11111111 00000000TMR0IF
00000001
0 0 0 0 1
タイマ
割込み
11111111 00000000
0 1