SHマイコンのシリアルデータフレームの割り込み受信プログラムについて

SHマイコンのシリアルデータフレームの割り込み受信プログラムについて 独学でマイコンを使った電子工作をしています。 現在無線モジュール(XBee)からのフレームを受信するプログラムを作っています。メイン関数内で必要なバイトのみモニタするプログラムはできました。次にそれをシリアル受信割り込みでモニタしようと試みましたがうまくいきません。 症状としては、全くデータが送られないといったものです。 使用しているマイコンはSH-2マイコンの7144Fで、コンパイラはGDLです。 個人的にはグローバル変数を使う経験があまりないので、それを使った所と割り込み関数内のソースが怪しいと思っています。 ソースプログラムです。 PCでのモニタはSCI1でXBeeはSCI0を使用しています。またメイン関数内のコメント部は割り込みなしでモニタ出来ていた時のものです。 XBeeの受信は4つのアナログデータ入力データを受信しようとしています。一つのアナログ入力値を2バイトで表しており、初めのバイトは256で割ったもので、後ろのバイトが余りです。analogvalue関数はそれを計算しています。 #include<7144.h> int rd[8]; int a; int xa,ya,xb,yb; void initIO(void) // I/Oポートのイニシャライズ { PFC.PACRL2.WORD=0x140; //SCI1_TXD1_RXD1_モニタ PFC.PACRL2.BIT.PA0MD=0x1; //SCI0_RXD0_XBee } void initSCI(void) // SCIのイニシャライズ { int i; SCI1.SCR.BYTE=0; // 初期値、割り込み禁止、送受信停止、内部クロック SCI1.SMR.BYTE=0; // 初期値、調歩同期、8ビット、パリティなし、ストップビット1、クロックPφ SCI1.BRR=12; // ボーレート設定 for(i=0;i<(SCI1.BRR*10);i++) // 1ビット待ち nop(); SCI1.SCR.BYTE=0x30; // 割り込み禁止、送受信動作 SCI1.SSR.BYTE&=0x80; // エラーフラグクリア SCI0.SCR.BYTE=0; // 初期値、割り込み禁止、送受信停止、内部クロック SCI0.SMR.BYTE=0; // 初期値、調歩同期、8ビット、パリティなし、ストップビット1、クロックPφ SCI0.BRR=78; // ボーレート設定、本文参照 for(i=0;i<(SCI0.BRR*10);i++) // 1ビット待ち nop(); SCI0.SCR.BYTE=0x70; // 割り込み許可、送受信動作 SCI0.SSR.BYTE&=0x80; // エラーフラグクリア INTC.IPRF.BIT._SCI0=15; // 割り込み優先順位 } int analogvalue(int high,int low) //XBee入力変換関数 { int ad; ad = (high * 256) + low; return ad; } void int_rxi0(void) // 受信割り込み関数 { if(SCI0.RDR==15){ //アナログデータ直前バイトだった場合 a=0;} switch(a){ case 0 : a++; break; case 1 : rd[1] = SCI0.RDR; a++; break; case 2 : rd[2] = SCI0.RDR; a++; break; case 3 : rd[3] = SCI0.RDR; a++; break; case 4 : rd[4] = SCI0.RDR; a++; break; case 5 : rd[5] = SCI0.RDR; a++; break; case 6 : rd[6] = SCI0.RDR; a++; break; case 7 : rd[7] = SCI0.RDR; a++; break; case 8 : rd[8] = SCI0.RDR; a++; break; default :break;} SCI0.SSR.BYTE&=0x80; xa = analogvalue(rd[1],rd[2]); ya = analogvalue(rd[3],rd[4]); xb = analogvalue(rd[5],rd[6]); yb = analogvalue(rd[7],rd[8]); } void int_eri0(void) // 受信エラー割り込み関数 { SCI0.SSR.BYTE&=0x80; // フラグクリア } void sci_tx(char td) //データ送信関数 { while(!SCI1.SSR.BIT.TDRE); // TDREがセットされるまで待つ SCI1.TDR = td; // 関数に受け取ったデータを送信 SCI1.SSR.BIT.TDRE=0; // TDREをクリア、次の送信に備える } int main(void) { // int rd[8]; // int b; // int xa,ya,xb,yb; MST.CR1.BIT._SCI1=0; // SCIのモジュールスタンバイ解除 MST.CR1.BIT._SCI0=0; //SCIのモジュールスタンバイ解除 SetSRReg(14); initIO(); initSCI(); // SCIのイニシャライズ while(1) //メインループ { /*b=1; while(!(SCI0.SSR.BYTE&0x78)); // 受信データかエラーフラグが立つまで待つ while(!(SCI0.RDR==15)){ //アナログデータ直前バイト待ち SCI0.SSR.BYTE&=0x80;} while(b<=8) { while(!(SCI0.SSR.BYTE&0x78)); // 受信データかエラーフラグが立つまで待つ if(SCI0.SSR.BYTE&0xC4){ // 正常であれば rd[b] = SCI0.RDR; SCI0.SSR.BYTE&=0x80; b++;} xa = analogvalue(rd[1],rd[2]); ya = analogvalue(rd[3],rd[4]); xb = analogvalue(rd[5],rd[6]); yb = analogvalue(rd[7],rd[8]); }*/ sci_tx(yb); } } レジスタなど色々とお答えしにくい部分がある質問で申し訳ありませんが、もしわかる方がいらあっしゃいましたら教えてください。可能であれば、簡単なプログラムも教えてくださると幸いです。よろしくおねがいします。

