マイコン演習

研修の最終日にあった課題(を更にいじってあそんだプログラム)を通して学んだことの備忘録

vect.c

/* vect.c : ベクタテーブル設定 */
#pragma section _VECT (コンパイル固有のプリプロセス宣言は#pragmaから始まる。コンパイラマニュアルを見ること。この場合はセクションをC_VECTに指定している。)
(externは別のファイルに書かれたstaticではないグローバル関数を利用するために宣言する。)
extern void main(void);
extern void tmrw_irq(void);
extern void tmrv_irq(void);

(定数を関数に見せかけるなぞの書きまわし。どのベクター番号に割り込み関数を記述するかはハードウェアマニュアルを見る。)
const void (*const vec_table[])(void)={
  main,0,0,0,0,0,0,0,0,0, /* 0- 9 */
  0,0,0,0,0,0,0,0,0,0, /* 10-19 14:irq0*/
  0,tmrw_irq,tmrv_irq,0,0,0 /* 20-25 21:tw*/
}

IRQ0_test.c

/******************************************* 
    トルコ行進曲 for H8/3664F  
    C言語による割り込み処理    
    2008.5.16 Programed by Y.Masaki  
*******************************************/ 

#include /* 割り込みマスク設定用 */
#include "iodefine.h" /* ヘッダファイル取込 */
(コンパイル固有のプリプロセス宣言は#pragmaから始まる。割り込み関数であるこをここで指示する。指示することで、関数終了時に呼び出される命令がRTS(通常関数)ではなくRTE(割込関数)になる。
#pragma interrupt (tmrw_irq) /* 割込処理関数名宣言 */
#pragma interrupt (tmrv_irq) /* 割込処理関数名宣言 */


void init(void);/* イニシャライズ */

static int flg;/* 処理分岐フラグ */
static const int motordata = {0x01,0x02,0x04,0x08};/* モーター回転用 */

static long timecnt;/* 音楽のテンポ設定用 */
static int scorectrl;/* シーケンス位置の保持 */

static long keepcnt;/* 長押しカウンタ */
static long resetcnt;/* アイドル時間カウンタ */
static long i;/* チャタリング回避用 */


static int do_flag;/* タイマW用イベントフラグ */
static int do_flag2;/* タイマV用イベントフラグ */
static int k;

/* 音階定義 */
static const double onkaidata =
{
  0,

  1600, /* C1 *//* 1 */
  1510.198128, /* C1# *//* 2 */
  1425.435932, /* D1 *//* 3 */
  1345.432029, /* D1# *//* 4 */
  1269.919151, /* E1 *//* 5 */
  1198.644714, /* F1 *//* 6 */
  1131.370791, /* F1# *//* 7 */
  1067.870448, /* G1 *//* 8 */
  1007.937508, /* G1# *//* 9 */
  951.3667789, /* A1 *//* 10 */
  897.9706374, /* A1# *//* 11 */
  847.5698583, /* B1 *//* 12 */

  800, /* C2 *//* 13 */
  755.0990638, /* C2# *//* 14 */
  712.7179662, /* D2 *//* 15 */
  672.7160145, /* D2# *//* 16 */
  634.9595754, /* E2 *//* 17 */
  599.3223571, /* F2 *//* 18 */
  565.6853954, /* F2# *//* 19 */
  533.9352239, /* G2 *//* 20 */
  503.9687539, /* G2# *//* 21 */
  475.6833895, /* A2 *//* 22 */
  448.9853187, /* A2# *//* 23 */
  423.7849291, /* B2 *//* 24 */

  400, /* C3 *//* 25 */
  377.5495319, /* C3# *//* 26 */
  356.3589831, /* D3 *//* 27 */
  336.3580072, /* D3# *//* 28 */
  317.4797877, /* E3 *//* 29 */
  299.6611786, /* F3 *//* 30 */
  282.8426977, /* F3# *//* 31 */
  266.967612, /* G3 *//* 32 */
  251.984377, /* G3# *//* 33 */
  237.8416947, /* A3 *//* 34 */
  224.4926593, /* A3# *//* 35 */
  211.8924646, /* B3 *//* 36 */

  200, /* C4 *//* 37 */

};

/* 楽譜 */

static const int score1[] =

{
  26,27,26,24,
  22,24,22,21,19,22,21,19,
  18,19,21,18,14,16,18,14,
  19,18,19,21,22,21,22,24,
  26,25,26,25,

  26,27,26,24,
  22,24,22,21,19,22,21,19,
  18,19,21,18,14,16,17,14,
  16,17,19,16,13,14,16,13,
  14,14,14,14,

  17,15,14,12,
  10,12,14,15,17,19,21,22,
  22,21,19,17,17,15,14,12,
  10,12,14,15,17,19,21,22,
  23,23,24,24,

  17,15,14,12,
  10,12,14,15,17,19,21,22,
  22,21,19,17,17,15,14,12,
  14,17,10,14,12,15, 9,12,
  10,10,10,10,

  26,27,26,24,
  22,24,22,21,19,22,21,19,
  18,19,21,18,14,16,18,14,
  19,18,19,21,22,21,22,24,
  26,25,26,25,

  26,25,26,23,
  27,26,27,26,27,26,27,26,
  27,26,24,22,21,22,24,21,
  22,24,26,19,18,19,21,18,
  19,19,19,19

};

void main(void)
{
  long flag1;
  long flag2;
  long x;
  int motor; (intは処理系依存でlong[4バイト]、short[2バイト]どちらかになる。longとかshort使うほうが移植性が高いということだ。) 
  int j;


  init(); /* イニシャライズ */

  flag1 = 0; 
  flag2 = 0;
  (なぜlong flag1 = 0;と書かないかというと、long flag1;はRAMの処理であり、flag1=0はROMの処理なので1行で混在するから。実際はコンパイルオプションでそういう問題を回避することが多い。)
  scorectrl = 0;
  while(1){ (OS管理でない場合にメイン関数を終了させると暴走するので必ず無限ループにしよう!Windowsのプログラムではやっちゃいけないことのひとつだけど、この場合はやらないといけない。)
    (右方向動作中に右端に、左方向動作中に左端に到達するとモータの回転を反転させる処理。)
    if*1 ){ (配列の要素数を求める定番の書き方)        
        scorectrl = 0;
      }
      do_flag2 = 0;
    }
  }
}

