• 締切済み

(H8マイコン)タイマ割込で変更したグローバル変数がメインループ内で認識されない

H8マイコンの学習をしています。 LEDを一定時間ごとに点滅させるためにタイマ割込を使用して時間稼ぎ処理を行おうとしました。 1ms毎の割込でグローバル変数をインクリメントし、メインループ内でグローバル変数が一定値以上になるまで無限ループする処理を作成しました。 しかし、メインループの数値チェックの無限ループが終了せずLEDが点滅しません。 原因についてお知恵を拝借できないでしょうか。 何卒よろしくお願いいたします。 以下は環境およびコードです。 マイコン:H8/36109(H8/H300 Tinyシリーズ) 使用ツール:HEW4, E8a (main.c) #include "iodefine.h" volatile unsigned int cnt; //グローバル変数 void main(void) {   cnt = 0;   while(cnt < 1000); //ここで無限ループのまま(補足も参照)   IO.PDR2.BIT.B0 = IO.PDR2.BIT.B0; //ここにブレークをかけても引っ掛らない } (intprg.c) #include <machine.h> #include "iodefine.h" extern volatile unsigned int cnt; #pragma section IntPRG  (略) // vector 22 Timer V __interrupt(vect=22) void INT_TimerV(void) {   cnt++; //(補足参照)   TV.TCSRV.BIT.CMFA = 0; //コンペアマッチフラグクリア } (hwsetup.c) void HardwareSetup(void) {   IO.PCR2 = 0xff; //出力ポート      //タイマVの設定   TV.TCRV0.BYTE = 0x4b; /* CMFA有効, コンペアマッチAでクリア, φ/128 = 125kHz */   TV.TCRV1.BYTE = 0x01; /* 外部入力禁止 */   TV.TCORA = 125; /* 1ms */   TV.TCSRV.BYTE = 0x00; /* フラグクリア, 出力禁止 */ } (補足) 割込動作内でブレークをかけるとブレークがかかり、そこからステップ実行するとグローバル変数が変化していることを確認しました。 同様に、メインループの数値チェック無限ループでブレークをかけ、条件を満たすようにグローバル変数を手動で書き換えステップ実行すると無限ループを脱出しました。

みんなの回答

回答No.5

お疲れ様です。 cntの宣言ですが、[volatile]はついていますでしょうか? もしかすると、これが原因かも。。

noname#251988
質問者

お礼

基本設定含め最初から確認することにしました。 よって、ここで一旦質問を打ち切らせていただきます。 ありがとうございました。

noname#251988
質問者

補足

早速の御回答ありがとうございます。 "main.c"の先頭部で以下のように宣言していますが何か間違っているのでしょうか? volatile unsigned int cnt; //グローバル変数

  • ricardo_
  • ベストアンサー率19% (14/72)
回答No.4

1.割り込みが本当に掛かっているかのチェック   メイン関数ではなく、割り込みでLEDを点滅させます。  割り込み毎にLED出力を反転させればいいが、オシロが無いと観測出来ない。  割り込みプログラムを工夫して肉眼で分かる周期で反転させるようにする。 2.それが出来たら、割り込み処理の中でグローバル変数をインクリメントする。  グローバル変数が1000以上だったら点灯、2000以上だったら消灯すると共にゼロクリア。  初めから1と2を同時に行っても良いでしょう。 3.ここまで出来てから、メイン関数で点滅する事を考える。

noname#251988
質問者

お礼

(2)の事項ですがH8/36109ではうまくいきませんでした。H8/3048ではうまくいったのですが。 そこで、基本設定含め最初から確認することにしました。よって、ここで一旦質問を打ち切らせていただきます。 ありがとうございました。

noname#251988
質問者

補足

早速の御回答ありがとうございます。 一応、インクリメントした値を割込内でI/Oに出力する方法でI/Oが全点灯することは目視確認していましたが、オシロによる測定は行っていませんでした。来週にオシロを使用する機会があるのでそこで確認してみようと思います。 それまでは(2)の事項をやってみようと思います。

回答No.3

 回答2の補足説明です。  main関数のwhileは 「ループの先頭でcnt < 10001 なら無限ループに入れ」 と解釈されています。  プログラマの意図が違うならそれなりのコーディングを すべきです。

noname#251988
質問者

補足

