内蔵発振器を使うときはOSCCONの設定を忘れずに

mikroCを使ってC言語でLED点滅の簡単なプログラムを書いてみたところDelay_ms()が指定通りに動かないという問題が発生しました。


以下がソースコードです。

void main() { 
     ANSEL = 0x00;
     TRISA = 0x00;
     TRISB = 0x00;
     PORTA = 0x00;
     PORTB = 0x00;

     while(1) {
          PORTB = 0b00000001;
          Delay_ms(1000);
          PORTB = 0b00000000;
          Delay_ms(1000);
     }
}

プロジェクト作成の段階でちゃんと内蔵発振器で8MHzで動かすように設定したはずなのになぁ・・・と悩んでいました。
ビルドは問題なく通りますがこれで実行するとLEDは点滅せずずっと点灯したままになりました。
そこでいろいろと試し、"Delay_ms(1)"と指定してみたところ250ms程度の待機がかかることが分かりました。
クロック周波数の設定がうまくいってないのかと思い、いろいろ調べてみたら初歩的なミスでOSCCONの設定をしていなかったことに気付きました。


OSCCONは内蔵発振器の設定を行うレジスタで、4〜6bit目で周波数を決定します。今回は8MHzで動作させたかったので0x70を指定しました。
するとDelay_ms(1000);で正しく1秒待機するようになりました。


正しいプログラム

void main() { 
     OSCCON = 0x70;     // 追加
     ANSEL = 0x00;
     TRISA = 0x00;
     TRISB = 0x00;
     PORTA = 0x00;
     PORTB = 0x00;

     while(1) {
          PORTB = 0b00000001;
          Delay_ms(1000);
          PORTB = 0b00000000;
          Delay_ms(1000);
     }
}

これまでセラロックばかりで動作させていたためOSCCONの存在をすっかり忘れていました^^;


あともう1点気になったのですが、PIC16F88ではOSCCONはバンク1に存在します。アセンブラで記述する際にはバンクを切り替えて、戻してという処理が必要でしたがmikroCでは単純にOSCCONに代入しているだけでちゃんと動きました。
アセンブラソースコードを見ても特にバンクを切り替えているような記述はありませんでした。バンク切り替えってしなくてもいいのかなとちょっと不思議に思いました。

;HelloWorld.c,2 :: 		OSCCON = 0x70;
	MOVLW      112
	MOVWF      OSCCON+0