/* タイマイニシャライズ */
void init(void)
{
  (こういう記述がハードウェアマニュアルを見て自分で書けるようになることが今回の研修の大きな目的のひとつである。)

  IO.PCR8 = 0x0F; /* モータを出力モードとする */
  IO.PCR5 = 0x00; /* センサを入力モードとする */
  IO.PCR7 = 0x00; /* スイッチを入力モードとする */

  flg = 1;

  set_imask_ccr(1); /*割り込み処理中の割り込みは割り込みキューに追加しない*/

  TW.TCRW.BIT.CKS = 3; /* 1/8 分周クロック*/
  TW.TCRW.BIT.CCLR = 1; /* コンペアマッチ時にカウンタリセットする */
  TW.GRA = 5000; /* コンペアポイントの設定 */
  TW.TIERW.BIT.IMIEA = 1; /* コンペアマッチによる割込み許可 */
  TW.TMRW.BIT.CTS = 1; /* TW count start */

  TV.TCRV0.BIT.CKS = 3; /* 1/128 分周クロック*/
  TV.TCRV1.BIT.ICKS = 1; /* 1/128 分周クロック*/
  TV.TCRV0.BIT.CCLR = 1; /* コンペアマッチ時にカウンタリセットする */
  TV.TCORA = 1000; /* コンペアポイントの設定 */
  TV.TCRV0.BIT.CMIEA = 1; /* コンペアマッチによる割込み許可 */
  TV.TCRV0.BIT.CMIEA = 0;にすれば割り込みは発生しないのでTW.GRA = 5000;の固定値でモーターが動く。音楽を奏でるように可変にしている場合は周期が早すぎてモーターはほとんど動かないです。課題を改造している形なのでプログラムが混在している形になっています。)
  TV.TCRV1.BIT.TRGE = 0;
  TV.TCRV1.BIT.TVEG = 0;

  set_imask_ccr(0); /*割り込み許可*/

  timecnt = 0;
  keepcnt = 0;
  resetcnt = 0;

}


