目次>5章 第2ステップ(色々な実験)>(1)LEDを点滅させる

LEDを点滅させる

更新日2005.6.25

PIC16F84Aに緑と赤のLEDを接続し、0.5秒毎に点滅させるプログラムを作ります。

実験回路
実験回路は以下の通りです。3章.第1ステップ(動かしてみる)で作成したものと同じです。

PORTBのRB0とRB1に緑と赤のLEDを接続していますので、RB0とRB1をオン/オフさせれば2つのLEDを点滅できます。

点滅させるには
0.5秒毎にLEDをオン/オフさせるプログラムは、以下のような処理をすれば良い事になります。

それでは、順にプログラムを作って行きましょう。

PICを初期化する
今回のプログラムでは、PORTBのRB0,RB1を出力モードに設定するだけです。また、RB2〜7には何も接続しませんので、PORTB全てを出力モードに設定しましょう。
(使わないポートは入力モードにしておくのが安全ですが、今回は簡易的このようにします)

PORTBの入出力モード設定は、TRISBレジスタで指定します。(PICの仕組み参照)
PORTB全てのピンを出力に設定しますので、TRISBの全ビットをオフ(0)にします。
この処理は以下のようになります。

BSFSTATUS,RP0; ファイルレジスタSTATUSのRP0(ビット5)をセット(1)する → バンク1
CLRFTRISB; ファイルレジスタTRISBをクリア(0) → PORTBは全て出力
BCFSTATUS,RP0; STATUSのRP0をクリア(0) → バンク0に戻しておく

RB0,RB1をオン/オフする
これは、3章で作ったプログラムと同じです。

RB0,RB1をオンにするには、次のようになります。

MOVLW03h
MOVWFPORTB; RB0,RB1をオンにする
この処理は、03hをWレジスタに格納し、Wレジスタの内容(03h)をPORTBに転送します。
03hは16進表現であり、ビット表現(2進数)では
00000011となります。
これで、ビット0と1(RB0と1)がオンになり、他のビットはオフになります。
(2進数と16進数については、7章(9)2進数と16進数(と10進数)を参照下さい。)

逆に、RB0,RB1をオフ(と言うかPORTBの全ビットをオフ)にするには、

CLRFPORTB; RB0,RB1をオフにする
となります。

0.5秒待つ(考え方)
簡単そうですが、少し厄介です。(分かってしまえば簡単ですが・・・)

PIC16F84Aで一定時間待つには以下の2通りの方法があります。
(1)命令を一定回数繰り返し実行する事で時間を稼ぐ
(2)TMR0割込みを使う
ここでは、(1)の方法を使用します。TMR0割込については、5章(5),(6)で実験します。


PIC16F84Aには、35個の命令があります。そして全ての命令は4クロックで実行されます。
(4クロックを1サイクルと呼びます)
クロックは、OSC1/2ピンに接続するレゾネータ(発振子)の周波数により決定されます。
今回は、10MHzのレゾネータを使用していますので、1秒当たりのクロック数は、  

10×106 = 10,000,000
となります。

従って、1クロックの時間は  

1秒/10,000,000 = 0.1μS(マイクロ秒)
となります。

1つの命令は、4クロック(1サイクル)で実行されますので、1命令を実行するのに  

0.4μS
かかります。

以上の事から、0.5秒待つには、  

0.5S/0.4μS = 1,250,000命令(サイクル)
実行すればよい事になります。

時間とクロックの関係を図で表すと次のようになります。

ここで留意点が2つあります。

@PICの命令には、8クロック(2サイクル)かかるものがある(→PICの命令一覧を参照)
A簡単に実装できるループ回数は256回が上限(→20×250回×250回のように実現する)

0.5秒待つ(プログラムを作る)
それではプログラムを作って見ましょう。

考え方でも説明した通り、1回で0.5秒待つ事はできませんので、3つのサブルーチンを作る事にします。
3つのサブルーチンの概要は以下のようになります。

0.5S待つサブルーチン
 100mS待つサブルーチンを5回呼び出す

100mS待つサブルーチン
 0.4mS待つサブルーチンを250回呼び出す

0.4mS待つサブルーチン
 命令を0.4mS分実行する(1サイクル0.4μS×1000サイクル)

それぞれのプログラムは次のようになりました。
「サイクル」は、1命令実行にかかるサイクル数(1サイクルは4クロック)です。CALL命令でサブルーチンを呼び出している所は、サブルーチンが消費するサイクル数を加算しています。
「小計」は、サブルーチンが1回呼ばれた時に、各命令が実行されるサイクル数の合計です。
各サブルーチンの最後の「合計」は、サブルーチンが1回呼び出された時に実行されるサイクル数の合計です。
尚、ループ回数は上の概要と少し異なります。

; << 0.4mS待つサブルーチン >>
T04mSサイクル小計コメント
MOVLW0F9h11F9h=249(ループ回数として249をセット)
MOVWFGPR_111
T04LPNOP11×249=249
DECFSZGPR_1,F1(2)1×248+2=250
GOTOT04LP22×248=496
RETURN22
合計999サイクル(0.3996mS)

; << 100mS待つサブルーチン >>
T100mSサイクル小計コメント
MOVLW0F9h11F9h=249(ループ回数として249をセット)
MOVWFGPR_211
T100LPCALLT04mS2+999(2+999)×249=249,249
DECFSZGPR_2,F1(2)1×248+2=250
GOTOT100LP22×248=496
RETURN22
合計249,999サイクル(99.999mS)

; << 0.5S待つサブルーチン >>
T05Sサイクル小計コメント
MOVLW05h11ループ回数5をセット
MOVWFGPR_311
T05LPCALLT100mS2+249,999(2+249,998)×5=1,249,995
DECFSZGPR_3,F1(2)1×4+2=6
GOTOT05LP22×4=8
RETURN22
合計1,250,013サイクル(500.005mS)

これで、0.5秒待つサブルーチンができました。使い方は次の通りです。

CALLT05S; 0.5秒待つ

プログラム全体
以上でプログラムのパーツができました。それではプログラムとして完成させましょう。

これをメモ帳などのテキストエディタに取り込んで、LED2.ASMという名で保存し、MPLABでアセンブル&PICライタでPICに書き込んで動かしてみて下さい。
MPLAB,PICライタの使い方は、「3章.第1ステップ(動かしてみる) 」を参照して下さい。

緑と赤のLEDが同時に点滅すれば成功です。0.5秒毎に点滅させていますので、周期は1秒です。

なお、ソースの先頭にいくつか説明していない命令があります。
これは、最初にこのように記述して下さい。(説明は、4章(2)PICの命令とアセンブラ命令の「アセンブラ命令」を参照して下さい。)

LISTP=PIC16F84A; LIST宣言で、使用するPICをPIC16F84Aと定義する
INCLUDEP16F84A.INC; 設定ファイルp16f84a.incを読み込む
__CONFIG_HS_OSC & _WDT_OFF & _PWRTE_ON & _CP_OFF

GPR_1EQU0Ch; GPRの1バイト目にGPR_1と言う名前を付ける
GPR_2EQU0Dh; GPRの2バイト目にGPR_2と言う名前を付ける
GPR_3EQU0Eh; GPRの3バイト目にGPR_3と言う名前を付ける