このページは、わたしの備忘録として作成しました。
(2) LEDを点滅させる
LEDを点灯させることができましたので、つぎはLEDをぴかぴかと点滅させてみたいとおもいます。
LEDを点滅させるには、LEDをつけたり消したりすればいいわけですね。では、前回のプログラムの16行目以降をつぎのように変更して、LEDを消してまたLEDを点灯させるようにしてみましょう。
16 |
GP0_OFF |
MOVLW |
0x00 |
; Wにb'000000'を格納して、それを |
||||
17 |
MOVWF |
0x06 |
; GPIOレジスタ(0x06番地)に書き込んで消灯させる |
|||||
18 |
GOTO |
GP0_ON |
; LEDをふたたび点灯させる | |||||
18 |
END |
; プログラムはここで終了 |
ダウンロード
12F509_LED_BLINK_GP0_1.asm
でも、これだと、LEDが点滅する間隔が数マイクロ秒しかないので、人間の目にはLEDがずっと点灯したままのようにみえます。家庭で照明につかわれているる蛍光灯も、高速で点滅していますが、人間の目にはずっと点灯しているようにみえます。映画やアニメ、そしてパソコンの画面もこの人間の網膜の残像を利用したものですね。LEDが点滅していることが人間の目にもわかるようにするには、LEDが点灯している時間と消灯している時間をおおくとる必要がありそうです。
では、LEDが人間の目でみて点滅していると感じるようにするためには、点灯と消灯の時間をどれぐらいに設定すればいいのでしょうか。LEDの色や明るさ、周囲の明るさ、個人差などがありますので、厳密ではありませんが、実験ボードで使用している3ミリ径の赤色LED(800mcd)が光るのを自分の目でみて確認してみました。点灯と消灯の時間が1ミリ秒だと、LEDは点灯したままでした。10ミリ秒だと、まだLEDは点灯したままでした。15ミリ秒前後だと、LEDがちらつきだしたのがわかりました。20ミリ秒にすると、LEDが点滅していると感じられるようになりましたが、点滅が速すぎて、いらいらしてきます。それで、今回は200ミリ秒の間隔でLEDを点滅させてみることにしました。
遅延させる方法
PICで遅延をつくる方法は、PICに関する解説書やおおくのウェブサイトでとりあげられていますが、なかなか複雑で、理解しにくいものです。遅延のテクニックについては、マイクロチップ社の『Tips ‘n Tricks』で簡潔に紹介されています(『Tips ‘n Tricks』の最新版は、マイクロチップ社のサイトで検索して探してください)。
NOP ; NOP(No OPeration)は、何もしない命令
NOP ; NOP2個で2命令サイクル
GOTO $+1 ; 1命令で2サイクル。$は現在のプログラムカウンタの値。
CALL Rtrn ; 1命令で4サイクル。
-----------------------------
Rtrn RETURN
これらのほかに、DECFSZ(DECrement File, Skip if Zero) や INCFSZ (INCrement File, Skip if Zero)などの命令を組み合わせて遅延時間をつくっていきます。1命令につきメモリロケーションを1つ使いますので、NOP だけで長い遅延時間をつくると、メモリサイズの小さいPIC12F509ではすぐにいっぱいになってしまいます。ですから、NOPと分岐命令のCALL や GOTO とDECFSZ や INCFSZ(今回は使用しません) を使ったサブルーチンをつくって遅延させます。内側のループカウンタがゼロになったら、GOTO命令はスキップされて次の番地の命令、すなわち外側のループカウンタが実行されます。
下記は、ミリ秒単位で遅延時間をつくるサブルーチンです。数学の苦手な私は、このルーチンをつくるのになんと2週間もかかってしまいました。しかし、苦労しただけあって、正確に1000命令サイクルの遅延をメインルーチンの変数 i で指定した回数だけ実行します(注:このルーチンをよびだすための命令などが数サイクルくわわります)。変数のレジスタは8ビットですので、1〜256の値を指定します。0を指定すると、i は256になります。257以上を指定すると、9ビット目は無視され、下位8ビットが有効になりますので、i は1になります。4MHzでPICを動かした場合は、このサブルーチンを1回よびだすことで1ミリ秒から256ミリ秒まで遅延させることができるというわけです。このサブルーチンは、インクルードファイルにして、他のプログラムでも流用できるようにしました。プログラム本体から i に200をセットし、LEDが点灯してからの保持時間、消灯してからの保持時間として DELAYms をよびだせば、0.2秒間隔でLEDは点滅するようになるはずです。なお、12ビットコアのPICの命令セットには RETURN はありませんので、RETLW 0 で代用します(RETURN と記述しても、MPASM は自動的に RETLW 0 に置き換えてくれます)。
1 |
DELAYms: |
; i x1000命令サイクル、i はメインルーチンで指定 |
||||||
2 |
CLRW |
; W をクリアする |
||||||
3 |
ADDWF |
i,W |
; ループカウンタ j の値を i にする | |||||
4 |
MOVWF |
j | ||||||
5 |
DELAY1k: |
; 1000命令サイクルの遅延ループ |
||||||
6 |
MOVLW |
0xF9 |
; ループカウンタ k に249(0xF9)をセットする |
|||||
7 |
MOVWF |
k |
||||||
8 |
LOOP1k |
|||||||
9 |
NOP |
|||||||
10 |
DECFSZ |
k,f |
||||||
11 |
GOTO |
LOOP1k |
; 2+4x249-1 |
|||||
12 |
DECFSZ |
j,f |
||||||
13 |
GOTO |
DELAY1k |
; 3xj+997xj=1,000xj |
|||||
14 |
RETLW |
0 |
; RETURNの代用 |
GP0につないだLEDを0.2秒間隔で点滅させるプログラムの本体です。
1 |
LIST |
P = 12F509 |
; プロセッサの種類を指定 |
|||||
2 |
#INCLUDE |
<P12F509.INC> |
; プロセッサのインクルードファイルを指定 |
|||||
3 |
__CONFIG |
0x0A |
; このように記述することもできます | |||||
4 |
; 外部リセットを使用しない |
|||||||
5 |
; コードプロテクトしない |
|||||||
6 |
; ウォッチドッグタイマを使用しない |
|||||||
7 |
; 内蔵クロックを使用する |
|||||||
8
|
i |
EQU |
0x07 |
; ループカウンタの変数の定義 |
||||
9
|
j |
EQU |
0x08 |
; ループカウンタの変数の定義 |
||||
10
|
k |
EQU |
0x09 |
; ループカウンタの変数の定義 |
||||
11 |
ORG |
0x000 |
; プログラム実行開始番地 |
|||||
12 |
MOVWF |
OSCCAL |
; OSCCALレジスタを更新 |
|||||
13 |
MOVLW |
0x08 |
; GP3を入力ポート、他は出力ポートに設定 |
|||||
14 |
TRIS |
0x06 |
; f=6 |
|||||
15 |
MOVLW |
0xDF |
; T0CSはゼロ、GP2を出力ポートに |
|||||
16 |
OPTION |
; OPTIONレジスタに書き込む |
||||||
17 |
MOVLW |
0xC8 |
; 200ミリ秒の遅延時間を設定 |
|||||
18 |
MOVWF |
i |
; カウンタの初期値は200(0xC8) |
|||||
19 |
GP0_ON |
MOVLW |
0x01 |
; Wにb'000001'を格納して、それを |
||||
20 |
MOVWF |
GPIO |
; GPIOレジスタ(0x06番地)に書き込む |
|||||
21 |
CALL |
DELAYms |
; LED点灯状態を200ミリ秒保持する |
|||||
22 |
GP0_OFF |
MOVLW |
0x00 |
; Wにb'000000'を格納して、それを |
||||
23 |
MOVWF |
GPIO |
; GPIOレジスタ(0x06番地)に書き込む |
|||||
24 |
CALL |
DELAYms |
; LED消灯状態を200ミリ秒保持する |
|||||
25 |
GOTO |
GP0_ON |
; これを電源が切られるまでくりかえす |
|||||
26 |
INCLUDE |
delayms.inc |
; 遅延ルーチンのインクルードファイルを指定 |
|||||
27 |
END |
; プログラムはここで終了 |
ダウンロード
12F509_LED_BLINK_GP0_2.asm
delayms.inc
このプログラムを実行させてみると、LEDが期待通りの間隔で点滅してくれました。なお、i の値を10〜20の間で変化させると、このページのはじめに網膜の残像について紹介したように、何ミリ秒間隔だとLEDの点滅が目で見てわかるようになるのか、ためすことができます(ひょっとすると、1ミリ秒でもわかる人がいるかも……。注:LEDの光を長時間みつめてはいけません。目を痛めます)。
LEDの点滅
![]() |
応用
おさらいをかねて、『ナイトライダー』の「ナイト2000」についているフラッシャーもどきをつくりました。
GP0、GP1、GP2、GP4、GP5にLEDをつなぎ、そのLEDを一列に配置して、順番に点灯、消灯させていきます。一度にひとつのLEDしか点灯しませんので、各LEDのカソードがわをたばねて、そこにLEDの電流制限抵抗を1本つけるだけでだいじょうぶです。
「ナイト2000」もどき
![]() |
ダウンロード
12F509_LED_BLINK_GP0_2.asm
delayms.inc
PIC10F206を使った「ナイト2000」もどきもつくってみました。ここです(2005年7月3日)
2005年7月3日更新
2005年2月20日作成