/* 割り込み処理ルーチン */
(割り込みは内容にもよるが、割り込みルーチン内部は極力小さくすること。今回も基本的にフラグを立てるだけにして、本処理はメインルーチンに記述している。)

void tmrw_irq (void)
{
  int dummy;
  do_flag = 1;
  keepcnt++;/* 長押し確認処理 */

  dummy = TW.TSRW.BIT.IMFA; /* ダミーリード */
  /* ビット処理はリードが暗黙に含まれているので実は不要 */
  /* バイト処理する場合は必要な行 */
  TW.TSRW.BIT.IMFA = 0; /* タイマのカウンタリセット */
  set_imask_ccr(0); /* 割込みマスクレベルリセット */

}

void tmrv_irq (void)
{
  int dummy;
  timecnt ++;
  if(timecnt > 50){
    do_flag2 = 1;
    timecnt = 0;
  }
  dummy = TV.TCSRV.BIT.CMFA; /* ダミーリード */
  /* ビット処理はリードが暗黙に含まれているので実は不要 */
  /* バイト処理する場合は必要な行 */
  TV.TCSRV.BIT.CMFA = 0; /* タイマのカウンタリセット */
}

*1:IO.PDR5.BYTE & 0x07) == 1 && flg == 2){       flg = 1;     }else if((IO.PDR5.BYTE & 0x07) == 4 && flg == 1){       flg = 2;     }     (スイッチ1、スイッチ2の押下されたかどうかの判定。)     if(IO.PDR7.BIT.B4 == 1){       flag2 += 1;       resetcnt = 0;     }     if(IO.PDR7.BIT.B6 == 1){       flag1 += 1;       resetcnt = 0;     }     (スイッチ1か2長押しならモータは停止。)     if(keepcnt > 5000){       flag1 = 1000;       flag2 = 1000;       flg = 0;     }     if(IO.PDR7.BIT.B4 == 0 && IO.PDR7.BIT.B6 == 0){       resetcnt++;       keepcnt = 0; /* 長押しカウント解除 */     }     if( resetcnt > 100){       if (flag1 > 10 && flag2 == 0){         flg = 2;(スイッチ1短押しならモータは右方向回転。)       }       else if (flag1 == 0 && flag2 > 10){         flg = 1;(スイッチ2短押しならモータは左方向回転。)       }       else if (flag1 > 10 && flag2 > 10){         flg = 0;(スイッチ1,2同時押しならモータは停止。)         TW.GRA = (int)onkaidata[(score1[scorectrl++])];       }       resetcnt = 0;       flag1 = 0;       flag2 = 0;     }     /* タイマW割り込み処理実行部分 */     if(do_flag == 1){       if(flg == 1) /* 右 */       {         k++;         if(k>3) k=0;         IO.PDR8.BYTE = motordata[k];       }       else if(flg == 2) /* 左 */       {         k--;         if(k<0) k=3;         IO.PDR8.BYTE = motordata[k];       }       else if(flg == 0) /* 停止 */       {         ;       }       do_flag = 0;     }     /* タイマV割り込み処理実行部分 */     if(do_flag2 == 1){       TW.GRA = (int)onkaidata[(score1[scorectrl])];       scorectrl++;       if(scorectrl >= (sizeof(score1) / sizeof(score1[0]