PIC12F629 入門 NO.3 ( C 言語編)

[Previous] [Next] [Index]
CC5X FREE 使った C 言語プログラムによる LED の点滅プログラム
 最新の CC5X C コンパイラ MPLAB IDE の統合環境で使うことができる。コンパイルからシミュレーションまで MPASM によるアセンブラプログラムの時と同様の使い方ができる。特別大きなプログラムを組むわけでもないので CC5X FREE で十分開発ができる。そこで前回アセンブラで組んだ発光ダイオード点滅プログラムを C 言語で組んでみた。

629test.c (テキスト形式)

 特に PIC12F629 の特徴を生かしたプログラムではないが、アセンブラプログラムと比べることで C 言語による記述方法が参考になるのではないだろうか。初心者なので間違いがあるかもしれないが何とか動くプログラムを書いてみた。 LED が 0.5 秒間隔で点滅するだけのプログラムだが C 言語では正確なタイミングを得るのが少々面倒だ。このタイミング調整は MPLAB SIM で Stopwatch によるシミュレーションデバッグがとても便利。

 今回は内部発振回路を使ったプログラムとした。Configuration bit の記述では 2 種類の内部発振回路を使う記述方法がある。一つは外部にクロックを出力する記述 FOSC = 5 と、他は外部にクロックを出力しない記述の FOSC = 4 。

アセンブラでは

__CONFIG _BODEN_OFF & _MCLRE_OFF & _PWRTE_ON & _WDT_OFF & _INTRC_OSC_NOCLKOUT & _CPD_OFF & _CP_OFF
CC5Xでは

#pragma config BODEN = off, MCLR_off, PWRTE = on, WDTE = off, FOSC = 4, CP_off
となる。

 上記の記述はプログラム内で行わずライタで PIC への書き込み時に設定してもいい。これは内部発振周波数の校正値 OSCCAL value の設定も同じ。

C 言語では

#pragma cdata[0x3ff] = 0x349c     // この例では 9c が手持ち個体の発振周波数校正値
とすることでアセンブラの記述

org	0x3ff
retlw	0x349c
と同じになる。

 校正値を OSCCAL レジスタにセットするにはアセンブラの記述では call 0x3ff としたが、 C 言語での記述では DW 0x2000 + 0x3ff として W レジスタにいったん校正値を読み込んだ後、OSCCAL = W とすればいい。

 コンフィギュレーションビットの FOSC = 4 の設定を FOSC = 5 とすると内部発振周波数 4MHz の 1/4 である 1MHz のクロックが PIC の 3 番ピンから出力される。上記プログラムを PIC に書き込むときにライターソフトでオッシレータ設定を IntOSC CLKOUT として GP4 (3 番ピン)に出力される様子をオシロスコープで確かめてみた。

 今回のプログラムでステップ数を調整するために nop(); を使っている。これはアセンブラの nop と同じ。 CC5X では nop(); を 2 回記述する代わりに nop2(); が使える。これはアセンブラの goto $+1 と同じだ。プログラムコードが短くて済むのでコードエリアが節約できる。ところが今回のプログラムに使われている nop(); 二つを nop2(); に置き換えたところ 1 秒の点滅周期が変わってしまった。シミュレータで検証してみたら for ループの最後に記述された nop2(); が実行されていないことが判明した。生成されたアセンブラコードを確認したところやはりすぐ手前の命令で for ループの先頭に戻るような記述となっていた。これは CC5X のコンパイラバグと思われる。この件についてはバグレポートを開発元にメールしたところ、 3-4 週間のうちに訂正するとの返事がきた。

for(;;) {
    GPIO0 = 1;      // GP0 ON
    delay(244);     // 499.992 msec
    nop2();         // cc5x では goto $+1 を生成する
    nop2();         // nop(); を二つ記述するのと同じ
    nop2();
    GPIO0 = 0;      // GP0 OFF
    delay(244);
    nop2();         // プログラムコードが短くて済むので積極的に使った方がいいが
    nop();          // ここで以下 2 行の nop(); をまとめて nop2(); と記述すると
    nop();          // コンパイラバグのため最後の nop2(); が実行されない。
}

[Previous] [Next] [Index]
2003/08/28
2005/02/13 delay( )関数の引数にchar型を宣言しているにもかかわらず、引数に500(1F4h)を使っていた誤りを訂正