Hi、武です。
今RL78マイコンを勉強しています。RL78/G12で規定された時間にLEDを点灯したい。ですので時間のDelay関数が必要かなと思います。
使用環境CS+ for CA/CXです。タイマのチャンネル2を使い、インターバル時間は1msを設定しています。
r_cg_timer_user.cのコード:
uint16_t counter_timer2 = 0;
__interrupt static void r_tau0_channel2_interrupt(void){ counter_timer2 ++;}
中断ファイルc_cg_intc_user.cのコード:
extern uint16_t counter_timer2;
void delay_ms_1(uint16_t dlms){ counter_timer2 = 0; R_TAU0_Channel2_Start(); while(counter_timer2 < dlms); R_TAU0_Channel2_Stop();}
ただし、動かないです。理由はタイマが起動されでも、void delay_ms_1のWhileのcounter_timer2 が変わらない。0のままです。Loopから抜かれないです。
どう修正すれば正しいDelayができるか教えていただきたいと思います。
割り込みハンドラは呼び出されていますね?
最適化が有効の場合、ファイルをまたいでの最適化でcounter_timer2が考慮されず、counter_timer2が0なのでwile文はwhile(0<dlms)として展開されていると考えられます。もしくは割り込みハンドラのインクリメントが参照がないので消されているかも。volatile宣言を追加すると解決するかもしれません。uint16_t counter_timer2 = 0;
↓volatile uint16_t counter_timer2 = 0;
volatile uint16_t counter_timer2 = 0;
__interrupt static void r_tau0_channel2_interrupt(void){ if (counter_timer2) {
counter_timer2--;
}}
extern volatile uint16_t counter_timer2;
void delay_ms_1(uint16_t dlms){ counter_timer2 = dlms; while(counter_timer2);}
タイマは低い優先度で常時動作状態。私ならこう書きます。タイマの位相によって割り込みまでのタイミングが変わるので必ず指定時間より待たすならdlsms+1をセットするか、タイマの値を0から開始するコードも入れる必要があります。
ご回答ありがとうございます。やってみましたが、あまり変わっていないようです。確認のコードが下記になります。
r_main.cのコード:
void main(void){ R_MAIN_UserInit(); /* Start user code. Do not edit comment generated here */ R_TAU0_Channel1_Start(); R_TAU0_Channel2_Start(); R_KEY_Start(); P6.3 = 1; while (1U) {;}}
中断ファイルコード:
タイマファイルコード:
__interrupt static void r_tau0_channel1_interrupt(void){ if (counter_timer2) {counter_timer2--;}}
実行中のDebugモードで、Delay関数のWhile中Counter2を見ました。ずーど初期値1000のままでした。LOOPの繰り返しに、タイマが止まっているか、タイマのcounter_timer2が変わっても、Loopへの更新できないかになるかな?この方法がだめかな。。。
割り込みハンドラが1ms間隔で実行されているかは確認できていますか?
Yamamoto様、確認しました。
外部Keyを押さなければ、つまり、中断がなければ、タイマが普通に動いていた。Keyを押したら、中断が発生しましたので、Delay関数を呼ばれました。Delayのwhile関数条件のcounter_timer2の値は変わらないので、永遠のLoopになります。この時に、Debug状態でタイマの状態が見えなくなります。おそらく、実行されていないかなと思います。やはり、永遠のLoopから抜かないと、なんでも停止いしているように見えます。
チョコ様が書いているように割り込み処理の実現部分に問題があり、そこを解決しないと先には進めないです。複数の割り込み処理がちゃんと実行されるようになれば解決すると思います。
チョコです。
武さん。以下の処理は、外部Keyに対応した割り込み処理の中でタイマのチャンネル2の割り込みを実行させたい(受付けさせたい)ように見えます。
そうなると、2つのことをきちんとする必要があります。
1つ目は、「外部Keyに対応した割り込み処理」の優先順位よりも「タイマのチャンネル2の割り込み処理」の優先順位をより優先に設定する。
2つ目は、「外部Keyに対応した割り込み処理」の先頭で、割り込み許可(EI();)を実行すべきです。
つまり、多重割り込みをきちんと実行する必要があるということです。
以上
チョコさん、Yamamotoさん
ご回答ありがとうございます。簡単と思いましたが、難しいのところかなと思います。もっと勉強が必要かなと思います。この件は大丈夫です。ご示教ありがとうございました!
実は、紹介したサンプルコードは、多重割り込みを使用しないで、同じようなことを実現しようとしています。下に示すINTP0割り込み処理の中で、タイマ割り込みをHALTモードの解除に利用して、タイマ割り込みでの実処理部を普通の関数にしてあるので、その関数を呼び出すことで、INTP0割り込み処理の中で、タイマ割り込み処理を実現しています。
個人的には、このようなやり方(長い期間割り込み処理の中に留まる)は好きではない(と言うよりやってはいけない)のですが、このようなことを行えば(サンプルコードを参考にすれば)、武さんのやりたいことはそれほど難しくなく実現はできますよ。
それよりは、多重割り込みを使いこなす方が常道です。