検索
連載

LEDの制御に時間の概念を取り入れるS08ではじめるマイコン制御プログラミング(4)(3/3 ページ)

少しずつ本格的になってきたマイコン制御。今回はタイマーと割り込みの考え方について、LEDの制御を例にしながら学ぼう。

PC用表示 関連情報
Share
Tweet
LINE
Hatena
前のページへ |       

ハードウェア・タイマー

 わざわざ、「ソフトウェア」タイマーというのですから、それならば「ハードウェア」タイマーもあるのではないかと考えた人。鋭いです。世の中の仕組みが良く分かった人ですね。

 実はQE128マイコンにもハードウェア・タイマーがあります。タイマーといっても時計ではありませんよ。正確な周期で数を数える、多機能なカウンタです。QE128マイコンでは8ビットのRTCと16ビットのTPMが搭載されています。今回は比較的使い方が簡単なRTCを用います。

 では、0.5秒毎にLEDの表示を更新するようにしましょう。リファレンス・マニュアルでRTC(Real-Time Counter)の章を見てみます。今回用いるのはRTCSCレジスタだけです(図3)。


RTCの設定
図3 RTCの設定

 RTCを使う前にRTCLKSとRTCPSの値を決めます。リファレンス・マニュアルに対応表(図4)が出ていますので、これを使うと便利です。0.5秒になる組み合わせを探せばいいのです。今回はRTCLKS=00b、RTCPS=1110bの組み合わせを使います。RTIEを1にすれば、割り込み許可になり、0.5秒毎にRTC割り込みがかかるようになります。

プリスケーラーの設定
図4 プリスケーラーの設定

 プログラムを見てみます。main関数では、LED表示部分も割り込み処理で行い、周辺I/Fや変数の初期化を行うだけになっています。カウンタ変数cも外部変数とし、割り込み処理内で操作できるようにしました。これまで使っていたソフトウェア・タイマーのwait関数も不要ですので取り除きます(リスト5)。

リスト5
リスト5

 mcu_init関数にRTC初期化の設定を追加します。RTCSC_RTIEで割り込みが開始され、0.5秒毎にRTC割り込みがかかることになります(リスト6)。

リスト6
リスト6

 0.5秒間隔で呼び出されるRTC割り込み処理int_timer関数を定義します。RTC割り込みのベクター・テーブルエントリー番号は24で、定義名は「VectorNumber_Vrtc」です。最初にRTIFに1を書き込み、ビット・クリアをしたあと、これまでmain関数で行っていたLED表示の更新をします。

リスト7
リスト7

 プログラムをビルド、デモボードにダウンロードして動作を確認してみてください。きちんと0.5秒間隔でLEDが更新します。多少、早くまたは遅く見えるかもしれませんが気のせいです……。

 すいません、白状します。実は今回RTCのクロック・ソースに使った1kHzのLPOはあまり精度がよくありません。条件によりますが、最大±30%程度の周期の誤差があります。ただ、使い方が簡単なので今回はこれで説明しました。精度が必要であれば、トリミングという処理がされたIRCLKを使うか、外部クロックERCLKを使うと精度を上げることが可能です。余裕があるようでしたら、リファレンス・マニュアルで調べてみてください。

 いかがでしたか? 今回説明した割り込みとタイマーの考え方は、制御プログラムではよく使われるものです。LEDのアップ/ダウン・カウンタのプログラムも、前回で作ったものと機能は変わりませんが、中身がだいぶアップグレードされてきたと実感してきているのではないでしょうか? 念のため、今回の最終版プログラムの全ソースリストを示します(リスト8)。

#include <hidef.h> /* for EnableInterrupts macro */
#include "derivative.h" /* include peripheral declarations */
void mcu_init(void);
void putbyte_led(unsigned char);
 
char step;
unsigned char c;
 
void main(void) {
 
  EnableInterrupts; /* enable interrupts */
  /* include your code here */
  mcu_init();
 
  c = 0;
  step = 0;
  for(;;) ; /* loop forever */
  /* please make sure that you never leave main */
}
 
void mcu_init(void){
  SOPT1_COPE = 0;
  PTCDD_PTCDD0 = 1;
  PTCDD_PTCDD1 = 1;
  PTCDD_PTCDD2 = 1;
  PTCDD_PTCDD3 = 1;
  PTCDD_PTCDD4 = 1;
  PTCDD_PTCDD5 = 1;
  PTEDD_PTEDD6 = 1;
  PTEDD_PTEDD7 = 1;
  KBI1PE_KBIPE2 = 1;
  PTAPE_PTAPE2 = 1;
  KBI1PE_KBIPE3 = 1;
  PTAPE_PTAPE3 = 1;
  KBI2PE_KBIPE2= 1;
  PTDPE_PTDPE2 = 1;
  KBI1SC_KBIE = 1;
  KBI2SC_KBIE = 1;
  RTCSC_RTCLKS = 0;
  RTCSC_RTCPS = 0xe;
  RTCSC_RTIE = 1;
  return ;
}
 
void putbyte_led(unsigned char c){
  c = ~c;
  PTED_PTED7 = c & 0x01;
  PTED_PTED6 = (c >> 1) & 0x01; 
  PTCD_PTCD5 = (c >> 2) & 0x01;
  PTCD_PTCD4 = (c >> 3) & 0x01;
  PTCD_PTCD3 = (c >> 4) & 0x01;
  PTCD_PTCD2 = (c >> 5) & 0x01;
  PTCD_PTCD1 = (c >> 6) & 0x01;
  PTCD_PTCD0 = (c >> 7) & 0x01;
  return ;
}
 
interrupt VectorNumber_Vkeyboard void chk_key_stat(void){
  if (KBI1SC_KBF) {
    KBI1SC_KBACK = 1;
    if (!PTAD_PTAD2) {
      step = 1;
    } else if (!PTAD_PTAD3) {
      step = -1;
    }
  }
  if (KBI2SC_KBF) {
    KBI2SC_KBACK = 1;
    if (!PTDD_PTDD2) {
      step = 0;
    }
  }
  return ; 
}
 
interrupt VectorNumber_Vrtc void int_timer(void){
  RTCSC_RTIF = 1;
  putbyte_led(c);
  c += step;
  return ; 
} 
リスト8



 次回はいよいよアナログ・データを扱いますよ。第5回をお楽しみに!(次回に続く)

Copyright © ITmedia, Inc. All Rights Reserved.

前のページへ |       
ページトップに戻る