申し訳ありません。こちらの記載ミスです。 実際のプログラムは以下のとおり、メインループが組み込まれています。 ご迷惑をおかけしました。 void main(void) {   while(1)   {     cnt = 0;     while(cnt < 1000); //ここで無限ループのまま(補足も参照)     IO.PDR2.BIT.B0 = IO.PDR2.BIT.B0;   } }

回答No.2

 デバッガーを使える環境のようですから mainのwhile 部分の アセンブラ表示を貼り付けてもらえると検討のしようがあるん ですが。   while(1) {     if (cnt > 1000) break;   } にすれば抜けて来ると思われます。

noname#251988
質問者

お礼

基本設定含め最初から確認することにしました。 よって、ここで一旦質問を打ち切らせていただきます。 ありがとうございました。

noname#251988
質問者

補足

早速の御回答ありがとうございます。 ご指摘頂いたように修正しましたが、抜けてくれませんでした 質問事項のアセンブラ表示は以下のとおりです。 "//"の行はCのコード、"[xxxxxx]"は逆アセンブリアドレスです。 グローバル変数「cnt」のアドレスは 0xFFE400 、タイマ割込ステータス(TV.TCSRV.BYTE)のアドレスは0xFFFFA1、I/O出力(IO.PDR2.BYTE)のアドレスは 0xFFFFD5 です。 (main.c) // void main(void) // { //   while(1) [00082E]     BAR   @_main:8 //   cnt = 0; [000816]_main  SUB.W  R0,R0 [000818]     MOV.W  R0,@_cnt:24 //   while(cnt < 1000); [00081E]     MOV.W  @_cnt24,R0 [000824]     CMP.W  #H'03E8, R0 [000828]     BCS   @H'081E:8 //   IO.PDR2.BIT.B0 = IO.PDR2.BIT.B0; [00082A]     BNOT  #0,@H'FFFFD5:8 [00082E]     BAR   @_main:8 // } (intprg.c) // __interrupt(vect=22) void INT_TimerV(void) [000434]_INT_TimerV  MOV.W  R1,@-ER7 [000436]         MOV.L  ER0,@-ER7 // { //   cnt++; [00043A]         MOV.L  #H'00FFE400, ER0 [000440]         MOV.W  @ER0,R1 [000442]         INC.W  #1,R1 [000444]         MOV.W  R1,@ER0 //   TV.TCSRV.BIT.CMFA = 0; [000446]         BCLR   #6,@H'FFFFA1:8 // } [00044A]         MOV.L  @ER7+,ER0 [00044E]         MOV.W  @ER7+,R1 [000450]         RET 指摘していただいたとおりに修正した後のアセンブラ表示は以下のとおりです。 (main.c) // void main(void) // { //   while(1) [00082E]     BAR   @_main:8 //   cnt = 0; [000816]_main  SUB.W  R0,R0 [000818]     MOV.W  R0,@_cnt:24 //   while(1) //   { //      if(cnt > 1000) { break; } [00081E]     MOV.W  @_cnt24,R0 [000824]     CMP.W  #H'03E8, R0 [000828]     BLS   @H'081E:8 //   } //   IO.PDR2.BIT.B0 = IO.PDR2.BIT.B0; [00082A]     BNOT  #0,@H'FFFFD5:8 [00082E]     BAR   @_main:8 // } (intprg.c)変更前とアドレス含めてすべて同じなので省略します。

  • ts244
  • ベストアンサー率41% (53/127)
回答No.1

専門家とは言っても、H8やHEWは使ったことが無くあまり詳しくないので 一般論ですが、、、 割り込みコンテキストで値をいじるcntにアクセスするとき 割り込み禁止にしておく必要はないですか? void main(void) { /* 割り込み禁止 */   cnt = 0; /* 割り込み許可 */   while(1) { /* 割り込み禁止 */    if (cnt >= 1000) break; /* 割り込み許可 */   } /* 割り込み許可 */   IO.PDR2.BIT.B0 = IO.PDR2.BIT.B0; } これが原因でもタイマのクリアが本当に1ms周期で処理能力が追いついているなら、 無限ループを抜けないってことは無いと思いますが設定はあってますか?

noname#251988
質問者

お礼

基本設定含め最初から確認することにしました。 よって、ここで一旦質問を打ち切らせていただきます。 ありがとうございました。

noname#251988
質問者

補足

早速の御回答ありがとうございます。 プログラムを以下のように修正しましたが、無限ループを抜けませんでした。 void main(void) {   set_imask_ccr((_UBYTE)1)/* 割り込み禁止 */   cnt = 0;   set_imask_ccr((_UBYTE)0)//* 割り込み許可 */   while(1) {   set_imask_ccr((_UBYTE)1)//* 割り込み禁止 */    if (cnt >= 1000) break;   set_imask_ccr((_UBYTE)0)//* 割り込み許可 */   }   set_imask_ccr((_UBYTE)0)/* 割り込み許可 */   IO.PDR2.BIT.B0 = IO.PDR2.BIT.B0; } 割込の方でも先頭に割込禁止処理、終端に割込許可処理を追加してあります。

関連するQ&A