補足

メイン関数内で行うと待ち時間が出来てしまいます。それを解消したいと思い、割り込み受信をしたいと思ったのが割り込みにしようとした経緯です。そのため割り込みを使用しなくても、待ち時間が出来ないような(常にモニタデータを送信する)プログラムが可能であれば、ご教授頂けると幸いです。 また、ご指摘いただいた int rd[8]部分は、なぜかは分かりませんが正常に動きましたが、下記のように修正しました。 xa = analogvalue(rd[0],rd[1]); ya = analogvalue(rd[2],rd[3]); xb = analogvalue(rd[4],rd[5]); yb = analogvalue(rd[6],rd[7]); ありがとうございます。

C言語関連1,673閲覧xmlns="http://www.w3.org/2000/svg">250

ベストアンサー

0

(1)質問とは関係ないが気になった点。 int rd[8];であるからrd[0]~rd[7]の8ヶしたがって、 case 8 : rd[8] = SCI0.RDR; a++; break;や yb = analogvalue(rd[7],rd[8]);や while(b<=8) { while(!(SCI0.SSR.BYTE&0x78)); // 受信データかエラーフラグが立つまで待つ if(SCI0.SSR.BYTE&0xC4){ // 正常であれば rd[b] = SCI0.RDR;______//ここb=8はrd「8」となってだめ SCI0.SSR.BYTE&=0x80; b++;} は正しく動作しないと思うのですが、 これで割り込みを使用しないとき正しく動いているというのは信じられませんがどうなっているのでしょうね。 ご参考までに。 「追記」割り込みの処理名もあっているようだから、 あと、 1.割り込みのプライオリティを少し下げる。7程度でどうでしょう。 2.main()の頭に DI;____//割り込み禁止 書き方はコンパイラーにあわせる。 ・ ・ ・ SetSRReg (0);____//割り込みマスク解除 EI;____//割り込み許可 while(1){ ・ としてみる。 根本は 1.受信割り込み割り込み処理の”SCI0.SSR.BYTE&=0x80;”とmain()関数の”while(!(SCI0.SSR.BYTE&0x78)); // 受信データかエラーフラグが立つまで待つ”との関係がまずい。 割り込みとmain()関数は非同期に動いてるわけだから割り込みが発生するとwhile(!(SCI0.SSR.BYTE&0x78))の条件が常に真でここから抜け出せなくなるよ。 通常、受信割り込み割り込み処理でSCI0.SSR.BYTE&=0x80;とするのは正しい。それなので別にユーザーフラグを用意しそれを割り込みでセットし、main()ルーティンでそのフラグが立ったかどうかをチェックするようにします。 while(!(ユーザーフラグ)); ユーザーフラグクリア; 2.受信エラーのときも同じように考えてください。 3.あと、気になった点”void sci_tx(char td) //データ送信関数”では割り込みで処理されないと思うのですけど。 「追記2」すいません。上述のプログラムではウエイトがかり、割り込みのメリットがほとんどないことになるので下記のようにする。 1)受信割り込み割り込み処理の”SCI0.SSR.BYTE&=0x80;”をコメントアウトし、main()関数内でクリアするようにする。 2)main()関数のwhile(!(SCI0.SSR.BYTE&0x78))もコメントアウトし、 ”if(SCI0.SSR.BYTE&0x78 == 0x40)__//正常であれば”にする。 while(b<=8){}のところも同じように変更する。 そうすることにより、ウエイトはなくなり、割り込みの効果を最大限活かすことができるようになる。 3)ユーザーフラグは不要になる。 4)この方法で注意することはmain()関数が大きくなるとORER(オーバーラン・エラー)が出るようになるので工夫がいることです。今回のプログラムでは大丈夫でしょう。

ThanksImg質問者からのお礼コメント

ご指摘を参考にやってみたところうまくいきそうです。細かいところまで丁寧に教えてくださり、ありがとうございました。

お礼日時:2012/12/25 17:49

その他の回答(1件)

0

まず、SHで割り込みを用いたプログラムを作られた経験はあるのでしょうか?SHの割り込みは、0番地から始まる割り込みベクタテーブルに割り込みルーチンとして用いるプログラムのアドレスを羅列しておく形式になっています。SCI0の受信割り込み(RXI_0)なら0x204番地、SCI1の受信割り込み(RXI_1)なら0x214番地です。まず、この「割り込みベクタテーブルを作って、リンカに対して特定アドレスにマッピングする指示を与える」手続きはできているのでしょうか? また、割り込み処理として用いるルーチンは、入るときと出るときで特別な処理が必要になります。ルネサス純正コンパイラであれば、#pragma interruptを使って割り込み関数であることを明示したりするのですが、お使いのコンパイラでその辺りの手続きを正しくしているでしょうか?或いは、導入処理はアセンブラによるルーチンで行い、C言語では普通の関数のように記述する手法もありますが、そういう仕組みはあるのでしょうか? 純正コンパイラは使っているのでサンプルを示すこともできるけど、GDLってよくわからないので。 --- 関数名だけは割り込み要素名に合わせてあるけど、その関数のアドレスがベクタに正しく記述されているのかこのソースからはわからないので、何とも言えません。