PICでは、HI-TECH Cコンパイラをを使用した、C言語による開発を行う事ができます。
C言語で開発を行う場合、プログラム中で一定時間処理をスリープさせるにはどうしたら良いでしょうか?
HI-TECH Cの環境では、主に以下の4つの手法があります。
1. 空ループを回す 2. _delay()マクロを使用する 3. __delay_ms()マクロを使用する 4. __delay_us()マクロを使用する |
上記のうち2,3,4のマクロはHI-TECH Cがあらかじめ用意してくれているものです。
__delay_ms()と__delay_us()は先頭のアンダーバーが2つですが、_delay()は1つで有ることに注意してください。また、これらのマクロはhtc.hで定義されているため、ファイルの先頭に「#include <htc.h>」の記述が必要です。
それでは、各パターンの具体的な方法について確認していきます。
1. 空ループを回す
空ループを回すパターンは、MPASMのアセンブラでコードを書いた経験がある人にとってはわかりやすい方法です。ループ内の処理は、NOP()関数を呼んでおけばアセンブラのNOP命令が1つ実行できます。
#include <htc.h> ... int loop = 100; while( loop-- > 0 ) { NOP(); } |
上記のコードをコンパイルすると、このようなアセンブリになりました。
12: int loop = 100; 3C9 3064 MOVLW 0x64 3CA 1283 BCF 0x3, 0x5 3CB 008F MOVWF 0xf 3CC 3000 MOVLW 0 3CD 0090 MOVWF 0x10 13: while( loop-- > 0 ) { 3CE 2BD1 GOTO 0x3d1 3D1 30FF MOVLW 0xff 3D2 1283 BCF 0x3, 0x5 3D3 078F ADDWF 0xf, F 3D4 1803 BTFSC 0x3, 0 3D5 0A90 INCF 0x10, F 3D6 30FF MOVLW 0xff 3D7 0790 ADDWF 0x10, F 3D8 1F90 BTFSS 0x10, 0x7 3D9 2BDB GOTO 0x3db 3DA 2BDC GOTO 0x3dc 3DB 2BCF GOTO 0x3cf 14: NOP(); 3CF 0000 NOP 3D0 2BD1 GOTO 0x3d1 15: } |
空ループで対応する場合は、生成されるコードとクロック周波数から待たせたい時間を逆算する必要があるので、待機時間が決まっている場合は面倒になります。
2. _delay()マクロを使用する
_delay()マクロを使用する場合も、基本的には空ループと同様なのですが、引数を指定できる点が違います。例えば以下のコードで100命令分の待ちを作ることが出来るので、空ループの時に考慮が必要だったループ判定はNOPで待機時間の計算についての面倒さから開放されます。
void main( void ) { _delay(100); } |
_delay()関数は、大きすぎる値を指定すると以下のエラーが発生する場合があるので注意が必要です。
例えば、下記のコードをコンパイルすると…
void main( void ) { _delay(50462463); // ok _delay(50462464); // ng } |
下側の_delay()命令でエラーになります。
Error [1274] test\main.c; 11. delay exceeds maximum limit of 50462464 cycles |
エラーメッセージにも表示されていますが、引数に50462464以上の値(16進数だと0x301FF00)を指定するとコンパイルが出来ません。
マイコンでこれほどの時間をスリープさせる事はあまり無いかもしれませんが、もし多くの時間をスリープさせたい場合は以下のようにループにすれば対処できます。
// これはNG _delay(50462464); // これはOK int loop = 0; for ( loop = 0; loop < 1000; loop++ ) { _delay(50000); } |
また、_delay()マクロに指定する値には定数での指定が必要です。
変数を使用するとエラーになります。
int waitTime = 100; _delay(waitTime); |
上記のコードをコンパイルした時に出力されるエラーメッセージです。
Error [1387] test\main.c; 13. inline delay argument must be constantError [712] test\main.c; 13. can't generate code for this expression |
定数なら大丈夫なので、以下のようにdefineにしておけばエラーになりません。
#define WAIT_TIME 100 _delay(WAIT_TIME); |
3. __delay_ms()マクロを使用する
_delay()命令をさらに便利にしたものが__delay_ms()です。
これは時間指定(ミリ秒)でスリープさせる事が可能です。
__delay_ms(1000); // 1秒待機 |
時間指定で待たせる場合、PICは時間をクロックから算出します。
PICの動作は、範囲内であれば任意のクロックが入力可能なので、プログラムでクロック周波数を定義する必要があり、具体的には_XTAL_FREQをdefineします。値はhzで指定するので、例えば8Mhzの場合、以下の定義となります。
#define _XTAL_FREQ 8000000 |
もし、この定義を書き忘れると以下のエラーが出力されます。
Error [192] test\main.c; 22.32 undefined identifier "_XTAL_FREQ" |
また、_delay_ms()も内部的に_delay()をコールしているため、同様の制限を受けます。
手元の環境だと、_delay_ms()に対して10000(10秒)を与えた時はOKでしたが、100秒だとエラーになりました。__delay_ms()の場合も、多くの時間をスリープさせたい場合は以下のようにループにすれば対処できます。
// これはNG __delay_ms(100000); // これはOK int loop = 0; for ( loop = 0; loop < 10; loop++ ) { __delay_ms(10000); } |
4. __delay_us()マクロを使用する
__delay_us()は__delay_ms()と基本的には同じです。異なるのは、待ち時間の単位がマイクロ秒である点だけで、制限も同様です。
今回は、PICのプログラムをC言語で開発する際に、一定時間スリープさせる方法を紹介しました。
空ループによる手法もありますが、待ち時間が決まっている場合は、提供されている__delay_ms()や__delay_us()マクロを使用することで、簡単に処理を記述する事が出来ます。
関連記事
コメントを残す